mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-17 23:09:10 +08:00
Refactored based on comments and feedback (3rd round)
This commit is contained in:
@@ -67,12 +67,28 @@ If you do not have [Composer](http://getcomposer.org/), you may download it from
|
|||||||
curl -s http://getcomposer.org/installer | php
|
curl -s http://getcomposer.org/installer | php
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
You can then install the Bootstrap Application using the following command:
|
You can then install the application using the following command:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-advanced
|
php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-advanced
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
### Install from an Archive File
|
||||||
|
|
||||||
|
This is not currently available. We will provide it when Yii 2 is formally released.
|
||||||
|
|
||||||
|
|
||||||
|
GETTING STARTED
|
||||||
|
---------------
|
||||||
|
|
||||||
|
After you install the application, you have to conduct the following steps to initialize
|
||||||
|
the installed application. You only need to do these once for all.
|
||||||
|
|
||||||
|
1. Execute the `init` command and select `dev` as environment.
|
||||||
|
2. Create a new database. It is assumed that MySQL InnoDB is used. If not, adjust `console/migrations/m130524_201442_init.php`.
|
||||||
|
3. In `common/config/params.php` set your database details in `components.db` values.
|
||||||
|
|
||||||
Now you should be able to access:
|
Now you should be able to access:
|
||||||
|
|
||||||
- the frontend using the URL `http://localhost/yii-advanced/frontend/www/`
|
- the frontend using the URL `http://localhost/yii-advanced/frontend/www/`
|
||||||
@@ -80,19 +96,3 @@ Now you should be able to access:
|
|||||||
|
|
||||||
assuming `yii-advanced` is directly under the document root of your Web server.
|
assuming `yii-advanced` is directly under the document root of your Web server.
|
||||||
|
|
||||||
|
|
||||||
### Install from an Archive File
|
|
||||||
|
|
||||||
This is not currently available. We will provide it when Yii 2 is formally released.
|
|
||||||
|
|
||||||
GETTING STARTED
|
|
||||||
---------------
|
|
||||||
|
|
||||||
After template application and its dependencies are downloaded you need to initialize it and set some config values to
|
|
||||||
match your application requirements.
|
|
||||||
|
|
||||||
1. Execute `install` command selecting `dev` as environment.
|
|
||||||
2. Set `id` value in `console/config/main.php`, `frontend/config/main.php`, `backstage/config/main.php`.
|
|
||||||
3. Create new database. It is assumed that MySQL InnoDB is used. If not, adjust `console/migrations/m130524_201442_init.php`.
|
|
||||||
4. In `common/config/params.php` set your database details in `components.db` values.
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ $params = array_merge(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'id' => 'change-me',
|
'id' => 'app-backend',
|
||||||
'basePath' => dirname(__DIR__),
|
'basePath' => dirname(__DIR__),
|
||||||
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
||||||
'preload' => array('log'),
|
'preload' => array('log'),
|
||||||
|
|||||||
@@ -36,9 +36,6 @@
|
|||||||
|
|
||||||
"frontend/runtime",
|
"frontend/runtime",
|
||||||
"frontend/www/assets"
|
"frontend/www/assets"
|
||||||
],
|
|
||||||
"yii-install-executable": [
|
|
||||||
"yii"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ $params = array_merge(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'id' => 'change-me',
|
'id' => 'app-console',
|
||||||
'basePath' => dirname(__DIR__),
|
'basePath' => dirname(__DIR__),
|
||||||
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
||||||
'preload' => array('log'),
|
'preload' => array('log'),
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use yii\db\Schema;
|
||||||
|
|
||||||
class m130524_201442_init extends \yii\db\Migration
|
class m130524_201442_init extends \yii\db\Migration
|
||||||
{
|
{
|
||||||
public function up()
|
public function up()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ $params = array_merge(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'id' => 'change-me',
|
'id' => 'app-frontend',
|
||||||
'basePath' => dirname(__DIR__),
|
'basePath' => dirname(__DIR__),
|
||||||
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
||||||
'preload' => array('log'),
|
'preload' => array('log'),
|
||||||
|
|||||||
@@ -4,27 +4,27 @@ $root = str_replace('\\', '/', __DIR__);
|
|||||||
$envs = require("$root/environments/index.php");
|
$envs = require("$root/environments/index.php");
|
||||||
$envNames = array_keys($envs);
|
$envNames = array_keys($envs);
|
||||||
|
|
||||||
echo "Yii Application Installation Tool v1.0\n\n";
|
echo "Yii Application Init Tool v1.0\n\n";
|
||||||
echo "Which environment do you want to install the application to?\n\n";
|
echo "Which environment do you want the application to be initialized in?\n\n";
|
||||||
foreach ($envNames as $i => $name) {
|
foreach ($envNames as $i => $name) {
|
||||||
echo " [$i] $name\n";
|
echo " [$i] $name\n";
|
||||||
}
|
}
|
||||||
echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
|
echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
|
||||||
$answer = trim(fgets(STDIN));
|
$answer = trim(fgets(STDIN));
|
||||||
if (!ctype_digit($answer) || !isset($envNames[$answer])) {
|
if (!ctype_digit($answer) || !isset($envNames[$answer])) {
|
||||||
echo "\n Quit installation.\n";
|
echo "\n Quit initialization.\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$env = $envs[$envNames[$answer]];
|
$env = $envs[$envNames[$answer]];
|
||||||
echo "\n Install the application under '{$envNames[$answer]}' environment? [yes|no] ";
|
echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
|
||||||
$answer = trim(fgets(STDIN));
|
$answer = trim(fgets(STDIN));
|
||||||
if (strncasecmp($answer, 'y', 1)) {
|
if (strncasecmp($answer, 'y', 1)) {
|
||||||
echo "\n Quit installation.\n";
|
echo "\n Quit initialization.\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "\n Start installation ...\n\n";
|
echo "\n Start initialization ...\n\n";
|
||||||
$files = getFileList("$root/environments/{$env['path']}");
|
$files = getFileList("$root/environments/{$env['path']}");
|
||||||
$all = false;
|
$all = false;
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
@@ -47,7 +47,7 @@ if (isset($env['executable'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "\n ... installation completed.\n\n";
|
echo "\n ... initialization completed.\n\n";
|
||||||
|
|
||||||
function getFileList($root, $basePath = '')
|
function getFileList($root, $basePath = '')
|
||||||
{
|
{
|
||||||
@@ -13,7 +13,7 @@ The most obvious change in Yii 2.0 is the use of namespaces. Almost every core c
|
|||||||
is namespaced, e.g., `yii\web\Request`. The "C" prefix is no longer used in class names.
|
is namespaced, e.g., `yii\web\Request`. The "C" prefix is no longer used in class names.
|
||||||
The naming of the namespaces follows the directory structure. For example, `yii\web\Request`
|
The naming of the namespaces follows the directory structure. For example, `yii\web\Request`
|
||||||
indicates the corresponding class file is `web/Request.php` under the Yii framework folder.
|
indicates the corresponding class file is `web/Request.php` under the Yii framework folder.
|
||||||
You can use any core class without explicitly include that class file, thanks to the Yii
|
You can use any core class without explicitly including that class file, thanks to the Yii
|
||||||
class loader.
|
class loader.
|
||||||
|
|
||||||
|
|
||||||
@@ -117,17 +117,17 @@ supported in most places in the Yii core code. For example, `FileCache::cachePat
|
|||||||
both a path alias and a normal directory path.
|
both a path alias and a normal directory path.
|
||||||
|
|
||||||
Path alias is also closely related with class namespaces. It is recommended that a path
|
Path alias is also closely related with class namespaces. It is recommended that a path
|
||||||
alias defined for each root namespace so that you can use Yii class autoloader without
|
alias be defined for each root namespace so that you can use Yii the class autoloader without
|
||||||
any further configuration. For example, because `@yii` refers to the Yii installation directory,
|
any further configuration. For example, because `@yii` refers to the Yii installation directory,
|
||||||
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library
|
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library
|
||||||
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation directory.
|
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation
|
||||||
And Yii will be able to autoload any class in this library.
|
directory and Yii will be able to autoload any class in this library.
|
||||||
|
|
||||||
|
|
||||||
View
|
View
|
||||||
----
|
----
|
||||||
|
|
||||||
Yii 2.0 introduces a `View` class to represent the view part in the MVC pattern.
|
Yii 2.0 introduces a `View` class to represent the view part of the MVC pattern.
|
||||||
It can be configured globally through the "view" application component. It is also
|
It can be configured globally through the "view" application component. It is also
|
||||||
accessible in any view file via `$this`. This is one of the biggest changes compared to 1.1:
|
accessible in any view file via `$this`. This is one of the biggest changes compared to 1.1:
|
||||||
**`$this` in a view file no longer refers to the controller or widget object.**
|
**`$this` in a view file no longer refers to the controller or widget object.**
|
||||||
@@ -159,7 +159,7 @@ extension for your Smarty views, or `twig` for Twig views. You may also configur
|
|||||||
Models
|
Models
|
||||||
------
|
------
|
||||||
|
|
||||||
A model is now associated with a form name returned its `formName()` method. This is
|
A model is now associated with a form name returned by its `formName()` method. This is
|
||||||
mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1,
|
mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1,
|
||||||
this is usually hardcoded as the class name of the model.
|
this is usually hardcoded as the class name of the model.
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ Previously in 1.1, you would have to enter the widget class names as strings via
|
|||||||
Themes
|
Themes
|
||||||
------
|
------
|
||||||
|
|
||||||
Theme works completely different in 2.0. It is now based on a path map to "translate" a source
|
Themes work completely different in 2.0. They are now based on a path map to "translate" a source
|
||||||
view into a themed view. For example, if the path map for a theme is
|
view into a themed view. For example, if the path map for a theme is
|
||||||
`array('/www/views' => '/www/themes/basic')`, then the themed version for a view file
|
`array('/www/views' => '/www/themes/basic')`, then the themed version for a view file
|
||||||
`/www/views/site/index.php` will be `/www/themes/basic/site/index.php`.
|
`/www/views/site/index.php` will be `/www/themes/basic/site/index.php`.
|
||||||
@@ -250,7 +250,7 @@ application component.
|
|||||||
Console Applications
|
Console Applications
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Console applications are now composed by controllers, too, like Web applications. In fact,
|
Console applications are now composed by controllers, like Web applications. In fact,
|
||||||
console controllers and Web controllers share the same base controller class.
|
console controllers and Web controllers share the same base controller class.
|
||||||
|
|
||||||
Each console controller is like `CConsoleCommand` in 1.1. It consists of one or several
|
Each console controller is like `CConsoleCommand` in 1.1. It consists of one or several
|
||||||
@@ -300,7 +300,7 @@ public function behaviors()
|
|||||||
Assets
|
Assets
|
||||||
------
|
------
|
||||||
|
|
||||||
Yii 2.0 introduces a new concept called *asset bundle*. It is a bit similar to script
|
Yii 2.0 introduces a new concept called *asset bundle*. It is similar to script
|
||||||
packages (managed by `CClientScript`) in 1.1, but with better support.
|
packages (managed by `CClientScript`) in 1.1, but with better support.
|
||||||
|
|
||||||
An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.)
|
An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.)
|
||||||
@@ -315,7 +315,7 @@ Static Helpers
|
|||||||
|
|
||||||
Yii 2.0 introduces many commonly used static helper classes, such as `Html`, `ArrayHelper`,
|
Yii 2.0 introduces many commonly used static helper classes, such as `Html`, `ArrayHelper`,
|
||||||
`StringHelper`. These classes are designed to be easily extended. Note that static classes
|
`StringHelper`. These classes are designed to be easily extended. Note that static classes
|
||||||
are usually hard to be extended because of the fixed class name references. But Yii 2.0
|
are usually hard to extend because of the fixed class name references. But Yii 2.0
|
||||||
introduces the class map (via `Yii::$classMap`) to overcome this difficulty.
|
introduces the class map (via `Yii::$classMap`) to overcome this difficulty.
|
||||||
|
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ Query Builder
|
|||||||
|
|
||||||
In 1.1, query building is scattered among several classes, including `CDbCommand`,
|
In 1.1, query building is scattered among several classes, including `CDbCommand`,
|
||||||
`CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query
|
`CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query
|
||||||
and `QueryBuilder` to generate SQL statements from query objects. For example,
|
and `QueryBuilder` to generate SQL statements from query objects. For example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$query = new \yii\db\Query;
|
$query = new \yii\db\Query;
|
||||||
@@ -365,7 +365,7 @@ ActiveRecord
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
ActiveRecord has undergone significant changes in Yii 2.0. The most important one
|
ActiveRecord has undergone significant changes in Yii 2.0. The most important one
|
||||||
is about relational ActiveRecord query. In 1.1, you have to declare the relations
|
is the relational ActiveRecord query. In 1.1, you have to declare the relations
|
||||||
in the `relations()` method. In 2.0, this is done via getter methods that return
|
in the `relations()` method. In 2.0, this is done via getter methods that return
|
||||||
an `ActiveQuery` object. For example, the following method declares an "orders" relation:
|
an `ActiveQuery` object. For example, the following method declares an "orders" relation:
|
||||||
|
|
||||||
@@ -392,7 +392,7 @@ by filtering with the primary keys of the primary records.
|
|||||||
|
|
||||||
|
|
||||||
Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you
|
Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you
|
||||||
use the `find()` method like the following:
|
use the `find()` method:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// to retrieve all *active* customers and order them by their ID:
|
// to retrieve all *active* customers and order them by their ID:
|
||||||
@@ -410,14 +410,14 @@ Therefore, you can use all query methods of `Query`.
|
|||||||
|
|
||||||
Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` to
|
Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` to
|
||||||
return results in terms of arrays. This is more efficient and is especially useful
|
return results in terms of arrays. This is more efficient and is especially useful
|
||||||
when you need to return large number of records. For example,
|
when you need to return a large number of records:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$customers = Customer::find()->asArray()->all();
|
$customers = Customer::find()->asArray()->all();
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes
|
By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes
|
||||||
would be saved to database when you call `save()`, regardless they are changed or not,
|
are saved to database when you call `save()`, regardless of having changed or not,
|
||||||
unless you explicitly list the attributes to save.
|
unless you explicitly list the attributes to save.
|
||||||
|
|
||||||
|
|
||||||
@@ -427,7 +427,7 @@ Auto-quoting Table and Column Names
|
|||||||
Yii 2.0 supports automatic quoting of database table and column names. A name enclosed
|
Yii 2.0 supports automatic quoting of database table and column names. A name enclosed
|
||||||
within double curly brackets is treated as a table name, and a name enclosed within
|
within double curly brackets is treated as a table name, and a name enclosed within
|
||||||
double square brackets is treated as a column name. They will be quoted according to
|
double square brackets is treated as a column name. They will be quoted according to
|
||||||
the database driver being used. For example,
|
the database driver being used:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$command = $connection->createCommand('SELECT [[id]] FROM {{posts}}');
|
$command = $connection->createCommand('SELECT [[id]] FROM {{posts}}');
|
||||||
|
|||||||
@@ -48,4 +48,11 @@ return array(
|
|||||||
YII_DEBUG ? 'punycode/punycode.js' : 'punycode/punycode.min.js',
|
YII_DEBUG ? 'punycode/punycode.js' : 'punycode/punycode.min.js',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
'yii/maskedinput' => array(
|
||||||
|
'sourcePath' => __DIR__ . '/assets',
|
||||||
|
'js' => array(
|
||||||
|
'jquery.maskedinput.js',
|
||||||
|
),
|
||||||
|
'depends' => array('yii/jquery'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
338
framework/yii/assets/jquery.maskedinput.js
Normal file
338
framework/yii/assets/jquery.maskedinput.js
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
Masked Input plugin for jQuery
|
||||||
|
Copyright (c) 2007-2013 Josh Bush (digitalbush.com)
|
||||||
|
Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
|
||||||
|
Version: 1.3.1
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
function getPasteEvent() {
|
||||||
|
var el = document.createElement('input'),
|
||||||
|
name = 'onpaste';
|
||||||
|
el.setAttribute(name, '');
|
||||||
|
return (typeof el[name] === 'function')?'paste':'input';
|
||||||
|
}
|
||||||
|
|
||||||
|
var pasteEventName = getPasteEvent() + ".mask",
|
||||||
|
ua = navigator.userAgent,
|
||||||
|
iPhone = /iphone/i.test(ua),
|
||||||
|
android=/android/i.test(ua),
|
||||||
|
caretTimeoutId;
|
||||||
|
|
||||||
|
$.mask = {
|
||||||
|
//Predefined character definitions
|
||||||
|
definitions: {
|
||||||
|
'9': "[0-9]",
|
||||||
|
'a': "[A-Za-z]",
|
||||||
|
'*': "[A-Za-z0-9]"
|
||||||
|
},
|
||||||
|
dataName: "rawMaskFn",
|
||||||
|
placeholder: '_',
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.extend({
|
||||||
|
//Helper Function for Caret positioning
|
||||||
|
caret: function(begin, end) {
|
||||||
|
var range;
|
||||||
|
|
||||||
|
if (this.length === 0 || this.is(":hidden")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof begin == 'number') {
|
||||||
|
end = (typeof end === 'number') ? end : begin;
|
||||||
|
return this.each(function() {
|
||||||
|
if (this.setSelectionRange) {
|
||||||
|
this.setSelectionRange(begin, end);
|
||||||
|
} else if (this.createTextRange) {
|
||||||
|
range = this.createTextRange();
|
||||||
|
range.collapse(true);
|
||||||
|
range.moveEnd('character', end);
|
||||||
|
range.moveStart('character', begin);
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this[0].setSelectionRange) {
|
||||||
|
begin = this[0].selectionStart;
|
||||||
|
end = this[0].selectionEnd;
|
||||||
|
} else if (document.selection && document.selection.createRange) {
|
||||||
|
range = document.selection.createRange();
|
||||||
|
begin = 0 - range.duplicate().moveStart('character', -100000);
|
||||||
|
end = begin + range.text.length;
|
||||||
|
}
|
||||||
|
return { begin: begin, end: end };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unmask: function() {
|
||||||
|
return this.trigger("unmask");
|
||||||
|
},
|
||||||
|
mask: function(mask, settings) {
|
||||||
|
var input,
|
||||||
|
defs,
|
||||||
|
tests,
|
||||||
|
partialPosition,
|
||||||
|
firstNonMaskPos,
|
||||||
|
len;
|
||||||
|
|
||||||
|
if (!mask && this.length > 0) {
|
||||||
|
input = $(this[0]);
|
||||||
|
return input.data($.mask.dataName)();
|
||||||
|
}
|
||||||
|
settings = $.extend({
|
||||||
|
placeholder: $.mask.placeholder, // Load default placeholder
|
||||||
|
completed: null
|
||||||
|
}, settings);
|
||||||
|
|
||||||
|
|
||||||
|
defs = $.mask.definitions;
|
||||||
|
tests = [];
|
||||||
|
partialPosition = len = mask.length;
|
||||||
|
firstNonMaskPos = null;
|
||||||
|
|
||||||
|
$.each(mask.split(""), function(i, c) {
|
||||||
|
if (c == '?') {
|
||||||
|
len--;
|
||||||
|
partialPosition = i;
|
||||||
|
} else if (defs[c]) {
|
||||||
|
tests.push(new RegExp(defs[c]));
|
||||||
|
if (firstNonMaskPos === null) {
|
||||||
|
firstNonMaskPos = tests.length - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tests.push(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.trigger("unmask").each(function() {
|
||||||
|
var input = $(this),
|
||||||
|
buffer = $.map(
|
||||||
|
mask.split(""),
|
||||||
|
function(c, i) {
|
||||||
|
if (c != '?') {
|
||||||
|
return defs[c] ? settings.placeholder : c;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
focusText = input.val();
|
||||||
|
|
||||||
|
function seekNext(pos) {
|
||||||
|
while (++pos < len && !tests[pos]);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function seekPrev(pos) {
|
||||||
|
while (--pos >= 0 && !tests[pos]);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shiftL(begin,end) {
|
||||||
|
var i,
|
||||||
|
j;
|
||||||
|
|
||||||
|
if (begin<0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = begin, j = seekNext(end); i < len; i++) {
|
||||||
|
if (tests[i]) {
|
||||||
|
if (j < len && tests[i].test(buffer[j])) {
|
||||||
|
buffer[i] = buffer[j];
|
||||||
|
buffer[j] = settings.placeholder;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = seekNext(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeBuffer();
|
||||||
|
input.caret(Math.max(firstNonMaskPos, begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
function shiftR(pos) {
|
||||||
|
var i,
|
||||||
|
c,
|
||||||
|
j,
|
||||||
|
t;
|
||||||
|
|
||||||
|
for (i = pos, c = settings.placeholder; i < len; i++) {
|
||||||
|
if (tests[i]) {
|
||||||
|
j = seekNext(i);
|
||||||
|
t = buffer[i];
|
||||||
|
buffer[i] = c;
|
||||||
|
if (j < len && tests[j].test(t)) {
|
||||||
|
c = t;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keydownEvent(e) {
|
||||||
|
var k = e.which,
|
||||||
|
pos,
|
||||||
|
begin,
|
||||||
|
end;
|
||||||
|
|
||||||
|
//backspace, delete, and escape get special treatment
|
||||||
|
if (k === 8 || k === 46 || (iPhone && k === 127)) {
|
||||||
|
pos = input.caret();
|
||||||
|
begin = pos.begin;
|
||||||
|
end = pos.end;
|
||||||
|
|
||||||
|
if (end - begin === 0) {
|
||||||
|
begin=k!==46?seekPrev(begin):(end=seekNext(begin-1));
|
||||||
|
end=k===46?seekNext(end):end;
|
||||||
|
}
|
||||||
|
clearBuffer(begin, end);
|
||||||
|
shiftL(begin, end - 1);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
} else if (k == 27) {//escape
|
||||||
|
input.val(focusText);
|
||||||
|
input.caret(0, checkVal());
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keypressEvent(e) {
|
||||||
|
var k = e.which,
|
||||||
|
pos = input.caret(),
|
||||||
|
p,
|
||||||
|
c,
|
||||||
|
next;
|
||||||
|
|
||||||
|
if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore
|
||||||
|
return;
|
||||||
|
} else if (k) {
|
||||||
|
if (pos.end - pos.begin !== 0){
|
||||||
|
clearBuffer(pos.begin, pos.end);
|
||||||
|
shiftL(pos.begin, pos.end-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = seekNext(pos.begin - 1);
|
||||||
|
if (p < len) {
|
||||||
|
c = String.fromCharCode(k);
|
||||||
|
if (tests[p].test(c)) {
|
||||||
|
shiftR(p);
|
||||||
|
|
||||||
|
buffer[p] = c;
|
||||||
|
writeBuffer();
|
||||||
|
next = seekNext(p);
|
||||||
|
|
||||||
|
if(android){
|
||||||
|
setTimeout($.proxy($.fn.caret,input,next),0);
|
||||||
|
}else{
|
||||||
|
input.caret(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.completed && next >= len) {
|
||||||
|
settings.completed.call(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearBuffer(start, end) {
|
||||||
|
var i;
|
||||||
|
for (i = start; i < end && i < len; i++) {
|
||||||
|
if (tests[i]) {
|
||||||
|
buffer[i] = settings.placeholder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeBuffer() { input.val(buffer.join('')); }
|
||||||
|
|
||||||
|
function checkVal(allow) {
|
||||||
|
//try to place characters where they belong
|
||||||
|
var test = input.val(),
|
||||||
|
lastMatch = -1,
|
||||||
|
i,
|
||||||
|
c;
|
||||||
|
|
||||||
|
for (i = 0, pos = 0; i < len; i++) {
|
||||||
|
if (tests[i]) {
|
||||||
|
buffer[i] = settings.placeholder;
|
||||||
|
while (pos++ < test.length) {
|
||||||
|
c = test.charAt(pos - 1);
|
||||||
|
if (tests[i].test(c)) {
|
||||||
|
buffer[i] = c;
|
||||||
|
lastMatch = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos > test.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (buffer[i] === test.charAt(pos) && i !== partialPosition) {
|
||||||
|
pos++;
|
||||||
|
lastMatch = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allow) {
|
||||||
|
writeBuffer();
|
||||||
|
} else if (lastMatch + 1 < partialPosition) {
|
||||||
|
input.val("");
|
||||||
|
clearBuffer(0, len);
|
||||||
|
} else {
|
||||||
|
writeBuffer();
|
||||||
|
input.val(input.val().substring(0, lastMatch + 1));
|
||||||
|
}
|
||||||
|
return (partialPosition ? i : firstNonMaskPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.data($.mask.dataName,function(){
|
||||||
|
return $.map(buffer, function(c, i) {
|
||||||
|
return tests[i]&&c!=settings.placeholder ? c : null;
|
||||||
|
}).join('');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!input.attr("readonly"))
|
||||||
|
input
|
||||||
|
.one("unmask", function() {
|
||||||
|
input
|
||||||
|
.unbind(".mask")
|
||||||
|
.removeData($.mask.dataName);
|
||||||
|
})
|
||||||
|
.bind("focus.mask", function() {
|
||||||
|
clearTimeout(caretTimeoutId);
|
||||||
|
var pos,
|
||||||
|
moveCaret;
|
||||||
|
|
||||||
|
focusText = input.val();
|
||||||
|
pos = checkVal();
|
||||||
|
|
||||||
|
caretTimeoutId = setTimeout(function(){
|
||||||
|
writeBuffer();
|
||||||
|
if (pos == mask.length) {
|
||||||
|
input.caret(0, pos);
|
||||||
|
} else {
|
||||||
|
input.caret(pos);
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
})
|
||||||
|
.bind("blur.mask", function() {
|
||||||
|
checkVal();
|
||||||
|
if (input.val() != focusText)
|
||||||
|
input.change();
|
||||||
|
})
|
||||||
|
.bind("keydown.mask", keydownEvent)
|
||||||
|
.bind("keypress.mask", keypressEvent)
|
||||||
|
.bind(pasteEventName, function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
var pos=checkVal(true);
|
||||||
|
input.caret(pos);
|
||||||
|
if (settings.completed && pos == input.val().length)
|
||||||
|
settings.completed.call(input);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
checkVal(); //Perform initial check for existing values
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
@@ -30,8 +30,8 @@ class ActionFilter extends Behavior
|
|||||||
public function events()
|
public function events()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'beforeAction' => 'beforeFilter',
|
Controller::EVENT_BEFORE_ACTION => 'beforeFilter',
|
||||||
'afterAction' => 'afterFilter',
|
Controller::EVENT_AFTER_ACTION => 'afterFilter',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,6 +278,15 @@ class Application extends Module
|
|||||||
return $this->getComponent('cache');
|
return $this->getComponent('cache');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the formatter component.
|
||||||
|
* @return \yii\base\Formatter the formatter application component.
|
||||||
|
*/
|
||||||
|
public function getFormatter()
|
||||||
|
{
|
||||||
|
return $this->getComponent('formatter');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the request component.
|
* Returns the request component.
|
||||||
* @return \yii\web\Request|\yii\console\Request the request component
|
* @return \yii\web\Request|\yii\console\Request the request component
|
||||||
@@ -333,6 +342,9 @@ class Application extends Module
|
|||||||
'errorHandler' => array(
|
'errorHandler' => array(
|
||||||
'class' => 'yii\base\ErrorHandler',
|
'class' => 'yii\base\ErrorHandler',
|
||||||
),
|
),
|
||||||
|
'formatter' => array(
|
||||||
|
'class' => 'yii\base\Formatter',
|
||||||
|
),
|
||||||
'i18n' => array(
|
'i18n' => array(
|
||||||
'class' => 'yii\i18n\I18N',
|
'class' => 'yii\i18n\I18N',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -151,43 +151,13 @@ class Controller extends Component
|
|||||||
/**
|
/**
|
||||||
* Binds the parameters to the action.
|
* Binds the parameters to the action.
|
||||||
* This method is invoked by [[Action]] when it begins to run with the given parameters.
|
* This method is invoked by [[Action]] when it begins to run with the given parameters.
|
||||||
* This method will check the parameter names that the action requires and return
|
|
||||||
* the provided parameters according to the requirement. If there is any missing parameter,
|
|
||||||
* an exception will be thrown.
|
|
||||||
* @param Action $action the action to be bound with parameters
|
* @param Action $action the action to be bound with parameters
|
||||||
* @param array $params the parameters to be bound to the action
|
* @param array $params the parameters to be bound to the action
|
||||||
* @return array the valid parameters that the action can run with.
|
* @return array the valid parameters that the action can run with.
|
||||||
* @throws InvalidRequestException if there are missing parameters.
|
|
||||||
*/
|
*/
|
||||||
public function bindActionParams($action, $params)
|
public function bindActionParams($action, $params)
|
||||||
{
|
{
|
||||||
if ($action instanceof InlineAction) {
|
return array();
|
||||||
$method = new \ReflectionMethod($this, $action->actionMethod);
|
|
||||||
} else {
|
|
||||||
$method = new \ReflectionMethod($action, 'run');
|
|
||||||
}
|
|
||||||
|
|
||||||
$args = array();
|
|
||||||
$missing = array();
|
|
||||||
foreach ($method->getParameters() as $param) {
|
|
||||||
$name = $param->getName();
|
|
||||||
if (array_key_exists($name, $params)) {
|
|
||||||
$args[] = $params[$name];
|
|
||||||
unset($params[$name]);
|
|
||||||
} elseif ($param->isDefaultValueAvailable()) {
|
|
||||||
$args[] = $param->getDefaultValue();
|
|
||||||
} else {
|
|
||||||
$missing[] = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($missing)) {
|
|
||||||
throw new InvalidRequestException(Yii::t('yii', 'Missing required parameters: {params}', array(
|
|
||||||
'{params}' => implode(', ', $missing),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -271,18 +241,6 @@ class Controller extends Component
|
|||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the parameter being bound to actions.
|
|
||||||
* This method is invoked when parameters are being bound to the currently requested action.
|
|
||||||
* Child classes may override this method to throw exceptions when there are missing and/or unknown parameters.
|
|
||||||
* @param Action $action the currently requested action
|
|
||||||
* @param array $missingParams the names of the missing parameters
|
|
||||||
* @param array $unknownParams the unknown parameters (name => value)
|
|
||||||
*/
|
|
||||||
public function validateActionParams($action, $missingParams, $unknownParams)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string the controller ID that is prefixed with the module ID (if any).
|
* @return string the controller ID that is prefixed with the module ID (if any).
|
||||||
*/
|
*/
|
||||||
|
|||||||
292
framework/yii/base/Formatter.php
Normal file
292
framework/yii/base/Formatter.php
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\base;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use DateTime;
|
||||||
|
use yii\helpers\HtmlPurifier;
|
||||||
|
use yii\helpers\Html;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter provides a set of commonly used data formatting methods.
|
||||||
|
*
|
||||||
|
* The formatting methods provided by Formatter are all named in the form of `asXyz()`.
|
||||||
|
* The behavior of some of them may be configured via the properties of Formatter. For example,
|
||||||
|
* by configuring [[dateFormat]], one may control how [[asDate()]] formats the value into a date string.
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class Formatter extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a date using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $dateFormat = 'Y/m/d';
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a time using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $timeFormat = 'h:i:s A';
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a date and time using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $datetimeFormat = 'Y/m/d h:i:s A';
|
||||||
|
/**
|
||||||
|
* @var array the text to be displayed when formatting a boolean value. The first element corresponds
|
||||||
|
* to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
|
||||||
|
*/
|
||||||
|
public $booleanFormat;
|
||||||
|
/**
|
||||||
|
* @var string the character displayed as the decimal point when formatting a number.
|
||||||
|
*/
|
||||||
|
public $decimalSeparator = '.';
|
||||||
|
/**
|
||||||
|
* @var string the character displayed as the thousands separator character when formatting a number.
|
||||||
|
*/
|
||||||
|
public $thousandSeparator = ',';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the component.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
if (empty($this->booleanFormat)) {
|
||||||
|
$this->booleanFormat = array(Yii::t('yii', 'No'), Yii::t('yii', 'Yes'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as is without any formatting.
|
||||||
|
* This method simply returns back the parameter without any format.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asRaw($value)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as an HTML-encoded plain text.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asText($value)
|
||||||
|
{
|
||||||
|
return Html::encode($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as an HTML-encoded plain text with newlines converted into breaks.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asNtext($value)
|
||||||
|
{
|
||||||
|
return nl2br(Html::encode($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as HTML-encoded text paragraphs.
|
||||||
|
* Each text paragraph is enclosed within a `<p>` tag.
|
||||||
|
* One or multiple consecutive empty lines divide two paragraphs.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asParagraphs($value)
|
||||||
|
{
|
||||||
|
return str_replace('<p></p>', '',
|
||||||
|
'<p>' . preg_replace('/[\r\n]{2,}/', "</p>\n<p>", Html::encode($value)) . '</p>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as HTML text.
|
||||||
|
* The value will be purified using [[HtmlPurifier]] to avoid XSS attacks.
|
||||||
|
* Use [[asRaw()]] if you do not want any purification of the value.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param array|null $config the configuration for the HTMLPurifier class.
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asHtml($value, $config = null)
|
||||||
|
{
|
||||||
|
return HtmlPurifier::process($value, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a mailto link.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asEmail($value)
|
||||||
|
{
|
||||||
|
return Html::mailto($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as an image tag.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asImage($value)
|
||||||
|
{
|
||||||
|
return Html::img($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a hyperlink.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
*/
|
||||||
|
public function asUrl($value)
|
||||||
|
{
|
||||||
|
$url = $value;
|
||||||
|
if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) {
|
||||||
|
$url = 'http://' . $url;
|
||||||
|
}
|
||||||
|
return Html::a(Html::encode($value), $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a boolean.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see booleanFormat
|
||||||
|
*/
|
||||||
|
public function asBoolean($value)
|
||||||
|
{
|
||||||
|
return $value ? $this->booleanFormat[1] : $this->booleanFormat[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a date.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[dateFormat]] will be used. The format string should be one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see dateFormat
|
||||||
|
*/
|
||||||
|
public function asDate($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
return date($format === null ? $this->dateFormat : $format, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a time.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[timeFormat]] will be used. The format string should be one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see timeFormat
|
||||||
|
*/
|
||||||
|
public function asTime($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
return date($format === null ? $this->timeFormat : $format, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a datetime.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[datetimeFormat]] will be used. The format string should be one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see datetimeFormat
|
||||||
|
*/
|
||||||
|
public function asDatetime($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
return date($format === null ? $this->datetimeFormat : $format, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the given datetime value as one that can be taken by various date/time formatting methods.
|
||||||
|
* @param mixed $value the datetime value to be normalized.
|
||||||
|
* @return mixed the normalized datetime value
|
||||||
|
*/
|
||||||
|
protected function normalizeDatetimeValue($value)
|
||||||
|
{
|
||||||
|
if (is_string($value)) {
|
||||||
|
if (ctype_digit($value) || $value[0] === '-' && ctype_digit(substr($value, 1))) {
|
||||||
|
return (int)$value;
|
||||||
|
} else {
|
||||||
|
return strtotime($value);
|
||||||
|
}
|
||||||
|
} elseif ($value instanceof DateTime) {
|
||||||
|
return $value->getTimestamp();
|
||||||
|
} else {
|
||||||
|
return (int)$value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as an integer.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @return string the formatting result.
|
||||||
|
*/
|
||||||
|
public function asInteger($value)
|
||||||
|
{
|
||||||
|
if (is_string($value) && preg_match('/^(-?\d+)/', $value, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
} else {
|
||||||
|
$value = (int)$value;
|
||||||
|
return "$value";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a double number.
|
||||||
|
* Property [[decimalSeparator]] will be used to represent the decimal point.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param integer $decimals the number of digits after the decimal point
|
||||||
|
* @return string the formatting result.
|
||||||
|
* @see decimalSeparator
|
||||||
|
*/
|
||||||
|
public function asDouble($value, $decimals = 2)
|
||||||
|
{
|
||||||
|
return str_replace('.', $this->decimalSeparator, sprintf("%.{$decimals}f", $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a number with decimal and thousand separators.
|
||||||
|
* This method calls the PHP number_format() function to do the formatting.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param integer $decimals the number of digits after the decimal point
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see decimalSeparator
|
||||||
|
* @see thousandSeparator
|
||||||
|
*/
|
||||||
|
public function asNumber($value, $decimals = 0)
|
||||||
|
{
|
||||||
|
return number_format($value, $decimals, $this->decimalSeparator, $this->thousandSeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @link http://www.yiiframework.com/
|
|
||||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
|
||||||
* @license http://www.yiiframework.com/license/
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace yii\base;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* InvalidRequestException represents an exception caused by incorrect end user request.
|
|
||||||
*
|
|
||||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
class InvalidRequestException extends UserException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @return string the user-friendly name of this exception
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return \Yii::t('yii', 'Invalid Request');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
namespace yii\bootstrap;
|
namespace yii\bootstrap;
|
||||||
|
|
||||||
use yii\base\InvalidConfigException;
|
use yii\base\InvalidConfigException;
|
||||||
use yii\helpers\base\ArrayHelper;
|
use yii\helpers\ArrayHelper;
|
||||||
use yii\helpers\Html;
|
use yii\helpers\Html;
|
||||||
|
|
||||||
|
|
||||||
@@ -32,17 +32,22 @@ class Dropdown extends Widget
|
|||||||
* // optional, url of the item link
|
* // optional, url of the item link
|
||||||
* 'url' => '',
|
* 'url' => '',
|
||||||
* // optional the HTML attributes of the item link
|
* // optional the HTML attributes of the item link
|
||||||
* 'urlOptions'=> array(...),
|
* 'linkOptions'=> array(...),
|
||||||
* // optional the HTML attributes of the item
|
* // optional the HTML attributes of the item
|
||||||
* 'options'=> array(...),
|
* 'options'=> array(...),
|
||||||
* // optional, an array of items that configure a sub menu of the item
|
* // optional, an array of items that configure a sub menu of the item
|
||||||
* // note: if `items` is set, then `url` of the parent item will be ignored and automatically set to "#"
|
* // note: if `items` is set, then `url` of the parent item will be ignored and automatically set to "#"
|
||||||
|
* // important: there is an issue with sub-dropdown menus, and as of 3.0, bootstrap won't support sub-dropdown
|
||||||
|
* // @see https://github.com/twitter/bootstrap/issues/5050#issuecomment-11741727
|
||||||
* 'items'=> array(...)
|
* 'items'=> array(...)
|
||||||
* )
|
* )
|
||||||
* ```
|
* ```
|
||||||
* Additionally, you can also configure a dropdown item as string.
|
|
||||||
*/
|
*/
|
||||||
public $items = array();
|
public $items = array();
|
||||||
|
/**
|
||||||
|
* @var boolean whether the labels for header items should be HTML-encoded.
|
||||||
|
*/
|
||||||
|
public $encodeLabels = true;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,43 +65,41 @@ class Dropdown extends Widget
|
|||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
echo Html::beginTag('ul', $this->options) . "\n";
|
echo $this->renderItems() . "\n";
|
||||||
echo $this->renderContents() . "\n";
|
|
||||||
echo Html::endTag('ul') . "\n";
|
|
||||||
$this->registerPlugin('dropdown');
|
$this->registerPlugin('dropdown');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders dropdown contents as specified on [[items]].
|
* Renders dropdown items as specified on [[items]].
|
||||||
* @return string the rendering result.
|
* @return string the rendering result.
|
||||||
* @throws InvalidConfigException
|
* @throws InvalidConfigException
|
||||||
*/
|
*/
|
||||||
protected function renderContents()
|
protected function renderItems()
|
||||||
{
|
{
|
||||||
$contents = array();
|
$items = array();
|
||||||
foreach ($this->items as $item) {
|
foreach ($this->items as $item) {
|
||||||
if (is_string($item)) {
|
if (is_string($item)) {
|
||||||
$contents[] = $item;
|
$items[] = $item;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isset($item['label'])) {
|
if (!isset($item['label'])) {
|
||||||
throw new InvalidConfigException("The 'label' option is required.");
|
throw new InvalidConfigException("The 'label' option is required.");
|
||||||
}
|
}
|
||||||
|
$label = $this->encodeLabels ? Html::encode($item['label']) : $item['label'];
|
||||||
$options = ArrayHelper::getValue($item, 'options', array());
|
$options = ArrayHelper::getValue($item, 'options', array());
|
||||||
$urlOptions = ArrayHelper::getValue($item, 'urlOptions', array());
|
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', array());
|
||||||
$urlOptions['tabindex'] = '-1';
|
$linkOptions['tabindex'] = '-1';
|
||||||
|
|
||||||
if (isset($item['items'])) {
|
if (isset($item['items'])) {
|
||||||
$this->addCssClass($options, 'dropdown-submenu');
|
$this->addCssClass($options, 'dropdown-submenu');
|
||||||
$content = Html::a($item['label'], '#', $urlOptions) . $this->dropdown($item['items']);
|
$content = Html::a($label, '#', $linkOptions) . $this->dropdown($item['items']);
|
||||||
} else {
|
} else {
|
||||||
$content = Html::a($item['label'], ArrayHelper::getValue($item, 'url', '#'), $urlOptions);
|
$content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions);
|
||||||
}
|
}
|
||||||
$contents[] = Html::tag('li', $content , $options);
|
$items[] = Html::tag('li', $content , $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode("\n", $contents);
|
return Html::tag('ul', implode("\n", $items), $this->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ class Html
|
|||||||
/**
|
/**
|
||||||
* Generates a hyperlink tag.
|
* Generates a hyperlink tag.
|
||||||
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
|
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
|
||||||
* such as an image tag. If this is is coming from end users, you should consider [[encode()]]
|
* such as an image tag. If this is coming from end users, you should consider [[encode()]]
|
||||||
* it to prevent XSS attacks.
|
* it to prevent XSS attacks.
|
||||||
* @param array|string|null $url the URL for the hyperlink tag. This parameter will be processed by [[url()]]
|
* @param array|string|null $url the URL for the hyperlink tag. This parameter will be processed by [[url()]]
|
||||||
* and will be used for the "href" attribute of the tag. If this parameter is null, the "href" attribute
|
* and will be used for the "href" attribute of the tag. If this parameter is null, the "href" attribute
|
||||||
@@ -366,7 +366,7 @@ class Html
|
|||||||
/**
|
/**
|
||||||
* Generates a mailto hyperlink.
|
* Generates a mailto hyperlink.
|
||||||
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
|
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
|
||||||
* such as an image tag. If this is is coming from end users, you should consider [[encode()]]
|
* such as an image tag. If this is coming from end users, you should consider [[encode()]]
|
||||||
* it to prevent XSS attacks.
|
* it to prevent XSS attacks.
|
||||||
* @param string $email email address. If this is null, the first parameter (link body) will be treated
|
* @param string $email email address. If this is null, the first parameter (link body) will be treated
|
||||||
* as the email address and used.
|
* as the email address and used.
|
||||||
|
|||||||
232
framework/yii/i18n/Formatter.php
Normal file
232
framework/yii/i18n/Formatter.php
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\i18n;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use IntlDateFormatter;
|
||||||
|
use NumberFormatter;
|
||||||
|
use DateTime;
|
||||||
|
use yii\base\InvalidConfigException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter is the localized version of [[\yii\base\Formatter]].
|
||||||
|
*
|
||||||
|
* Formatter requires the PHP "intl" extension to be installed. Formatter supports localized
|
||||||
|
* formatting of date, time and numbers, based on the current [[locale]].
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class Formatter extends \yii\base\Formatter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string the locale ID that is used to localize the date and number formatting.
|
||||||
|
* If not set, [[\yii\base\Application::language]] will be used.
|
||||||
|
*/
|
||||||
|
public $locale;
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a date using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $dateFormat = 'short';
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a time using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $timeFormat = 'short';
|
||||||
|
/**
|
||||||
|
* @var string the default format string to be used to format a date and time using PHP date() function.
|
||||||
|
*/
|
||||||
|
public $datetimeFormat = 'short';
|
||||||
|
/**
|
||||||
|
* @var array the options to be set for the NumberFormatter objects. Please refer to
|
||||||
|
*/
|
||||||
|
public $numberFormatOptions = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the component.
|
||||||
|
* This method will check if the "intl" PHP extension is installed and set the
|
||||||
|
* default value of [[locale]].
|
||||||
|
* @throws InvalidConfigException if the "intl" PHP extension is not installed.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
if (!extension_loaded('intl')) {
|
||||||
|
throw new InvalidConfigException('The "intl" PHP extension is not install. It is required to format data values in localized formats.');
|
||||||
|
}
|
||||||
|
if ($this->locale === null) {
|
||||||
|
$this->locale = Yii::$app->language;
|
||||||
|
}
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private $_dateFormats = array(
|
||||||
|
'short' => IntlDateFormatter::SHORT,
|
||||||
|
'medium' => IntlDateFormatter::MEDIUM,
|
||||||
|
'long' => IntlDateFormatter::LONG,
|
||||||
|
'full' => IntlDateFormatter::FULL,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a date.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[dateFormat]] will be used. The format string should be the one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see dateFormat
|
||||||
|
*/
|
||||||
|
public function asDate($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
if ($format === null) {
|
||||||
|
$format = $this->dateFormat;
|
||||||
|
}
|
||||||
|
if (isset($this->_dateFormats[$format])) {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE);
|
||||||
|
} else {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE);
|
||||||
|
$formatter->setPattern($format);
|
||||||
|
}
|
||||||
|
return $formatter->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a time.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[dateFormat]] will be used. The format string should be the one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see timeFormat
|
||||||
|
*/
|
||||||
|
public function asTime($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
if ($format === null) {
|
||||||
|
$format = $this->timeFormat;
|
||||||
|
}
|
||||||
|
if (isset($this->_dateFormats[$format])) {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format]);
|
||||||
|
} else {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE);
|
||||||
|
$formatter->setPattern($format);
|
||||||
|
}
|
||||||
|
return $formatter->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a datetime.
|
||||||
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - an integer representing a UNIX timestamp
|
||||||
|
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
||||||
|
* - a PHP DateTime object
|
||||||
|
*
|
||||||
|
* @param string $format the format used to convert the value into a date string.
|
||||||
|
* If null, [[dateFormat]] will be used. The format string should be the one
|
||||||
|
* that can be recognized by the PHP `date()` function.
|
||||||
|
* @return string the formatted result
|
||||||
|
* @see datetimeFormat
|
||||||
|
*/
|
||||||
|
public function asDatetime($value, $format = null)
|
||||||
|
{
|
||||||
|
$value = $this->normalizeDatetimeValue($value);
|
||||||
|
if ($format === null) {
|
||||||
|
$format = $this->datetimeFormat;
|
||||||
|
}
|
||||||
|
if (isset($this->_dateFormats[$format])) {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format]);
|
||||||
|
} else {
|
||||||
|
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE);
|
||||||
|
$formatter->setPattern($format);
|
||||||
|
}
|
||||||
|
return $formatter->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a decimal number.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
|
||||||
|
* for details on how to specify a format.
|
||||||
|
* @return string the formatted result.
|
||||||
|
*/
|
||||||
|
public function asDecimal($value, $format = null)
|
||||||
|
{
|
||||||
|
return $this->createNumberFormatter(NumberFormatter::DECIMAL, $format)->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a currency number.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param string $currency the 3-letter ISO 4217 currency code indicating the currency to use.
|
||||||
|
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
|
||||||
|
* for details on how to specify a format.
|
||||||
|
* @return string the formatted result.
|
||||||
|
*/
|
||||||
|
public function asCurrency($value, $currency = 'USD', $format = null)
|
||||||
|
{
|
||||||
|
return $this->createNumberFormatter(NumberFormatter::CURRENCY, $format)->formatCurrency($value, $currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a percent number.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
|
||||||
|
* for details on how to specify a format.
|
||||||
|
* @return string the formatted result.
|
||||||
|
*/
|
||||||
|
public function asPercent($value, $format = null)
|
||||||
|
{
|
||||||
|
return $this->createNumberFormatter(NumberFormatter::PERCENT, $format)->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the value as a scientific number.
|
||||||
|
* @param mixed $value the value to be formatted
|
||||||
|
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
|
||||||
|
* for details on how to specify a format.
|
||||||
|
* @return string the formatted result.
|
||||||
|
*/
|
||||||
|
public function asScientific($value, $format = null)
|
||||||
|
{
|
||||||
|
return $this->createNumberFormatter(NumberFormatter::SCIENTIFIC, $format)->format($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a number formatter based on the given type and format.
|
||||||
|
* @param integer $type the type of the number formatter
|
||||||
|
* @param string $format the format to be used
|
||||||
|
* @return NumberFormatter the created formatter instance
|
||||||
|
*/
|
||||||
|
protected function createNumberFormatter($type, $format)
|
||||||
|
{
|
||||||
|
$formatter = new NumberFormatter($this->locale, $type);
|
||||||
|
if ($format !== null) {
|
||||||
|
$formatter->setPattern($format);
|
||||||
|
}
|
||||||
|
if (!empty($this->numberFormatOptions)) {
|
||||||
|
foreach ($this->numberFormatOptions as $name => $attribute) {
|
||||||
|
$formatter->setAttribute($name, $attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $formatter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,6 +43,6 @@ return array(
|
|||||||
'mandatory' => false,
|
'mandatory' => false,
|
||||||
'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2'),
|
'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2'),
|
||||||
'by' => '<a href="http://www.php.net/manual/en/book.intl.php">Internationalization</a> support',
|
'by' => '<a href="http://www.php.net/manual/en/book.intl.php">Internationalization</a> support',
|
||||||
'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use <abbr title="Internationalized domain names">IDN</abbr>-feature of EmailValidator or UrlValidator.'
|
'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use <abbr title="Internationalized domain names">IDN</abbr>-feature of EmailValidator or UrlValidator or the <code>yii\i18n\Formatter</code> class.'
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
namespace yii\web;
|
namespace yii\web;
|
||||||
|
|
||||||
use Yii;
|
use Yii;
|
||||||
|
use yii\base\HttpException;
|
||||||
|
use yii\base\InlineAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller is the base class of Web controllers.
|
* Controller is the base class of Web controllers.
|
||||||
@@ -18,6 +20,48 @@ use Yii;
|
|||||||
*/
|
*/
|
||||||
class Controller extends \yii\base\Controller
|
class Controller extends \yii\base\Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Binds the parameters to the action.
|
||||||
|
* This method is invoked by [[Action]] when it begins to run with the given parameters.
|
||||||
|
* This method will check the parameter names that the action requires and return
|
||||||
|
* the provided parameters according to the requirement. If there is any missing parameter,
|
||||||
|
* an exception will be thrown.
|
||||||
|
* @param \yii\base\Action $action the action to be bound with parameters
|
||||||
|
* @param array $params the parameters to be bound to the action
|
||||||
|
* @return array the valid parameters that the action can run with.
|
||||||
|
* @throws HttpException if there are missing parameters.
|
||||||
|
*/
|
||||||
|
public function bindActionParams($action, $params)
|
||||||
|
{
|
||||||
|
if ($action instanceof InlineAction) {
|
||||||
|
$method = new \ReflectionMethod($this, $action->actionMethod);
|
||||||
|
} else {
|
||||||
|
$method = new \ReflectionMethod($action, 'run');
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array();
|
||||||
|
$missing = array();
|
||||||
|
foreach ($method->getParameters() as $param) {
|
||||||
|
$name = $param->getName();
|
||||||
|
if (array_key_exists($name, $params)) {
|
||||||
|
$args[] = $params[$name];
|
||||||
|
unset($params[$name]);
|
||||||
|
} elseif ($param->isDefaultValueAvailable()) {
|
||||||
|
$args[] = $param->getDefaultValue();
|
||||||
|
} else {
|
||||||
|
$missing[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($missing)) {
|
||||||
|
throw new HttpException(400, Yii::t('yii', 'Missing required parameters: {params}', array(
|
||||||
|
'{params}' => implode(', ', $missing),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a URL using the given route and parameters.
|
* Creates a URL using the given route and parameters.
|
||||||
*
|
*
|
||||||
|
|||||||
90
framework/yii/web/VerbFilter.php
Normal file
90
framework/yii/web/VerbFilter.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\web;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use yii\base\ActionEvent;
|
||||||
|
use yii\base\Behavior;
|
||||||
|
use yii\base\HttpException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VerbFilter is an action filter that filters by HTTP request methods.
|
||||||
|
*
|
||||||
|
* It allows to define allowed HTTP request methods for each action and will throw
|
||||||
|
* an HTTP 405 error when the method is not allowed.
|
||||||
|
*
|
||||||
|
* To use VerbFilter, declare it in the `behaviors()` method of your controller class.
|
||||||
|
* For example, the following declarations will define a typical set of allowed
|
||||||
|
* request methods for REST CRUD actions.
|
||||||
|
*
|
||||||
|
* ~~~
|
||||||
|
* public function behaviors()
|
||||||
|
* {
|
||||||
|
* return array(
|
||||||
|
* 'verbs' => array(
|
||||||
|
* 'class' => \yii\web\VerbFilter::className(),
|
||||||
|
* 'actions' => array(
|
||||||
|
* 'index' => array('get'),
|
||||||
|
* 'view' => array('get'),
|
||||||
|
* 'create' => array('get', 'post'),
|
||||||
|
* 'update' => array('get', 'put', 'post'),
|
||||||
|
* 'delete' => array('post', 'delete'),
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* ~~~
|
||||||
|
*
|
||||||
|
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7
|
||||||
|
* @author Carsten Brandt <mail@cebe.cc>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class VerbFilter extends Behavior
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array this property defines the allowed request methods for each action.
|
||||||
|
* For each action that should only support limited set of request methods
|
||||||
|
* you add an entry with the action id as array key and an array of
|
||||||
|
* allowed methods (e.g. GET, HEAD, PUT) as the value.
|
||||||
|
* If an action is not listed all request methods are considered allowed.
|
||||||
|
*/
|
||||||
|
public $actions = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares event handlers for the [[owner]]'s events.
|
||||||
|
* @return array events (array keys) and the corresponding event handler methods (array values).
|
||||||
|
*/
|
||||||
|
public function events()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
Controller::EVENT_BEFORE_ACTION => 'beforeAction',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ActionEvent $event
|
||||||
|
* @return boolean
|
||||||
|
* @throws \yii\base\HttpException when the request method is not allowed.
|
||||||
|
*/
|
||||||
|
public function beforeAction($event)
|
||||||
|
{
|
||||||
|
$action = $event->action->id;
|
||||||
|
if (isset($this->actions[$action])) {
|
||||||
|
$verb = Yii::$app->getRequest()->getRequestMethod();
|
||||||
|
$allowed = array_map('strtoupper', $this->actions[$action]);
|
||||||
|
if (!in_array($verb, $allowed)) {
|
||||||
|
$event->isValid = false;
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7
|
||||||
|
header('Allow: ' . implode(', ', $allowed));
|
||||||
|
throw new HttpException(405, 'Method Not Allowed. This url can only handle the following request methods: ' . implode(', ', $allowed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $event->isValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,8 +134,8 @@ class ActiveForm extends Widget
|
|||||||
$id = $this->options['id'];
|
$id = $this->options['id'];
|
||||||
$options = Json::encode($this->getClientOptions());
|
$options = Json::encode($this->getClientOptions());
|
||||||
$attributes = Json::encode($this->attributes);
|
$attributes = Json::encode($this->attributes);
|
||||||
$this->view->registerAssetBundle('yii/form');
|
$this->getView()->registerAssetBundle('yii/form');
|
||||||
$this->view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
|
$this->getView()->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
|
||||||
}
|
}
|
||||||
echo Html::endForm();
|
echo Html::endForm();
|
||||||
}
|
}
|
||||||
|
|||||||
64
framework/yii/widgets/InputWidget.php
Normal file
64
framework/yii/widgets/InputWidget.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\widgets;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use yii\base\Widget;
|
||||||
|
use yii\base\Model;
|
||||||
|
use yii\base\InvalidConfigException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InputWidget is the base class for widgets that collect user inputs.
|
||||||
|
*
|
||||||
|
* An input widget can be associated with a data model and an attribute,
|
||||||
|
* or a name and a value. If the former, the name and the value will
|
||||||
|
* be generated automatically.
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class InputWidget extends Widget
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Model the data model that this widget is associated with.
|
||||||
|
*/
|
||||||
|
public $model;
|
||||||
|
/**
|
||||||
|
* @var string the model attribute that this widget is associated with.
|
||||||
|
*/
|
||||||
|
public $attribute;
|
||||||
|
/**
|
||||||
|
* @var string the input name. This must be set if [[model]] and [[attribute]] are not set.
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
/**
|
||||||
|
* @var string the input value.
|
||||||
|
*/
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the widget.
|
||||||
|
* If you override this method, make sure you call the parent implementation first.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
if (!$this->hasModel() && $this->name === null) {
|
||||||
|
throw new InvalidConfigException("Either 'name' or 'model' and 'attribute' properties must be specified.");
|
||||||
|
}
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean whether this widget is associated with a data model.
|
||||||
|
*/
|
||||||
|
protected function hasModel()
|
||||||
|
{
|
||||||
|
return $this->model instanceof Model && $this->attribute !== null;
|
||||||
|
}
|
||||||
|
}
|
||||||
136
framework/yii/widgets/MaskedInput.php
Normal file
136
framework/yii/widgets/MaskedInput.php
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\widgets;
|
||||||
|
|
||||||
|
use yii\base\InvalidConfigException;
|
||||||
|
use yii\helpers\Html;
|
||||||
|
use yii\helpers\Json;
|
||||||
|
use yii\web\JsExpression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MaskedInput generates a masked text input.
|
||||||
|
*
|
||||||
|
* MaskedInput is similar to [[Html::textInput()]] except that
|
||||||
|
* an input mask will be used to force users to enter properly formatted data,
|
||||||
|
* such as phone numbers, social security numbers.
|
||||||
|
*
|
||||||
|
* To use MaskedInput, you must set the [[mask]] property. The following example
|
||||||
|
* shows how to use MaskedInput to collect phone numbers:
|
||||||
|
*
|
||||||
|
* ~~~
|
||||||
|
* echo MaskedInput::widget(array(
|
||||||
|
* 'name' => 'phone',
|
||||||
|
* 'mask' => '999-999-9999',
|
||||||
|
* ));
|
||||||
|
* ~~~
|
||||||
|
*
|
||||||
|
* The masked text field is implemented based on the [jQuery masked input plugin](http://digitalbush.com/projects/masked-input-plugin).
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class MaskedInput extends InputWidget
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string the input mask (e.g. '99/99/9999' for date input). The following characters are predefined:
|
||||||
|
*
|
||||||
|
* - `a`: represents an alpha character (A-Z,a-z)
|
||||||
|
* - `9`: represents a numeric character (0-9)
|
||||||
|
* - `*`: represents an alphanumeric character (A-Z,a-z,0-9)
|
||||||
|
* - `?`: anything listed after '?' within the mask is considered optional user input
|
||||||
|
*
|
||||||
|
* Additional characters can be defined by specifying the [[charMap]] property.
|
||||||
|
*/
|
||||||
|
public $mask;
|
||||||
|
/**
|
||||||
|
* @var array the mapping between mask characters and the corresponding patterns.
|
||||||
|
* For example, `array('~' => '[+-]')` specifies that the '~' character expects '+' or '-' input.
|
||||||
|
* Defaults to null, meaning using the map as described in [[mask]].
|
||||||
|
*/
|
||||||
|
public $charMap;
|
||||||
|
/**
|
||||||
|
* @var string the character prompting for user input. Defaults to underscore '_'.
|
||||||
|
*/
|
||||||
|
public $placeholder;
|
||||||
|
/**
|
||||||
|
* @var string a JavaScript function callback that will be invoked when user finishes the input.
|
||||||
|
*/
|
||||||
|
public $completed;
|
||||||
|
/**
|
||||||
|
* @var array the HTML attributes for the input tag.
|
||||||
|
*/
|
||||||
|
public $options = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the widget.
|
||||||
|
* @throws InvalidConfigException if the "mask" property is not set.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
if (empty($this->mask)) {
|
||||||
|
throw new InvalidConfigException('The "mask" property must be set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->options['id'])) {
|
||||||
|
$this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the widget.
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
if ($this->hasModel()) {
|
||||||
|
echo Html::activeTextInput($this->model, $this->attribute, $this->options);
|
||||||
|
} else {
|
||||||
|
echo Html::textInput($this->name, $this->value, $this->options);
|
||||||
|
}
|
||||||
|
$this->registerClientScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the needed JavaScript.
|
||||||
|
*/
|
||||||
|
public function registerClientScript()
|
||||||
|
{
|
||||||
|
$options = $this->getClientOptions();
|
||||||
|
$options = empty($options) ? '' : ',' . Json::encode($options);
|
||||||
|
$js = '';
|
||||||
|
if (is_array($this->charMap) && !empty($this->charMap)) {
|
||||||
|
$js .= 'jQuery.mask.definitions=' . Json::encode($this->charMap) . ";\n";
|
||||||
|
}
|
||||||
|
$id = $this->options['id'];
|
||||||
|
$js .= "jQuery(\"#{$id}\").mask(\"{$this->mask}\"{$options});";
|
||||||
|
$this->getView()->registerAssetBundle('yii/maskedinput');
|
||||||
|
$this->getView()->registerJs($js);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array the options for the text field
|
||||||
|
*/
|
||||||
|
protected function getClientOptions()
|
||||||
|
{
|
||||||
|
$options = array();
|
||||||
|
if ($this->placeholder !== null) {
|
||||||
|
$options['placeholder'] = $this->placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->completed !== null) {
|
||||||
|
if ($this->completed instanceof JsExpression) {
|
||||||
|
$options['completed'] = $this->completed;
|
||||||
|
} else {
|
||||||
|
$options['completed'] = new JsExpression($this->completed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
179
tests/unit/framework/base/FormatterTest.php
Normal file
179
tests/unit/framework/base/FormatterTest.php
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
namespace yiiunit\framework\base;
|
||||||
|
|
||||||
|
use yii\base\Formatter;
|
||||||
|
use yiiunit\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class FormatterTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Formatter
|
||||||
|
*/
|
||||||
|
protected $formatter;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->mockApplication();
|
||||||
|
$this->formatter = new Formatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
$this->formatter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsRaw()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame($value, $this->formatter->asRaw($value));
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame($value, $this->formatter->asRaw($value));
|
||||||
|
$value = '<>';
|
||||||
|
$this->assertSame($value, $this->formatter->asRaw($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsText()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame($value, $this->formatter->asText($value));
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame("$value", $this->formatter->asText($value));
|
||||||
|
$value = '<>';
|
||||||
|
$this->assertSame('<>', $this->formatter->asText($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsNtext()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame($value, $this->formatter->asNtext($value));
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame("$value", $this->formatter->asNtext($value));
|
||||||
|
$value = '<>';
|
||||||
|
$this->assertSame('<>', $this->formatter->asNtext($value));
|
||||||
|
$value = "123\n456";
|
||||||
|
$this->assertSame("123<br />\n456", $this->formatter->asNtext($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsParagraphs()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame("<p>$value</p>", $this->formatter->asParagraphs($value));
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame("<p>$value</p>", $this->formatter->asParagraphs($value));
|
||||||
|
$value = '<>';
|
||||||
|
$this->assertSame('<p><></p>', $this->formatter->asParagraphs($value));
|
||||||
|
$value = "123\n456";
|
||||||
|
$this->assertSame("<p>123\n456</p>", $this->formatter->asParagraphs($value));
|
||||||
|
$value = "123\n\n456";
|
||||||
|
$this->assertSame("<p>123</p>\n<p>456</p>", $this->formatter->asParagraphs($value));
|
||||||
|
$value = "123\n\n\n456";
|
||||||
|
$this->assertSame("<p>123</p>\n<p>456</p>", $this->formatter->asParagraphs($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsHtml()
|
||||||
|
{
|
||||||
|
// todo: dependency on HtmlPurifier
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsEmail()
|
||||||
|
{
|
||||||
|
$value = 'test@sample.com';
|
||||||
|
$this->assertSame("<a href=\"mailto:$value\">$value</a>", $this->formatter->asEmail($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsImage()
|
||||||
|
{
|
||||||
|
$value = 'http://sample.com/img.jpg';
|
||||||
|
$this->assertSame("<img src=\"$value\" alt=\"\" />", $this->formatter->asImage($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsBoolean()
|
||||||
|
{
|
||||||
|
$value = true;
|
||||||
|
$this->assertSame('Yes', $this->formatter->asBoolean($value));
|
||||||
|
$value = false;
|
||||||
|
$this->assertSame('No', $this->formatter->asBoolean($value));
|
||||||
|
$value = "111";
|
||||||
|
$this->assertSame('Yes', $this->formatter->asBoolean($value));
|
||||||
|
$value = "";
|
||||||
|
$this->assertSame('No', $this->formatter->asBoolean($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsDate()
|
||||||
|
{
|
||||||
|
$value = time();
|
||||||
|
$this->assertSame(date('Y/m/d', $value), $this->formatter->asDate($value));
|
||||||
|
$this->assertSame(date('Y-m-d', $value), $this->formatter->asDate($value, 'Y-m-d'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsTime()
|
||||||
|
{
|
||||||
|
$value = time();
|
||||||
|
$this->assertSame(date('h:i:s A', $value), $this->formatter->asTime($value));
|
||||||
|
$this->assertSame(date('h:i:s', $value), $this->formatter->asTime($value, 'h:i:s'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsDatetime()
|
||||||
|
{
|
||||||
|
$value = time();
|
||||||
|
$this->assertSame(date('Y/m/d h:i:s A', $value), $this->formatter->asDatetime($value));
|
||||||
|
$this->assertSame(date('Y-m-d h:i:s', $value), $this->formatter->asDatetime($value, 'Y-m-d h:i:s'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsInteger()
|
||||||
|
{
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame("$value", $this->formatter->asInteger($value));
|
||||||
|
$value = 123.23;
|
||||||
|
$this->assertSame("123", $this->formatter->asInteger($value));
|
||||||
|
$value = 'a';
|
||||||
|
$this->assertSame("0", $this->formatter->asInteger($value));
|
||||||
|
$value = -123.23;
|
||||||
|
$this->assertSame("-123", $this->formatter->asInteger($value));
|
||||||
|
$value = "-123abc";
|
||||||
|
$this->assertSame("-123", $this->formatter->asInteger($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsDouble()
|
||||||
|
{
|
||||||
|
$value = 123.12;
|
||||||
|
$this->assertSame("123.12", $this->formatter->asDouble($value));
|
||||||
|
$this->assertSame("123.1", $this->formatter->asDouble($value, 1));
|
||||||
|
$this->assertSame("123", $this->formatter->asDouble($value, 0));
|
||||||
|
$value = 123;
|
||||||
|
$this->assertSame("123.00", $this->formatter->asDouble($value));
|
||||||
|
$this->formatter->decimalSeparator = ',';
|
||||||
|
$value = 123.12;
|
||||||
|
$this->assertSame("123,12", $this->formatter->asDouble($value));
|
||||||
|
$this->assertSame("123,1", $this->formatter->asDouble($value, 1));
|
||||||
|
$this->assertSame("123", $this->formatter->asDouble($value, 0));
|
||||||
|
$value = 123123.123;
|
||||||
|
$this->assertSame("123123,12", $this->formatter->asDouble($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsNumber()
|
||||||
|
{
|
||||||
|
$value = 123123.123;
|
||||||
|
$this->assertSame("123,123", $this->formatter->asNumber($value));
|
||||||
|
$this->assertSame("123,123.12", $this->formatter->asNumber($value, 2));
|
||||||
|
$this->formatter->decimalSeparator = ',';
|
||||||
|
$this->formatter->thousandSeparator = ' ';
|
||||||
|
$this->assertSame("123 123", $this->formatter->asNumber($value));
|
||||||
|
$this->assertSame("123 123,12", $this->formatter->asNumber($value, 2));
|
||||||
|
$this->formatter->thousandSeparator = '';
|
||||||
|
$this->assertSame("123123", $this->formatter->asNumber($value));
|
||||||
|
$this->assertSame("123123,12", $this->formatter->asNumber($value, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
88
tests/unit/framework/i18n/FormatterTest.php
Normal file
88
tests/unit/framework/i18n/FormatterTest.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yiiunit\framework\i18n;
|
||||||
|
|
||||||
|
use yii\i18n\Formatter;
|
||||||
|
use yiiunit\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class FormatterTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Formatter
|
||||||
|
*/
|
||||||
|
protected $formatter;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
if (!extension_loaded('intl')) {
|
||||||
|
$this->markTestSkipped('intl extension is required.');
|
||||||
|
}
|
||||||
|
$this->mockApplication();
|
||||||
|
$this->formatter = new Formatter(array(
|
||||||
|
'locale' => 'en_US',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
$this->formatter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsDecimal()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame($value, $this->formatter->asDecimal($value));
|
||||||
|
$value = '123456';
|
||||||
|
$this->assertSame("123,456", $this->formatter->asDecimal($value));
|
||||||
|
$value = '-123456.123';
|
||||||
|
$this->assertSame("-123,456.123", $this->formatter->asDecimal($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsPercent()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame('12,300%', $this->formatter->asPercent($value));
|
||||||
|
$value = '0.1234';
|
||||||
|
$this->assertSame("12%", $this->formatter->asPercent($value));
|
||||||
|
$value = '-0.009343';
|
||||||
|
$this->assertSame("-1%", $this->formatter->asPercent($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsScientific()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame('1.23E2', $this->formatter->asScientific($value));
|
||||||
|
$value = '123456';
|
||||||
|
$this->assertSame("1.23456E5", $this->formatter->asScientific($value));
|
||||||
|
$value = '-123456.123';
|
||||||
|
$this->assertSame("-1.23456123E5", $this->formatter->asScientific($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsCurrency()
|
||||||
|
{
|
||||||
|
$value = '123';
|
||||||
|
$this->assertSame('$123.00', $this->formatter->asCurrency($value));
|
||||||
|
$value = '123.456';
|
||||||
|
$this->assertSame("$123.46", $this->formatter->asCurrency($value));
|
||||||
|
$value = '-123456.123';
|
||||||
|
$this->assertSame("($123,456.12)", $this->formatter->asCurrency($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDate()
|
||||||
|
{
|
||||||
|
$time = time();
|
||||||
|
$this->assertSame(date('n/j/y', $time), $this->formatter->asDate($time));
|
||||||
|
$this->assertSame(date('M j, Y', $time), $this->formatter->asDate($time, 'long'));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user