diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e4b8278 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + +env: + - DB=mysql + +before_script: + - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS yiitest;'; fi" + +script: phpunit \ No newline at end of file diff --git a/build/build b/build/build index fff4282..691eba9 100755 --- a/build/build +++ b/build/build @@ -16,5 +16,5 @@ require(__DIR__ . '/../framework/yii.php'); $id = 'yiic-build'; $basePath = __DIR__; -$application = new yii\console\Application($id, $basePath); +$application = new yii\console\Application(array('id' => $id, 'basePath' => $basePath)); $application->run(); diff --git a/docs/guide/active-record.md b/docs/guide/active-record.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/authentication.md b/docs/guide/authentication.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/authorization.md b/docs/guide/authorization.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/caching.md b/docs/guide/caching.md new file mode 100644 index 0000000..cd945e7 --- /dev/null +++ b/docs/guide/caching.md @@ -0,0 +1,3 @@ +Caching +======= + diff --git a/docs/guide/console.md b/docs/guide/console.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/dao.md b/docs/guide/dao.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/error.md b/docs/guide/error.md new file mode 100644 index 0000000..c97fada --- /dev/null +++ b/docs/guide/error.md @@ -0,0 +1,3 @@ +Error Handling +============== + diff --git a/docs/guide/extension.md b/docs/guide/extension.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/form.md b/docs/guide/form.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/gii.md b/docs/guide/gii.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 6cc5ef8..3f9a803 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -25,8 +25,8 @@ http://hostname/path/to/yii/requirements/index.php ~~~ Yii requires PHP 5.3, so the server must have PHP 5.3 or above installed and -available to the web server. Yii has been tested with [Apache HTTP server](http://httpd.apache.org/) -on Windows and Linux. It may also run on other Web servers and platforms, +available to the web server. Yii has been tested with [Apache HTTP server](http://httpd.apache.org/) +on Windows and Linux. It may also run on other Web servers and platforms, provided PHP 5.3 is supported. @@ -34,7 +34,7 @@ Recommended Apache Configuration -------------------------------- Yii is ready to work with a default Apache web server configuration. -The `.htaccess` files in Yii framework and application folders restrict +The `.htaccess` files in Yii framework and application folders deny access to the restricted resources. To hide the bootstrap file (usually `index.php`) in your URLs you can add `mod_rewrite` instructions to the `.htaccess` file in your document root or to the virtual host configuration: @@ -63,7 +63,7 @@ server { access_log /www/mysite/log/access.log main; server_name mysite; - root $host_path/htdocs; + root $host_path/htdocs; set $yii_bootstrap "index.php"; charset utf-8; @@ -108,4 +108,5 @@ server { } ~~~ -Using this configuration you can set `cgi.fix_pathinfo=0` in php.ini to avoid many unnecessary system stat() calls. +Using this configuration you can set `cgi.fix_pathinfo=0` in php.ini to avoid +many unnecessary system `stat()` calls. diff --git a/docs/guide/logging.md b/docs/guide/logging.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/migration.md b/docs/guide/migration.md new file mode 100644 index 0000000..0fe2fb3 --- /dev/null +++ b/docs/guide/migration.md @@ -0,0 +1,3 @@ +Database Migration +================== + diff --git a/docs/guide/mvc.md b/docs/guide/mvc.md index 79140ce..a99d043 100644 --- a/docs/guide/mvc.md +++ b/docs/guide/mvc.md @@ -11,7 +11,7 @@ the communication between the model and the view. Besides implementing MVC, Yii also introduces a front-controller, called `Application`, which encapsulates the execution context for the processing -of a request. Application collects some information about a user request and +of a request. Application collects information about a user request and then dispatches it to an appropriate controller for further handling. The following diagram shows the static structure of a Yii application: @@ -21,6 +21,7 @@ The following diagram shows the static structure of a Yii application: A Typical Workflow ------------------ + The following diagram shows a typical workflow of a Yii application when it is handling a user request: diff --git a/docs/guide/performance.md b/docs/guide/performance.md new file mode 100644 index 0000000..9a871dc --- /dev/null +++ b/docs/guide/performance.md @@ -0,0 +1,181 @@ +Performance Tuning +================== + +Application performance consists of two parts. First is the framework performance +and the second is the application itself. Yii has a pretty low performance impact +on your application out of the box and can be fine-tuned further for production +environment. As for the application, we'll provide some of the best practices +along with examples on how to apply them to Yii. + +Preparing framework for production +---------------------------------- + +### Disabling Debug Mode + +First thing you should do before deploying your application to production environment +is to disable debug mode. A Yii application runs in debug mode if the constant +`YII_DEBUG` is defined as `true` in `index.php` so to disable debug the following +should be in your `index.php`: + +```php +defined('YII_DEBUG') or define('YII_DEBUG', false); +``` + +Debug mode is very useful during development stage, but it would impact performance +because some components cause extra burden in debug mode. For example, the message +logger may record additional debug information for every message being logged. + +### Enabling PHP opcode cache + +Enabling the PHP opcode cache improves any PHP application performance and lowers +memory usage significantly. Yii is no exception. It was tested with +[APC PHP extension](http://php.net/manual/en/book.apc.php) that caches +and optimizes PHP intermediate code and avoids the time spent in parsing PHP +scripts for every incoming request. + +### Turning on ActiveRecord database schema caching + +If the application is using Active Record, we should turn on the schema caching +to save the time of parsing database schema. This can be done by setting the +`Connection::enableSchemaCache` property to be `true` via application configuration +`protected/config/main.php`: + +```php +return array( + // ... + 'components' => array( + // ... + 'db' => array( + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=localhost;dbname=mydatabase', + 'username' => 'root', + 'password' => '', + 'enableSchemaCache' => true, + + // Duration of schema cache. + // 'schemaCacheDuration' => 3600, + + // Name of the cache component used. Default is 'cache'. + //'schemaCache' => 'cache', + ), + 'cache' => array( + 'class' => 'yii\caching\FileCache', + ), + ), +); +``` + +Note that `cache` application component should be configured. + +### Combining and Minimizing Assets + +TBD + +### Using better storage for sessions + +By default PHP uses files to handle sessions. It is OK for development and +small projects but when it comes to handling concurrent requests it's better to +switch to another storage such as database. You can do so by configuring your +application via `protected/config/main.php`: + +```php +return array( + // ... + 'components' => array( + 'session' => array( + 'class' => 'yii\web\DbSession', + + // Set the following if want to use DB component other than + // default 'db'. + // 'db' => 'mydb', + + // To override default session table set the following + // 'sessionTable' => 'my_session', + ), + ), +); +``` + +You can use `CacheSession` to store sessions using cache. Note that some +cache storages such as memcached has no guaranteee that session data will not +be lost leading to unexpected logouts. + +Improving application +--------------------- + +### Using Serverside Caching Techniques + +As described in the Caching section, Yii provides several caching solutions that +may improve the performance of a Web application significantly. If the generation +of some data takes long time, we can use the data caching approach to reduce the +data generation frequency; If a portion of page remains relatively static, we +can use the fragment caching approach to reduce its rendering frequency; +If a whole page remains relative static, we can use the page caching approach to +save the rendering cost for the whole page. + + +### Leveraging HTTP to save procesing time and bandwidth + +TBD + +### Database Optimization + +Fetching data from database is often the main performance bottleneck in +a Web application. Although using caching may alleviate the performance hit, +it does not fully solve the problem. When the database contains enormous data +and the cached data is invalid, fetching the latest data could be prohibitively +expensive without proper database and query design. + +Design index wisely in a database. Indexing can make SELECT queries much faster, +but it may slow down INSERT, UPDATE or DELETE queries. + +For complex queries, it is recommended to create a database view for it instead +of issuing the queries inside the PHP code and asking DBMS to parse them repetitively. + +Do not overuse Active Record. Although Active Record is good at modelling data +in an OOP fashion, it actually degrades performance due to the fact that it needs +to create one or several objects to represent each row of query result. For data +intensive applications, using DAO or database APIs at lower level could be +a better choice. + +Last but not least, use LIMIT in your SELECT queries. This avoids fetching +overwhelming data from database and exhausting the memory allocated to PHP. + +### Using asArray + +A good way to save memory and processing time on read-only pages is to use +ActiveRecord's `asArray` method. + +```php +class PostController extends Controller +{ + public function actionIndex() + { + $posts = Post::find()->orderBy('id DESC')->limit(100)->asArray()->all(); + echo $this->render('index', array( + 'posts' => $posts, + )); + } +} +``` + +In the view you should access fields of each invidual record from `$posts` as array: + +```php +foreach($posts as $post) { + echo $post['title']."
"; +} +``` + +Note that you can use array notation even if `asArray` wasn't specified and you're +working with AR objects. + +### Processing data in background + +In order to respond to user requests faster you can process heavy parts of the +request later if there's no need for immediate response. + +- Cron jobs + console. +- queues + handlers. + +TBD \ No newline at end of file diff --git a/docs/guide/query-builder.md b/docs/guide/query-builder.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/security.md b/docs/guide/security.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/template.md b/docs/guide/template.md new file mode 100644 index 0000000..dc83d15 --- /dev/null +++ b/docs/guide/template.md @@ -0,0 +1,3 @@ +Template +======== + diff --git a/docs/guide/testing.md b/docs/guide/testing.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/theming.md b/docs/guide/theming.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/guide/url.md b/docs/guide/url.md new file mode 100644 index 0000000..46bb177 --- /dev/null +++ b/docs/guide/url.md @@ -0,0 +1,3 @@ +URL Management +============== + diff --git a/docs/guide/validation.md b/docs/guide/validation.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/view_renderers.md b/docs/view_renderers.md index 1d88d21..e26fe83 100644 --- a/docs/view_renderers.md +++ b/docs/view_renderers.md @@ -27,6 +27,9 @@ array( ) ``` +Note that Smarty and Twig are not bundled with Yii and you have to download and +unpack these yourself and then specify `twigPath` and `smartyPath` respectively. + Twig ---- diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 9d501b1..ed975c9 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -600,6 +600,13 @@ class YiiBase */ public static function t($message, $params = array(), $language = null) { - return self::$app->getI18N()->translate($message, $params, $language); + if (self::$app !== null) { + return self::$app->getI18N()->translate($message, $params, $language); + } else { + if (strpos($message, '|') !== false && preg_match('/^([\w\-\\/\.\\\\]+)\|(.*)/', $message, $matches)) { + $message = $matches[2]; + } + return is_array($params) ? strtr($message, $params) : $message; + } } } diff --git a/framework/base/Widget.php b/framework/base/Widget.php index 13e6d30..1aabd4f 100644 --- a/framework/base/Widget.php +++ b/framework/base/Widget.php @@ -83,7 +83,8 @@ class Widget extends Component */ public function render($view, $params = array()) { - return $this->view->render($view, $params, $this); + $viewFile = $this->findViewFile($view); + return $this->view->renderFile($viewFile, $params, $this); } /** diff --git a/framework/db/ActiveRelation.php b/framework/db/ActiveRelation.php index f1b198b..97e2a8c 100644 --- a/framework/db/ActiveRelation.php +++ b/framework/db/ActiveRelation.php @@ -266,7 +266,7 @@ class ActiveRelation extends ActiveQuery { $attributes = array_keys($this->link); $values = array(); - if (count($attributes) ===1) { + if (count($attributes) === 1) { // single key $attribute = reset($this->link); foreach ($models as $model) { diff --git a/framework/db/Connection.php b/framework/db/Connection.php index 797508a..f71b940 100644 --- a/framework/db/Connection.php +++ b/framework/db/Connection.php @@ -517,7 +517,7 @@ class Connection extends Component public function quoteSql($sql) { $db = $this; - return preg_replace_callback('/(\\{\\{([\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/', + return preg_replace_callback('/(\\{\\{([%\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/', function($matches) use($db) { if (isset($matches[3])) { return $db->quoteColumnName($matches[3]); diff --git a/framework/db/Query.php b/framework/db/Query.php index 2239f5d..6f76265 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -483,7 +483,7 @@ class Query extends \yii\base\Component * Sets the ORDER BY part of the query. * @param string|array $columns the columns (and the directions) to be ordered by. * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`). + * (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). * @return Query the query object itself @@ -499,7 +499,7 @@ class Query extends \yii\base\Component * Adds additional ORDER BY columns to the query. * @param string|array $columns the columns (and the directions) to be ordered by. * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`). + * (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). * @return Query the query object itself diff --git a/framework/helpers/base/ArrayHelper.php b/framework/helpers/base/ArrayHelper.php index 9870542..5f72fe4 100644 --- a/framework/helpers/base/ArrayHelper.php +++ b/framework/helpers/base/ArrayHelper.php @@ -236,15 +236,17 @@ class ArrayHelper * To sort by multiple keys, provide an array of keys here. * @param boolean|array $ascending whether to sort in ascending or descending order. When * sorting by multiple keys with different ascending orders, use an array of ascending flags. - * @param integer|array $sortFlag the PHP sort flag. Valid values include: - * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, and `SORT_STRING | SORT_FLAG_CASE`. The last - * value is for sorting strings in case-insensitive manner. Please refer to - * See [PHP manual](http://php.net/manual/en/function.sort.php) for more details. - * When sorting by multiple keys with different sort flags, use an array of sort flags. + * @param integer|array $sortFlag the PHP sort flag. Valid values include + * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING` and `SORT_LOCALE_STRING`. + * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php) + * for more details. When sorting by multiple keys with different sort flags, use an array of sort flags. + * @param boolean|array $caseSensitive whether to sort string in case-sensitive manner. This parameter + * is used only when `$sortFlag` is `SORT_STRING`. + * When sorting by multiple keys with different case sensitivities, use an array of boolean values. * @throws InvalidParamException if the $ascending or $sortFlag parameters do not have * correct number of elements as that of $key. */ - public static function multisort(&$array, $key, $ascending = true, $sortFlag = SORT_REGULAR) + public static function multisort(&$array, $key, $ascending = true, $sortFlag = SORT_REGULAR, $caseSensitive = true) { $keys = is_array($key) ? $key : array($key); if (empty($keys) || empty($array)) { @@ -259,20 +261,30 @@ class ArrayHelper if (is_scalar($sortFlag)) { $sortFlag = array_fill(0, $n, $sortFlag); } elseif (count($sortFlag) !== $n) { - throw new InvalidParamException('The length of $ascending parameter must be the same as that of $keys.'); + throw new InvalidParamException('The length of $sortFlag parameter must be the same as that of $keys.'); + } + if (is_scalar($caseSensitive)) { + $caseSensitive = array_fill(0, $n, $caseSensitive); + } elseif (count($caseSensitive) !== $n) { + throw new InvalidParamException('The length of $caseSensitive parameter must be the same as that of $keys.'); } $args = array(); foreach ($keys as $i => $key) { $flag = $sortFlag[$i]; - if ($flag == (SORT_STRING | SORT_FLAG_CASE)) { - $flag = SORT_STRING; - $column = array(); - foreach (static::getColumn($array, $key) as $k => $value) { - $column[$k] = strtolower($value); + $cs = $caseSensitive[$i]; + if (!$cs && ($flag === SORT_STRING)) { + if (defined('SORT_FLAG_CASE')) { + $flag = $flag | SORT_FLAG_CASE; + $args[] = static::getColumn($array, $key); + } else { + $column = array(); + foreach (static::getColumn($array, $key) as $k => $value) { + $column[$k] = mb_strtolower($value); + } + $args[] = $column; } - $args[] = $column; } else { - $args[] = static::getColumn($array, $key); + $args[] = static::getColumn($array, $key); } $args[] = $ascending[$i] ? SORT_ASC : SORT_DESC; $args[] = $flag; diff --git a/framework/helpers/base/Html.php b/framework/helpers/base/Html.php index 5b8e7db..15db823 100644 --- a/framework/helpers/base/Html.php +++ b/framework/helpers/base/Html.php @@ -95,9 +95,9 @@ class Html public static $attributeOrder = array( 'type', 'id', + 'class', 'name', 'value', - 'class', 'href', 'src', @@ -127,13 +127,15 @@ class Html * Encodes special characters into HTML entities. * The [[yii\base\Application::charset|application charset]] will be used for encoding. * @param string $content the content to be encoded + * @param boolean $doubleEncode whether to encode HTML entities in `$content`. If false, + * HTML entities in `$content` will not be further encoded. * @return string the encoded content * @see decode * @see http://www.php.net/manual/en/function.htmlspecialchars.php */ - public static function encode($content) + public static function encode($content, $doubleEncode = true) { - return htmlspecialchars($content, ENT_QUOTES, Yii::$app->charset); + return htmlspecialchars($content, ENT_QUOTES, Yii::$app->charset, $doubleEncode); } /** @@ -375,7 +377,8 @@ class Html */ public static function mailto($text, $email = null, $options = array()) { - return static::a($text, 'mailto:' . ($email === null ? $text : $email), $options); + $options['href'] = 'mailto:' . ($email === null ? $text : $email); + return static::tag('a', $text, $options); } /** diff --git a/framework/helpers/base/SecurityHelper.php b/framework/helpers/base/SecurityHelper.php index 6ba48ba..ed5bfd6 100644 --- a/framework/helpers/base/SecurityHelper.php +++ b/framework/helpers/base/SecurityHelper.php @@ -42,7 +42,8 @@ class SecurityHelper public static function encrypt($data, $key) { $module = static::openCryptModule(); - $key = StringHelper::substr($key, 0, mcrypt_enc_get_key_size($module)); + // 192-bit (24 bytes) key size + $key = StringHelper::substr($key, 0, 24); srand(); $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); mcrypt_generic_init($module, $key, $iv); @@ -63,7 +64,8 @@ class SecurityHelper public static function decrypt($data, $key) { $module = static::openCryptModule(); - $key = StringHelper::substr($key, 0, mcrypt_enc_get_key_size($module)); + // 192-bit (24 bytes) key size + $key = StringHelper::substr($key, 0, 24); $ivSize = mcrypt_enc_get_iv_size($module); $iv = StringHelper::substr($data, 0, $ivSize); mcrypt_generic_init($module, $key, $iv); @@ -148,7 +150,8 @@ class SecurityHelper if (!extension_loaded('mcrypt')) { throw new InvalidConfigException('The mcrypt PHP extension is not installed.'); } - $module = @mcrypt_module_open('rijndael-256', '', MCRYPT_MODE_CBC, ''); + // AES uses a 128-bit block size + $module = @mcrypt_module_open('rijndael-128', '', 'cbc', ''); if ($module === false) { throw new Exception('Failed to initialize the mcrypt module.'); } @@ -269,4 +272,4 @@ class SecurityHelper $salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22)); return $salt; } -} \ No newline at end of file +} diff --git a/framework/helpers/base/VarDumper.php b/framework/helpers/base/VarDumper.php index fe15d98..43b0cd8 100644 --- a/framework/helpers/base/VarDumper.php +++ b/framework/helpers/base/VarDumper.php @@ -116,7 +116,7 @@ class VarDumper } elseif (self::$_depth <= $level) { self::$_output .= get_class($var) . '(...)'; } else { - $id = self::$_objects[] = $var; + $id = array_push(self::$_objects, $var); $className = get_class($var); $members = (array)$var; $spaces = str_repeat(' ', $level * 4); diff --git a/framework/web/Request.php b/framework/web/Request.php index ac19d5a..5e2f064 100644 --- a/framework/web/Request.php +++ b/framework/web/Request.php @@ -96,7 +96,7 @@ class Request extends \yii\base\Request */ public function getIsPostRequest() { - return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'], 'POST'); + return $this->getRequestMethod() === 'POST'; } /** diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..bf37a26 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + + + ./tests/unit + + + \ No newline at end of file diff --git a/readme.md b/readme.md index dfb9c45..6293292 100644 --- a/readme.md +++ b/readme.md @@ -34,6 +34,6 @@ You are welcome to participate in Yii 2 development in the following ways: * [Report issues](https://github.com/yiisoft/yii2/issues) * [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-design-discussions-for-yii-20/) * Fix issues, develop features, write/polish documentation - - Before you start, please adopt an existing issue or start a new one to avoid duplicated efforts. + - Before you start, please adopt an existing issue (labelled with "ready for adoption") or start a new one to avoid duplicated efforts. - Please submit a merge request after you finish development. diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php index fc15690..238a7cc 100644 --- a/tests/unit/data/config.php +++ b/tests/unit/data/config.php @@ -3,7 +3,7 @@ return array( 'mysql' => array( 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', - 'username' => 'root', + 'username' => 'travis', 'password' => '', 'fixture' => __DIR__ . '/mysql.sql', ), diff --git a/tests/unit/framework/helpers/ArrayHelperTest.php b/tests/unit/framework/helpers/ArrayHelperTest.php index 187217f..b3ffabf 100644 --- a/tests/unit/framework/helpers/ArrayHelperTest.php +++ b/tests/unit/framework/helpers/ArrayHelperTest.php @@ -40,11 +40,20 @@ class ArrayHelperTest extends \yii\test\TestCase $array = array( array('name' => 'a', 'age' => 3), array('name' => 'b', 'age' => 2), + array('name' => 'B', 'age' => 4), array('name' => 'A', 'age' => 1), ); - ArrayHelper::multisort($array, array('name', 'age'), SORT_ASC, array(SORT_STRING|SORT_FLAG_CASE, SORT_REGULAR)); + + ArrayHelper::multisort($array, array('name', 'age'), SORT_ASC, array(SORT_STRING, SORT_REGULAR)); + $this->assertEquals(array('name' => 'A', 'age' => 1), $array[0]); + $this->assertEquals(array('name' => 'B', 'age' => 4), $array[1]); + $this->assertEquals(array('name' => 'a', 'age' => 3), $array[2]); + $this->assertEquals(array('name' => 'b', 'age' => 2), $array[3]); + + ArrayHelper::multisort($array, array('name', 'age'), SORT_ASC, array(SORT_STRING, SORT_REGULAR), false); $this->assertEquals(array('name' => 'A', 'age' => 1), $array[0]); $this->assertEquals(array('name' => 'a', 'age' => 3), $array[1]); $this->assertEquals(array('name' => 'b', 'age' => 2), $array[2]); + $this->assertEquals(array('name' => 'B', 'age' => 4), $array[3]); } } diff --git a/tests/unit/framework/helpers/VarDumperTest.php b/tests/unit/framework/helpers/VarDumperTest.php new file mode 100644 index 0000000..8757588 --- /dev/null +++ b/tests/unit/framework/helpers/VarDumperTest.php @@ -0,0 +1,12 @@ + - \ No newline at end of file