From 4d720389c3aa5fae65341a6541131edfe575c999 Mon Sep 17 00:00:00 2001 From: egorpromo Date: Sun, 17 Nov 2013 19:48:27 +0700 Subject: [PATCH 01/35] It is more obviouse what to pass in trigger() method --- framework/yii/base/Component.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php index 48d4f05..9af22a8 100644 --- a/framework/yii/base/Component.php +++ b/framework/yii/base/Component.php @@ -436,7 +436,7 @@ class Component extends Object * @param string $name the event name * @param Event $event the event parameter. If not set, a default [[Event]] object will be created. */ - public function trigger($name, $event = null) + public function trigger($name, Event $event = null) { $this->ensureBehaviors(); if (!empty($this->_events[$name])) { From a0824422b234f9ea949f41726657ffc953c8a67d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sun, 17 Nov 2013 15:43:05 +0100 Subject: [PATCH 02/35] removed duplicate assignment of primaryKey in cubrid --- framework/yii/db/cubrid/Schema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index 3131fa8..458f2e3 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -180,7 +180,7 @@ class Schema extends \yii\db\Schema $column->name = $info['Field']; $column->allowNull = $info['Null'] === 'YES'; - $column->isPrimaryKey = strpos($info['Key'], 'PRI') !== false; + $column->isPrimaryKey = false; // primary key will be set by loadTableSchema() later $column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false; $column->dbType = strtolower($info['Type']); From c768ee7196546be61e968a251578332458ead832 Mon Sep 17 00:00:00 2001 From: Larry Ullman Date: Sun, 17 Nov 2013 09:49:50 -0500 Subject: [PATCH 03/35] Just started editing --- docs/guide/performance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/performance.md b/docs/guide/performance.md index d16d962..42aa042 100644 --- a/docs/guide/performance.md +++ b/docs/guide/performance.md @@ -1,7 +1,7 @@ Performance Tuning ================== -Application performance consists of two parts. First is the framework performance +The performance of your web application is based upon 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 From 2230ecb185816534c9466c90f5a6c9f31ffdb9d1 Mon Sep 17 00:00:00 2001 From: Larry Ullman Date: Sun, 17 Nov 2013 11:50:46 -0500 Subject: [PATCH 04/35] Edited model.md up to Validation --- docs/guide/model.md | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/docs/guide/model.md b/docs/guide/model.md index 154fd38..465cb16 100644 --- a/docs/guide/model.md +++ b/docs/guide/model.md @@ -8,16 +8,15 @@ In keeping with the MVC approach, a model in Yii is intended for storing or temp - Massive attribute assignment: the ability to populate multiple model attributes in one step. - Scenario-based data validation. -Models in Yii extend from the [[\yii\base\Model]] class. Models are typically used to both hold data and define the validation rules for that data. The validation rules greatly simply the generation of models from complex web forms. -The Model class is also the base for more advanced models with additional functionality such as [Active Record](active-record.md). +Models in Yii extend from the [[\yii\base\Model]] class. Models are typically used to both hold data and define the validation rules for that data (aka, the business logic). The business logic greatly simplifies the generation of models from complex web forms by providing validation and error reporting. +The Model class is also the base class for more advanced models with additional functionality, such as [Active Record](active-record.md). Attributes ---------- -Attributes store the actual data represented by a model and can -be accessed like object member variables. For example, a `Post` model -may contain a `title` attribute and a `content` attribute which may be -accessed as follows: +The actual data represented by a model is stored in the model's *attributes*. Model attributes can +be accessed like the member variables of any object. For example, a `Post` model +may contain a `title` attribute and a `content` attribute, accessible as follows: ```php $post = new Post; @@ -28,7 +27,7 @@ echo $post->content; ``` Since [[\yii\base\Model|Model]] implements the [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) interface, -you can also access the attributes like accessing array elements: +you can also access the attributes as if they were array elements: ```php $post = new Post; @@ -51,8 +50,8 @@ class LoginForm extends \yii\base\Model } ``` -Derived model classes may use different ways to declare attributes by overriding the [[\yii\base\Model::attributes()|attributes()]] -method. For example, [[\yii\db\ActiveRecord]] defines attributes as the column names of the database table +Derived model classes may declare attributes in different ways, by overriding the [[\yii\base\Model::attributes()|attributes()]] +method. For example, [[\yii\db\ActiveRecord]] defines attributes using the column names of the database table that is associated with the class. @@ -60,13 +59,11 @@ Attribute Labels ---------------- Attribute labels are mainly used for display purpose. For example, given an attribute `firstName`, we can declare -a label `First Name` which is more user-friendly and can be displayed to end users in places such as form labels, +a label `First Name` that is more user-friendly when displayed to end users in places such as form labels and error messages. Given an attribute name, you can obtain its label by calling [[\yii\base\Model::getAttributeLabel()]]. -To declare attribute labels, you should override the [[\yii\base\Model::attributeLabels()]] method and return -a mapping from attribute names to attribute labels, like shown in the example below. If an attribute is not found -in this mapping, its label will be generated using the [[\yii\base\Model::generateAttributeLabel()]] method, which -in many cases, will generate reasonable labels (e.g. `username` to `Username`, `orderNumber` to `Order Number`). +To declare attribute labels, override the [[\yii\base\Model::attributeLabels()]] method. The overridden method returns a mapping of attribute names to attribute labels, as shown in the example below. If an attribute is not found +in this mapping, its label will be generated using the [[\yii\base\Model::generateAttributeLabel()]] method. In many cases, [[\yii\base\Model::generateAttributeLabel()]] will generate reasonable labels (e.g. `username` to `Username`, `orderNumber` to `Order Number`). ```php // LoginForm has two attributes: username and password @@ -88,17 +85,19 @@ class LoginForm extends \yii\base\Model Scenarios --------- -A model may be used in different scenarios. For example, a `User` model may be used to collect user login inputs, -and it may also be used for user registration purpose. For this reason, each model has a property named `scenario` -which stores the name of the scenario that the model is currently being used in. As we will explain in the next -few sections, the concept of scenario is mainly used for data validation and massive attribute assignment. +A model may be used in different *scenarios*. For example, a `User` model may be used to collect user login inputs, +but it may also be used for user registration purposes. In the one scenario, every piece of data is required; in the other, only the username and password would be. + +To easily implement the business logic for different scenarios, each model has a property named `scenario` +that stores the name of the scenario that the model is currently being used in. As will be explained in the next +few sections, the concept of scenarios is mainly used for data validation and massive attribute assignment. Associated with each scenario is a list of attributes that are *active* in that particular scenario. For example, in the `login` scenario, only the `username` and `password` attributes are active; while in the `register` scenario, additional attributes such as `email` are *active*. -Possible scenarios should be listed in the `scenarios()` method which returns an array whose keys are the scenario -names and whose values are the corresponding active attribute lists. Below is an example: +Possible scenarios should be listed in the `scenarios()` method. This method returns an array whose keys are the scenario +names and whose values are lists of attributes that should be active in that scenario: ```php class User extends \yii\db\ActiveRecord @@ -113,14 +112,14 @@ class User extends \yii\db\ActiveRecord } ``` -Sometimes, we want to mark an attribute as not safe for massive assignment (but we still want it to be validated). -We may do so by prefixing an exclamation character to the attribute name when declaring it in `scenarios()`. For example, +Sometimes, we want to mark an attribute as not safe for massive assignment (but we still want the attribute to be validated). +We may do so by prefixing an exclamation character to the attribute name when declaring it in `scenarios()`. For example: ```php ['username', 'password', '!secret'] ``` -Active model scenario could be set using one of the following ways: +Identifying the active model scenario can be done using one of the following approaches: ```php class EmployeeController extends \yii\web\Controller @@ -143,8 +142,7 @@ class EmployeeController extends \yii\web\Controller } ``` -In the example above we are using [Active Record](active-record.md). For basic form models it's rarely needed to -use scenarios since form model is typically used for a single form. +The example above presumes that the model is based upon [Active Record](active-record.md). For basic form models, scenarios are rarely needed, as the basic form model is normally tied directly to a single form. Validation ---------- From 09a3300b7c3ebd774d04ebeee13d23449c341b0b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sun, 17 Nov 2013 21:09:13 +0100 Subject: [PATCH 05/35] refactored redis cache, added mset() --- framework/yii/caching/RedisCache.php | 85 +++++++++++++------------ tests/unit/framework/caching/ApcCacheTest.php | 5 ++ tests/unit/framework/caching/CacheTestCase.php | 26 +++++++- tests/unit/framework/caching/DbCacheTest.php | 12 ++++ tests/unit/framework/caching/FileCacheTest.php | 12 ++++ tests/unit/framework/caching/MemCacheTest.php | 8 +++ tests/unit/framework/caching/MemCachedTest.php | 8 +++ tests/unit/framework/caching/RedisCacheTest.php | 11 ++++ 8 files changed, 125 insertions(+), 42 deletions(-) diff --git a/framework/yii/caching/RedisCache.php b/framework/yii/caching/RedisCache.php index d31d66b..b64f000 100644 --- a/framework/yii/caching/RedisCache.php +++ b/framework/yii/caching/RedisCache.php @@ -10,7 +10,7 @@ namespace yii\caching; use yii\redis\Connection; /** - * RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6 or higher. + * RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6.12 or higher. * * RedisCache needs to be configured with [[hostname]], [[port]] and [[database]] of the server * to connect to. By default RedisCache assumes there is a redis server running on localhost at @@ -119,10 +119,7 @@ class RedisCache extends Cache } /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. + * @inheritDocs */ protected function getValue($key) { @@ -130,9 +127,7 @@ class RedisCache extends Cache } /** - * Retrieves multiple values from cache with the specified keys. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys + * @inheritDocs */ protected function getValues($keys) { @@ -146,55 +141,67 @@ class RedisCache extends Cache } /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param float $expire the number of seconds in which the cached value will expire. 0 means never expire. - * This can be a floating point number to specify the time in milliseconds. - * @return boolean true if the value is successfully stored into cache, false otherwise + * @inheritDocs */ - protected function setValue($key,$value,$expire) + protected function setValue($key, $value, $expire) { if ($expire == 0) { return (bool) $this->_connection->executeCommand('SET', [$key, $value]); } else { $expire = (int) ($expire * 1000); - return (bool) $this->_connection->executeCommand('PSETEX', [$key, $expire, $value]); + return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'PX', $expire]); } } /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param float $expire the number of seconds in which the cached value will expire. 0 means never expire. - * This can be a floating point number to specify the time in milliseconds. - * @return boolean true if the value is successfully stored into cache, false otherwise + * @inheritDocs */ - protected function addValue($key,$value,$expire) + protected function setValues($data, $expire) { + $args = []; + foreach($data as $key => $value) { + $args[] = $key; + $args[] = $value; + } + + $failedKeys = []; if ($expire == 0) { - return (bool) $this->_connection->executeCommand('SETNX', [$key, $value]); + $this->_connection->executeCommand('MSET', $args); } else { - // TODO consider requiring redis version >= 2.6.12 that supports this in one command $expire = (int) ($expire * 1000); $this->_connection->executeCommand('MULTI'); - $this->_connection->executeCommand('SETNX', [$key, $value]); - $this->_connection->executeCommand('PEXPIRE', [$key, $expire]); - $response = $this->_connection->executeCommand('EXEC'); - return (bool) $response[0]; + $this->_connection->executeCommand('MSET', $args); + $index = []; + foreach ($data as $key => $value) { + $this->_connection->executeCommand('PEXPIRE', [$key, $expire]); + $index[] = $key; + } + $result = $this->_connection->executeCommand('EXEC'); + array_shift($result); + foreach($result as $i => $r) { + if ($r != 1) { + $failedKeys[] = $index[$i]; + } + } + } + return $failedKeys; + } + + /** + * @inheritDocs + */ + protected function addValue($key, $value, $expire) + { + if ($expire == 0) { + return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'NX']); + } else { + $expire = (int) ($expire * 1000); + return (bool) $this->_connection->executeCommand('SET', [$key, $value, 'PX', $expire, 'NX']); } } /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion + * @inheritDocs */ protected function deleteValue($key) { @@ -202,9 +209,7 @@ class RedisCache extends Cache } /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. + * @inheritDocs */ protected function flushValues() { diff --git a/tests/unit/framework/caching/ApcCacheTest.php b/tests/unit/framework/caching/ApcCacheTest.php index adda151..b65ec41 100644 --- a/tests/unit/framework/caching/ApcCacheTest.php +++ b/tests/unit/framework/caching/ApcCacheTest.php @@ -37,4 +37,9 @@ class ApcCacheTest extends CacheTestCase { $this->markTestSkipped("APC keys are expiring only on the next request."); } + + public function testExpireAdd() + { + $this->markTestSkipped("APC keys are expiring only on the next request."); + } } diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index 849cad0..afd514d 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -91,7 +91,18 @@ abstract class CacheTestCase extends TestCase $this->assertEquals('array_test', $array['array_test']); } - public function testMset() + /** + * @return array testing mset with and without expiry + */ + public function msetExpiry() + { + return [[0], [2]]; + } + + /** + * @dataProvider msetExpiry + */ + public function testMset($expiry) { $cache = $this->getCacheInstance(); $cache->flush(); @@ -100,7 +111,7 @@ abstract class CacheTestCase extends TestCase 'string_test' => 'string_test', 'number_test' => 42, 'array_test' => ['array_test' => 'array_test'], - ]); + ], $expiry); $this->assertEquals('string_test', $cache->get('string_test')); @@ -170,6 +181,17 @@ abstract class CacheTestCase extends TestCase $this->assertFalse($cache->get('expire_test')); } + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + usleep(500000); + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + usleep(2500000); + $this->assertFalse($cache->get('expire_testa')); + } + public function testAdd() { $cache = $this->prepare(); diff --git a/tests/unit/framework/caching/DbCacheTest.php b/tests/unit/framework/caching/DbCacheTest.php index c3c0233..c2d03e2 100644 --- a/tests/unit/framework/caching/DbCacheTest.php +++ b/tests/unit/framework/caching/DbCacheTest.php @@ -83,4 +83,16 @@ class DbCacheTest extends CacheTestCase static::$time++; $this->assertFalse($cache->get('expire_test')); } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + static::$time++; + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + static::$time++; + $this->assertFalse($cache->get('expire_testa')); + } } diff --git a/tests/unit/framework/caching/FileCacheTest.php b/tests/unit/framework/caching/FileCacheTest.php index 70271c9..f102614 100644 --- a/tests/unit/framework/caching/FileCacheTest.php +++ b/tests/unit/framework/caching/FileCacheTest.php @@ -33,4 +33,16 @@ class FileCacheTest extends CacheTestCase static::$time++; $this->assertFalse($cache->get('expire_test')); } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + static::$time++; + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + static::$time++; + $this->assertFalse($cache->get('expire_testa')); + } } diff --git a/tests/unit/framework/caching/MemCacheTest.php b/tests/unit/framework/caching/MemCacheTest.php index e489a39..63f8be1 100644 --- a/tests/unit/framework/caching/MemCacheTest.php +++ b/tests/unit/framework/caching/MemCacheTest.php @@ -34,4 +34,12 @@ class MemCacheTest extends CacheTestCase } parent::testExpire(); } + + public function testExpireAdd() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); + } + parent::testExpireAdd(); + } } diff --git a/tests/unit/framework/caching/MemCachedTest.php b/tests/unit/framework/caching/MemCachedTest.php index 57ee110..3a9d415 100644 --- a/tests/unit/framework/caching/MemCachedTest.php +++ b/tests/unit/framework/caching/MemCachedTest.php @@ -34,4 +34,12 @@ class MemCachedTest extends CacheTestCase } parent::testExpire(); } + + public function testExpireAdd() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); + } + parent::testExpireAdd(); + } } diff --git a/tests/unit/framework/caching/RedisCacheTest.php b/tests/unit/framework/caching/RedisCacheTest.php index b064f78..3201a49 100644 --- a/tests/unit/framework/caching/RedisCacheTest.php +++ b/tests/unit/framework/caching/RedisCacheTest.php @@ -45,6 +45,17 @@ class RedisCacheTest extends CacheTestCase $this->assertFalse($cache->get('expire_test_ms')); } + public function testExpireAddMilliseconds() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->add('expire_testa_ms', 'expire_testa_ms', 0.2)); + usleep(100000); + $this->assertEquals('expire_testa_ms', $cache->get('expire_testa_ms')); + usleep(300000); + $this->assertFalse($cache->get('expire_testa_ms')); + } + /** * Store a value that is 2 times buffer size big * https://github.com/yiisoft/yii2/issues/743 From 8d4bf893e1f405c35ff571703578eaad6e479d23 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 18 Nov 2013 11:23:11 -0500 Subject: [PATCH 06/35] Fixes #1221: make it easier to subclass BaseDataProvider with custom pagination. --- framework/yii/data/BaseDataProvider.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php index db1e057..cf094c7 100644 --- a/framework/yii/data/BaseDataProvider.php +++ b/framework/yii/data/BaseDataProvider.php @@ -165,10 +165,7 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa public function getPagination() { if ($this->_pagination === null) { - $this->_pagination = new Pagination; - if ($this->id !== null) { - $this->_pagination->pageVar = $this->id . '-page'; - } + $this->setPagination([]); } return $this->_pagination; } From 49da1b4aadb935d8ab43ee9ed068dd52d02a611a Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 18 Nov 2013 12:27:58 -0500 Subject: [PATCH 07/35] Fixes #1225: doc fix. --- framework/yii/base/Widget.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/base/Widget.php b/framework/yii/base/Widget.php index c47a89d..4a06c92 100644 --- a/framework/yii/base/Widget.php +++ b/framework/yii/base/Widget.php @@ -41,7 +41,7 @@ class Widget extends Component implements ViewContextInterface * This method creates an instance of the calling class. It will apply the configuration * to the created instance. A matching [[end()]] call should be called later. * @param array $config name-value pairs that will be used to initialize the object properties - * @return Widget the newly created widget instance + * @return static the newly created widget instance */ public static function begin($config = []) { @@ -55,7 +55,7 @@ class Widget extends Component implements ViewContextInterface /** * Ends a widget. * Note that the rendering result of the widget is directly echoed out. - * @return Widget the widget instance that is ended. + * @return static the widget instance that is ended. * @throws InvalidCallException if [[begin()]] and [[end()]] calls are not properly nested */ public static function end() From b6cc8c0066aa926c6428d7ad39242a86855ea831 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 18 Nov 2013 20:38:04 -0500 Subject: [PATCH 08/35] Fixes #1149: Filter out already included javascript files requested via ajax. --- framework/yii/assets/yii.js | 112 +++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/framework/yii/assets/yii.js b/framework/yii/assets/yii.js index add3a02..dc1d859 100644 --- a/framework/yii/assets/yii.js +++ b/framework/yii/assets/yii.js @@ -44,6 +44,11 @@ yii = (function ($) { var pub = { /** + * List of scripts that can be loaded multiple times via AJAX requests. Each script can be represented + * as either an absolute URL or a relative one. + */ + reloadableScripts: [], + /** * The selector for clickable elements that need to support confirmation and form submission. */ clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]', @@ -161,46 +166,79 @@ yii = (function ($) { }, init: function () { - var $document = $(document); + initCsrfHandler(); + initRedirectHandler(); + initScriptFilter(); + initDataMethods(); + } + }; - // automatically send CSRF token for all AJAX requests - $.ajaxPrefilter(function (options, originalOptions, xhr) { - if (!options.crossDomain && pub.getCsrfVar()) { - xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); + function initRedirectHandler() { + // handle AJAX redirection + $(document).ajaxComplete(function (event, xhr, settings) { + var url = xhr.getResponseHeader('X-Redirect'); + if (url) { + window.location = url; + } + }); + } + + function initCsrfHandler() { + // automatically send CSRF token for all AJAX requests + $.ajaxPrefilter(function (options, originalOptions, xhr) { + if (!options.crossDomain && pub.getCsrfVar()) { + xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); + } + }); + } + + function initDataMethods() { + var $document = $(document); + // handle data-confirm and data-method for clickable elements + $document.on('click.yii', pub.clickableSelector, function (event) { + var $this = $(this); + if (pub.allowAction($this)) { + return pub.handleAction($this); + } else { + event.stopImmediatePropagation(); + return false; + } + }); + + // handle data-confirm and data-method for changeable elements + $document.on('change.yii', pub.changeableSelector, function (event) { + var $this = $(this); + if (pub.allowAction($this)) { + return pub.handleAction($this); + } else { + event.stopImmediatePropagation(); + return false; + } + }); + } + + function initScriptFilter() { + var hostInfo = location.protocol + '//' + location.host; + var loadedScripts = $('script').filter(function () { + return this.src; + }).map(function () { + return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; + }).toArray(); + $.ajaxPrefilter('script', function (options, originalOptions, xhr) { + var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; + if (loadedScripts.indexOf(url) < 0) { + loadedScripts.push(url); + } else { + var found = pub.reloadableScripts.map(function () { + return this.charAt(0) === '/' ? hostInfo + this : this; + }).indexOf(url) >= 0; + if (!found) { + xhr.abort(); } - }); + } + }); + } - // handle AJAX redirection - $document.ajaxComplete(function (event, xhr, settings) { - var url = xhr.getResponseHeader('X-Redirect'); - if (url) { - window.location = url; - } - }); - - // handle data-confirm and data-method for clickable elements - $document.on('click.yii', pub.clickableSelector, function (event) { - var $this = $(this); - if (pub.allowAction($this)) { - return pub.handleAction($this); - } else { - event.stopImmediatePropagation(); - return false; - } - }); - - // handle data-confirm and data-method for changeable elements - $document.on('change.yii', pub.changeableSelector, function (event) { - var $this = $(this); - if (pub.allowAction($this)) { - return pub.handleAction($this); - } else { - event.stopImmediatePropagation(); - return false; - } - }); - } - }; return pub; })(jQuery); From a69fa1bfedad85982b7ee1ee5109e47719d802c7 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 18 Nov 2013 20:52:28 -0500 Subject: [PATCH 09/35] Do not render debug toolbar in ajax request. --- extensions/debug/Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/debug/Module.php b/extensions/debug/Module.php index b315c6c..ae707da 100644 --- a/extensions/debug/Module.php +++ b/extensions/debug/Module.php @@ -85,7 +85,7 @@ class Module extends \yii\base\Module public function renderToolbar($event) { - if (!$this->checkAccess()) { + if (!$this->checkAccess() || Yii::$app->getRequest()->getIsAjax()) { return; } $url = Yii::$app->getUrlManager()->createUrl($this->id . '/default/toolbar', [ From cffb55a2604c102fde7b0249d2b1725e438b706c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 18 Nov 2013 22:52:30 -0500 Subject: [PATCH 10/35] Fixes #1227: help command displays invalid module command list --- framework/yii/console/controllers/HelpController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/console/controllers/HelpController.php b/framework/yii/console/controllers/HelpController.php index 90e810f..eee1923 100644 --- a/framework/yii/console/controllers/HelpController.php +++ b/framework/yii/console/controllers/HelpController.php @@ -124,7 +124,7 @@ class HelpController extends Controller continue; } foreach ($this->getModuleCommands($child) as $command) { - $commands[] = $prefix . $id . '/' . $command; + $commands[] = $command; } } From e36867163693268831364b04e98b0426aaa6308e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 19 Nov 2013 09:43:05 +0100 Subject: [PATCH 11/35] changed magic property to getter call in Pagination issue #1228 --- framework/yii/data/Pagination.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/data/Pagination.php b/framework/yii/data/Pagination.php index dc75294..6a85dd2 100644 --- a/framework/yii/data/Pagination.php +++ b/framework/yii/data/Pagination.php @@ -182,7 +182,7 @@ class Pagination extends Object } else { unset($params[$this->pageVar]); } - $route = $this->route === null ? Yii::$app->controller->route : $this->route; + $route = $this->route === null ? Yii::$app->controller->getRoute() : $this->route; return Yii::$app->getUrlManager()->createUrl($route, $params); } From 4d54319e352bb0f7fbd447f5800006b27c87ffe8 Mon Sep 17 00:00:00 2001 From: marsuboss Date: Tue, 19 Nov 2013 10:56:47 +0100 Subject: [PATCH 12/35] Duplicate --- apps/basic/requirements.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/basic/requirements.php b/apps/basic/requirements.php index 139284f..47bdf37 100644 --- a/apps/basic/requirements.php +++ b/apps/basic/requirements.php @@ -59,7 +59,7 @@ $requirements = [ [ 'name' => 'APC extension', 'mandatory' => false, - 'condition' => extension_loaded('apc') || extension_loaded('apc'), + 'condition' => extension_loaded('apc'), 'by' => 'CApcCache', ], // Additional PHP extensions : From 11727d52bd8a5948e1ac52aeda3ce49e40a276bc Mon Sep 17 00:00:00 2001 From: marsuboss Date: Tue, 19 Nov 2013 11:37:43 +0100 Subject: [PATCH 13/35] Duplicate --- apps/advanced/requirements.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/advanced/requirements.php b/apps/advanced/requirements.php index 139284f..47bdf37 100644 --- a/apps/advanced/requirements.php +++ b/apps/advanced/requirements.php @@ -59,7 +59,7 @@ $requirements = [ [ 'name' => 'APC extension', 'mandatory' => false, - 'condition' => extension_loaded('apc') || extension_loaded('apc'), + 'condition' => extension_loaded('apc'), 'by' => 'CApcCache', ], // Additional PHP extensions : From fbfa18e6281e914ff9d9cbbd0805d6d72ae70ebb Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 19 Nov 2013 12:28:00 +0100 Subject: [PATCH 14/35] fixed requirement checker for intl PECL fixes #1230 --- framework/yii/requirements/YiiRequirementChecker.php | 3 +++ framework/yii/requirements/requirements.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/framework/yii/requirements/YiiRequirementChecker.php b/framework/yii/requirements/YiiRequirementChecker.php index c8ad45d..586cdce 100644 --- a/framework/yii/requirements/YiiRequirementChecker.php +++ b/framework/yii/requirements/YiiRequirementChecker.php @@ -178,6 +178,9 @@ class YiiRequirementChecker if (empty($extensionVersion)) { return false; } + if (strncasecmp($extensionVersion, 'PECL-', 5) == 0) { + $extensionVersion = substr($extensionVersion, 5); + } return version_compare($extensionVersion, $version, $compare); } diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php index 34b556e..916d6aa 100644 --- a/framework/yii/requirements/requirements.php +++ b/framework/yii/requirements/requirements.php @@ -44,7 +44,7 @@ return array( 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='), 'by' => 'Internationalization support', 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use advanced parameters formatting - in \Yii::t(), IDN-feature of + in Yii::t(), IDN-feature of EmailValidator or UrlValidator or the yii\i18n\Formatter class.' ), ); From e09cc16c49e0a62b3a514d7c2191e723e7e03935 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 19 Nov 2013 17:24:11 +0400 Subject: [PATCH 15/35] ApcCache is now compatible with APCu --- framework/yii/caching/ApcCache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/yii/caching/ApcCache.php b/framework/yii/caching/ApcCache.php index 688c3f1..8a0d207 100644 --- a/framework/yii/caching/ApcCache.php +++ b/framework/yii/caching/ApcCache.php @@ -124,6 +124,10 @@ class ApcCache extends Cache */ protected function flushValues() { - return apc_clear_cache('user'); + if (extension_loaded('apcu')) { + return apc_clear_cache(); + } else { + return apc_clear_cache('user'); + } } } From 9efe446545b4ace1dd080d0063b362d7a7c1afa2 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 10:20:07 -0500 Subject: [PATCH 16/35] Fixes #1236: removed Sort::ASC and DESC --- framework/yii/data/ActiveDataProvider.php | 4 +- framework/yii/data/Sort.php | 56 ++++++++++-------------- tests/unit/framework/data/SortTest.php | 42 +++++++++--------- tests/unit/framework/helpers/ArrayHelperTest.php | 4 +- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php index 89a7cf6..e9d5403 100644 --- a/framework/yii/data/ActiveDataProvider.php +++ b/framework/yii/data/ActiveDataProvider.php @@ -172,8 +172,8 @@ class ActiveDataProvider extends BaseDataProvider $model = new $this->query->modelClass; foreach ($model->attributes() as $attribute) { $sort->attributes[$attribute] = [ - 'asc' => [$attribute => Sort::ASC], - 'desc' => [$attribute => Sort::DESC], + 'asc' => [$attribute => SORT_ASC], + 'desc' => [$attribute => SORT_DESC], 'label' => $model->getAttributeLabel($attribute), ]; } diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php index 156b447..97a8649 100644 --- a/framework/yii/data/Sort.php +++ b/framework/yii/data/Sort.php @@ -29,9 +29,9 @@ use yii\helpers\Inflector; * 'attributes' => [ * 'age', * 'name' => [ - * 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - * 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], - * 'default' => Sort::DESC, + * 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + * 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + * 'default' => SORT_DESC, * 'label' => 'Name', * ], * ], @@ -66,7 +66,7 @@ use yii\helpers\Inflector; * that can lead to pages with the data sorted by the corresponding attributes. * * @property array $attributeOrders Sort directions indexed by attribute names. Sort direction can be either - * [[Sort::ASC]] for ascending order or [[Sort::DESC]] for descending order. This property is read-only. + * `SORT_ASC` for ascending order or `SORT_DESC` for descending order. This property is read-only. * @property array $orders The columns (keys) and their corresponding sort directions (values). This can be * passed to [[\yii\db\Query::orderBy()]] to construct a DB query. This property is read-only. * @@ -76,16 +76,6 @@ use yii\helpers\Inflector; class Sort extends Object { /** - * Sort ascending - */ - const ASC = false; - - /** - * Sort descending - */ - const DESC = true; - - /** * @var boolean whether the sorting can be applied to multiple attributes simultaneously. * Defaults to false, which means each time the data can only be sorted by one attribute. */ @@ -99,9 +89,9 @@ class Sort extends Object * [ * 'age', * 'name' => [ - * 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - * 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], - * 'default' => Sort::DESC, + * 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + * 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + * 'default' => SORT_DESC, * 'label' => 'Name', * ], * ] @@ -112,9 +102,9 @@ class Sort extends Object * * ~~~ * 'age' => [ - * 'asc' => ['age' => Sort::ASC], - * 'desc' => ['age' => Sort::DESC], - * 'default' => Sort::ASC, + * 'asc' => ['age' => SORT_ASC], + * 'desc' => ['age' => SORT_DESC], + * 'default' => SORT_ASC, * 'label' => Inflector::camel2words('age'), * ] * ~~~ @@ -153,8 +143,8 @@ class Sort extends Object * * ~~~ * [ - * 'name' => Sort::ASC, - * 'create_time' => Sort::DESC, + * 'name' => SORT_ASC, + * 'create_time' => SORT_DESC, * ] * ~~~ * @@ -199,13 +189,13 @@ class Sort extends Object foreach ($this->attributes as $name => $attribute) { if (!is_array($attribute)) { $attributes[$attribute] = [ - 'asc' => [$attribute => self::ASC], - 'desc' => [$attribute => self::DESC], + 'asc' => [$attribute => SORT_ASC], + 'desc' => [$attribute => SORT_DESC], ]; } elseif (!isset($attribute['asc'], $attribute['desc'])) { $attributes[$name] = array_merge([ - 'asc' => [$name => self::ASC], - 'desc' => [$name => self::DESC], + 'asc' => [$name => SORT_ASC], + 'desc' => [$name => SORT_DESC], ], $attribute); } else { $attributes[$name] = $attribute; @@ -226,7 +216,7 @@ class Sort extends Object $orders = []; foreach ($attributeOrders as $attribute => $direction) { $definition = $this->attributes[$attribute]; - $columns = $definition[$direction === self::ASC ? 'asc' : 'desc']; + $columns = $definition[$direction === SORT_ASC ? 'asc' : 'desc']; foreach ($columns as $name => $dir) { $orders[$name] = $dir; } @@ -243,8 +233,8 @@ class Sort extends Object * Returns the currently requested sort information. * @param boolean $recalculate whether to recalculate the sort directions * @return array sort directions indexed by attribute names. - * Sort direction can be either [[Sort::ASC]] for ascending order or - * [[Sort::DESC]] for descending order. + * Sort direction can be either `SORT_ASC` for ascending order or + * `SORT_DESC` for descending order. */ public function getAttributeOrders($recalculate = false) { @@ -262,7 +252,7 @@ class Sort extends Object } if (isset($this->attributes[$attribute])) { - $this->_attributeOrders[$attribute] = $descending; + $this->_attributeOrders[$attribute] = $descending ? SORT_DESC : SORT_ASC; if (!$this->enableMultiSort) { return $this->_attributeOrders; } @@ -279,8 +269,8 @@ class Sort extends Object /** * Returns the sort direction of the specified attribute in the current request. * @param string $attribute the attribute name - * @return boolean|null Sort direction of the attribute. Can be either [[Sort::ASC]] - * for ascending order or [[Sort::DESC]] for descending order. Null is returned + * @return boolean|null Sort direction of the attribute. Can be either `SORT_ASC` + * for ascending order or `SORT_DESC` for descending order. Null is returned * if the attribute is invalid or does not need to be sorted. */ public function getAttributeOrder($attribute) @@ -305,7 +295,7 @@ class Sort extends Object public function link($attribute, $options = []) { if (($direction = $this->getAttributeOrder($attribute)) !== null) { - $class = $direction ? 'desc' : 'asc'; + $class = $direction === SORT_DESC ? 'desc' : 'asc'; if (isset($options['class'])) { $options['class'] .= ' ' . $class; } else { diff --git a/tests/unit/framework/data/SortTest.php b/tests/unit/framework/data/SortTest.php index abe0031..dca2fcb 100644 --- a/tests/unit/framework/data/SortTest.php +++ b/tests/unit/framework/data/SortTest.php @@ -25,8 +25,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ @@ -37,14 +37,14 @@ class SortTest extends TestCase $orders = $sort->getOrders(); $this->assertEquals(3, count($orders)); - $this->assertEquals(Sort::ASC, $orders['age']); - $this->assertEquals(Sort::DESC, $orders['first_name']); - $this->assertEquals(Sort::DESC, $orders['last_name']); + $this->assertEquals(SORT_ASC, $orders['age']); + $this->assertEquals(SORT_DESC, $orders['first_name']); + $this->assertEquals(SORT_DESC, $orders['last_name']); $sort->enableMultiSort = false; $orders = $sort->getOrders(true); $this->assertEquals(1, count($orders)); - $this->assertEquals(Sort::ASC, $orders['age']); + $this->assertEquals(SORT_ASC, $orders['age']); } public function testGetAttributeOrders() @@ -53,8 +53,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ @@ -65,13 +65,13 @@ class SortTest extends TestCase $orders = $sort->getAttributeOrders(); $this->assertEquals(2, count($orders)); - $this->assertEquals(Sort::ASC, $orders['age']); - $this->assertEquals(Sort::DESC, $orders['name']); + $this->assertEquals(SORT_ASC, $orders['age']); + $this->assertEquals(SORT_DESC, $orders['name']); $sort->enableMultiSort = false; $orders = $sort->getAttributeOrders(true); $this->assertEquals(1, count($orders)); - $this->assertEquals(Sort::ASC, $orders['age']); + $this->assertEquals(SORT_ASC, $orders['age']); } public function testGetAttributeOrder() @@ -80,8 +80,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ @@ -90,8 +90,8 @@ class SortTest extends TestCase 'enableMultiSort' => true, ]); - $this->assertEquals(Sort::ASC, $sort->getAttributeOrder('age')); - $this->assertEquals(Sort::DESC, $sort->getAttributeOrder('name')); + $this->assertEquals(SORT_ASC, $sort->getAttributeOrder('age')); + $this->assertEquals(SORT_DESC, $sort->getAttributeOrder('name')); $this->assertNull($sort->getAttributeOrder('xyz')); } @@ -101,8 +101,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ @@ -127,8 +127,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ @@ -155,8 +155,8 @@ class SortTest extends TestCase 'attributes' => [ 'age', 'name' => [ - 'asc' => ['first_name' => Sort::ASC, 'last_name' => Sort::ASC], - 'desc' => ['first_name' => Sort::DESC, 'last_name' => Sort::DESC], + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], ], ], 'params' => [ diff --git a/tests/unit/framework/helpers/ArrayHelperTest.php b/tests/unit/framework/helpers/ArrayHelperTest.php index e566cec..11c9f8e 100644 --- a/tests/unit/framework/helpers/ArrayHelperTest.php +++ b/tests/unit/framework/helpers/ArrayHelperTest.php @@ -147,7 +147,7 @@ class ArrayHelperTest extends TestCase // single key $sort = new Sort([ 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => Sort::ASC], + 'defaultOrder' => ['name' => SORT_ASC], ]); $orders = $sort->getOrders(); @@ -164,7 +164,7 @@ class ArrayHelperTest extends TestCase // multiple keys $sort = new Sort([ 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => Sort::ASC, 'age' => Sort::DESC], + 'defaultOrder' => ['name' => SORT_ASC, 'age' => SORT_DESC], ]); $orders = $sort->getOrders(); From dbf35253b7b48071eb0c290e26d230c041849a73 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 10:25:07 -0500 Subject: [PATCH 17/35] Fixes #1237. --- framework/yii/db/pgsql/Schema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index 4925984..302843b 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -49,6 +49,7 @@ class Schema extends \yii\db\Schema 'inet' => self::TYPE_STRING, 'smallint' => self::TYPE_SMALLINT, 'int4' => self::TYPE_INTEGER, + 'int8' => self::TYPE_BIGINT, 'integer' => self::TYPE_INTEGER, 'bigint' => self::TYPE_BIGINT, 'interval' => self::TYPE_STRING, From 0833fe2e403f24589adcae5d46f65043bacb20a4 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 10:30:28 -0500 Subject: [PATCH 18/35] Fixed test break. --- framework/yii/data/Sort.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php index 97a8649..6630cfd 100644 --- a/framework/yii/data/Sort.php +++ b/framework/yii/data/Sort.php @@ -355,10 +355,10 @@ class Sort extends Object $definition = $this->attributes[$attribute]; $directions = $this->getAttributeOrders(); if (isset($directions[$attribute])) { - $descending = !$directions[$attribute]; + $descending = $directions[$attribute] === SORT_DESC; unset($directions[$attribute]); } else { - $descending = !empty($definition['default']); + $descending = isset($definition['default']) && $definition['default'] === SORT_DESC; } if ($this->enableMultiSort) { From dd97c002a6866274d227f37ad421fd6aad2837ac Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 10:43:30 -0500 Subject: [PATCH 19/35] fixed test break. --- framework/yii/data/Sort.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php index 6630cfd..9b73cc0 100644 --- a/framework/yii/data/Sort.php +++ b/framework/yii/data/Sort.php @@ -355,7 +355,7 @@ class Sort extends Object $definition = $this->attributes[$attribute]; $directions = $this->getAttributeOrders(); if (isset($directions[$attribute])) { - $descending = $directions[$attribute] === SORT_DESC; + $descending = $directions[$attribute] !== SORT_DESC; unset($directions[$attribute]); } else { $descending = isset($definition['default']) && $definition['default'] === SORT_DESC; From 726a305b7e658fe68db1319af279bd24c75e7444 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 10:57:59 -0500 Subject: [PATCH 20/35] fixed test break. --- framework/yii/data/Sort.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php index 9b73cc0..7612641 100644 --- a/framework/yii/data/Sort.php +++ b/framework/yii/data/Sort.php @@ -355,21 +355,21 @@ class Sort extends Object $definition = $this->attributes[$attribute]; $directions = $this->getAttributeOrders(); if (isset($directions[$attribute])) { - $descending = $directions[$attribute] !== SORT_DESC; + $direction = $directions[$attribute] === SORT_DESC ? SORT_ASC : SORT_DESC; unset($directions[$attribute]); } else { - $descending = isset($definition['default']) && $definition['default'] === SORT_DESC; + $direction = isset($definition['default']) ? $definition['default'] : SORT_ASC; } if ($this->enableMultiSort) { - $directions = array_merge([$attribute => $descending], $directions); + $directions = array_merge([$attribute => $direction], $directions); } else { - $directions = [$attribute => $descending]; + $directions = [$attribute => $direction]; } $sorts = []; - foreach ($directions as $attribute => $descending) { - $sorts[] = $descending ? $attribute . $this->separators[1] . $this->descTag : $attribute; + foreach ($directions as $attribute => $direction) { + $sorts[] = $direction === SORT_DESC ? $attribute . $this->separators[1] . $this->descTag : $attribute; } return implode($this->separators[0], $sorts); } From 3959b8dbdae1dd78f96cf2c0741bcb585e8f79ed Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 11:33:25 -0500 Subject: [PATCH 21/35] Fixed test break. --- framework/yii/helpers/BaseArrayHelper.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php index a5382e7..9ac5faa 100644 --- a/framework/yii/helpers/BaseArrayHelper.php +++ b/framework/yii/helpers/BaseArrayHelper.php @@ -333,8 +333,8 @@ class BaseArrayHelper * elements, a property name of the objects, or an anonymous function returning the values for comparison * purpose. The anonymous function signature should be: `function($item)`. * To sort by multiple keys, provide an array of keys here. - * @param boolean|array $descending whether to sort in descending or ascending order. When - * sorting by multiple keys with different descending orders, use an array of descending flags. + * @param integer|array $direction the sorting direction. It can be either `SORT_ASC` or `SORT_DESC`. + * When sorting by multiple keys with different sorting directions, use an array of sorting directions. * @param integer|array $sortFlag the PHP sort flag. Valid values include * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, `SORT_LOCALE_STRING`, `SORT_NATURAL` and `SORT_FLAG_CASE`. * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php) @@ -345,16 +345,16 @@ class BaseArrayHelper * @throws InvalidParamException if the $descending or $sortFlag parameters do not have * correct number of elements as that of $key. */ - public static function multisort(&$array, $key, $descending = false, $sortFlag = SORT_REGULAR, $caseSensitive = true) + public static function multisort(&$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR, $caseSensitive = true) { $keys = is_array($key) ? $key : [$key]; if (empty($keys) || empty($array)) { return; } $n = count($keys); - if (is_scalar($descending)) { - $descending = array_fill(0, $n, $descending); - } elseif (count($descending) !== $n) { + if (is_scalar($direction)) { + $direction = array_fill(0, $n, $direction); + } elseif (count($direction) !== $n) { throw new InvalidParamException('The length of $descending parameter must be the same as that of $keys.'); } if (is_scalar($sortFlag)) { @@ -377,7 +377,7 @@ class BaseArrayHelper } else { $args[] = static::getColumn($array, $key); } - $args[] = $descending[$i] ? SORT_DESC : SORT_ASC; + $args[] = $direction; $args[] = $flag; } $args[] = &$array; From 719e3bca196be2725763e916b409e0e679f633cb Mon Sep 17 00:00:00 2001 From: Alex-Code Date: Tue, 19 Nov 2013 16:41:32 +0000 Subject: [PATCH 22/35] Update yii.js ```map``` and ```indexOf``` on arrays were only added in IE9. Changed to make use of jQuery's equivalents. --- framework/yii/assets/yii.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/framework/yii/assets/yii.js b/framework/yii/assets/yii.js index dc1d859..b9f2cdd 100644 --- a/framework/yii/assets/yii.js +++ b/framework/yii/assets/yii.js @@ -219,19 +219,17 @@ yii = (function ($) { function initScriptFilter() { var hostInfo = location.protocol + '//' + location.host; - var loadedScripts = $('script').filter(function () { - return this.src; - }).map(function () { + var loadedScripts = $('script[src]').map(function () { return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; }).toArray(); $.ajaxPrefilter('script', function (options, originalOptions, xhr) { var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; - if (loadedScripts.indexOf(url) < 0) { + if ($.inArray(url, loadedScripts) === -1) { loadedScripts.push(url); } else { - var found = pub.reloadableScripts.map(function () { - return this.charAt(0) === '/' ? hostInfo + this : this; - }).indexOf(url) >= 0; + var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) { + return script.charAt(0) === '/' ? hostInfo + script : script; + })) !== -1; if (!found) { xhr.abort(); } From 7d9639ea4976638e4e0aa224f4500dfbb3f6c5fb Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 11:47:09 -0500 Subject: [PATCH 23/35] Fixed test break. --- framework/yii/helpers/BaseArrayHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php index 9ac5faa..9b51c63 100644 --- a/framework/yii/helpers/BaseArrayHelper.php +++ b/framework/yii/helpers/BaseArrayHelper.php @@ -377,7 +377,7 @@ class BaseArrayHelper } else { $args[] = static::getColumn($array, $key); } - $args[] = $direction; + $args[] = $direction[$i]; $args[] = $flag; } $args[] = &$array; From 53457a0a3f323a8452c9fafbbd87e5f8566f043c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 14:10:00 -0500 Subject: [PATCH 24/35] Simplified ArrayHelper::multisort(). --- framework/yii/helpers/BaseArrayHelper.php | 18 ++---------------- tests/unit/framework/helpers/ArrayHelperTest.php | 4 ++-- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php index 9b51c63..da63238 100644 --- a/framework/yii/helpers/BaseArrayHelper.php +++ b/framework/yii/helpers/BaseArrayHelper.php @@ -339,13 +339,10 @@ class BaseArrayHelper * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, `SORT_LOCALE_STRING`, `SORT_NATURAL` and `SORT_FLAG_CASE`. * 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 $descending or $sortFlag parameters do not have * correct number of elements as that of $key. */ - public static function multisort(&$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR, $caseSensitive = true) + public static function multisort(&$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR) { $keys = is_array($key) ? $key : [$key]; if (empty($keys) || empty($array)) { @@ -362,21 +359,10 @@ class BaseArrayHelper } elseif (count($sortFlag) !== $n) { 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 = []; foreach ($keys as $i => $key) { $flag = $sortFlag[$i]; - $cs = $caseSensitive[$i]; - if (!$cs && ($flag === SORT_STRING)) { - $flag = $flag | SORT_FLAG_CASE; - $args[] = static::getColumn($array, $key); - } else { - $args[] = static::getColumn($array, $key); - } + $args[] = static::getColumn($array, $key); $args[] = $direction[$i]; $args[] = $flag; } diff --git a/tests/unit/framework/helpers/ArrayHelperTest.php b/tests/unit/framework/helpers/ArrayHelperTest.php index 11c9f8e..6aa2a45 100644 --- a/tests/unit/framework/helpers/ArrayHelperTest.php +++ b/tests/unit/framework/helpers/ArrayHelperTest.php @@ -129,13 +129,13 @@ class ArrayHelperTest extends TestCase ['name' => 'A', 'age' => 1], ]; - ArrayHelper::multisort($array, ['name', 'age'], false, [SORT_STRING, SORT_REGULAR]); + ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING, SORT_REGULAR]); $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); $this->assertEquals(['name' => 'B', 'age' => 4], $array[1]); $this->assertEquals(['name' => 'a', 'age' => 3], $array[2]); $this->assertEquals(['name' => 'b', 'age' => 2], $array[3]); - ArrayHelper::multisort($array, ['name', 'age'], false, [SORT_STRING, SORT_REGULAR], false); + ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING | SORT_FLAG_CASE, SORT_REGULAR]); $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); $this->assertEquals(['name' => 'a', 'age' => 3], $array[1]); $this->assertEquals(['name' => 'b', 'age' => 2], $array[2]); From d2e5f2c5074500e22f7845420b168301e7459e6f Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 16:33:52 -0500 Subject: [PATCH 25/35] Fixes #1234: use dash instead of underscore to separate language and country in locale id. --- apps/advanced/backend/views/layouts/main.php | 2 +- apps/advanced/frontend/views/layouts/main.php | 2 +- apps/basic/views/layouts/main.php | 2 +- docs/guide/i18n.md | 2 +- docs/guide/view.md | 2 +- extensions/debug/panels/DbPanel.php | 2 +- framework/yii/BaseYii.php | 2 +- framework/yii/base/Application.php | 4 ++-- framework/yii/i18n/I18N.php | 8 ++++---- framework/yii/i18n/MissingTranslationEvent.php | 2 +- framework/yii/messages/config.php | 2 +- framework/yii/web/Request.php | 8 ++++---- tests/unit/data/i18n/messages/de-DE/test.php | 9 ++++++++ tests/unit/data/i18n/messages/de_DE/test.php | 9 -------- tests/unit/data/i18n/messages/en-US/test.php | 7 +++++++ tests/unit/data/i18n/messages/en_US/test.php | 7 ------- .../i18n/FallbackMessageFormatterTest.php | 8 ++++---- tests/unit/framework/i18n/FormatterTest.php | 2 +- tests/unit/framework/i18n/I18NTest.php | 24 +++++++++++----------- tests/unit/framework/i18n/MessageFormatterTest.php | 14 ++++++------- 20 files changed, 59 insertions(+), 59 deletions(-) create mode 100644 tests/unit/data/i18n/messages/de-DE/test.php delete mode 100644 tests/unit/data/i18n/messages/de_DE/test.php create mode 100644 tests/unit/data/i18n/messages/en-US/test.php delete mode 100644 tests/unit/data/i18n/messages/en_US/test.php diff --git a/apps/advanced/backend/views/layouts/main.php b/apps/advanced/backend/views/layouts/main.php index 9f0280d..fdffc26 100644 --- a/apps/advanced/backend/views/layouts/main.php +++ b/apps/advanced/backend/views/layouts/main.php @@ -13,7 +13,7 @@ AppAsset::register($this); ?> beginPage(); ?> - + <?= Html::encode($this->title) ?> diff --git a/apps/advanced/frontend/views/layouts/main.php b/apps/advanced/frontend/views/layouts/main.php index 7b2ce6f..febcc5a 100644 --- a/apps/advanced/frontend/views/layouts/main.php +++ b/apps/advanced/frontend/views/layouts/main.php @@ -14,7 +14,7 @@ AppAsset::register($this); ?> beginPage(); ?> - + <?= Html::encode($this->title) ?> diff --git a/apps/basic/views/layouts/main.php b/apps/basic/views/layouts/main.php index 8489e9c..04acdfb 100644 --- a/apps/basic/views/layouts/main.php +++ b/apps/basic/views/layouts/main.php @@ -13,7 +13,7 @@ AppAsset::register($this); ?> beginPage(); ?> - + <?= Html::encode($this->title) ?> diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md index 6524801..477de0a 100644 --- a/docs/guide/i18n.md +++ b/docs/guide/i18n.md @@ -57,7 +57,7 @@ Yii tries to load approprite translation from one of the message sources defined 'app*' => [ 'class' => 'yii\i18n\PhpMessageSource', //'basePath' => '@app/messages', - //'sourceLanguage' => 'en_US', + //'sourceLanguage' => 'en-US', 'fileMap' => [ 'app' => 'app.php', 'app/error' => 'error.php', diff --git a/docs/guide/view.md b/docs/guide/view.md index 5951a30..ae86809 100644 --- a/docs/guide/view.md +++ b/docs/guide/view.md @@ -256,7 +256,7 @@ use yii\helpers\Html; ?> beginPage(); ?> - + <?= Html::encode($this->title) ?> diff --git a/extensions/debug/panels/DbPanel.php b/extensions/debug/panels/DbPanel.php index e24da93..a487dd4 100644 --- a/extensions/debug/panels/DbPanel.php +++ b/extensions/debug/panels/DbPanel.php @@ -48,7 +48,7 @@ EOD; public function getDetail() { $timings = $this->calculateTimings(); - ArrayHelper::multisort($timings, 3, true); + ArrayHelper::multisort($timings, 3, SORT_DESC); $rows = []; foreach ($timings as $timing) { $duration = sprintf('%.1f ms', $timing[3] * 1000); diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index 357a1e7..f11df7f 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -498,7 +498,7 @@ class BaseYii * @param string $category the message category. * @param string $message the message to be translated. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en_US`, `en`). If this is null, the current + * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current * [[\yii\base\Application::language|application language]] will be used. * @return string the translated message. */ diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index 0af586c..dc363f1 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -79,13 +79,13 @@ abstract class Application extends Module * @var string the language that is meant to be used for end users. * @see sourceLanguage */ - public $language = 'en_US'; + public $language = 'en-US'; /** * @var string the language that the application is written in. This mainly refers to * the language that the messages and view files are written in. * @see language */ - public $sourceLanguage = 'en_US'; + public $sourceLanguage = 'en-US'; /** * @var Controller the currently active controller instance */ diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 5575621..c59a6d2 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -53,14 +53,14 @@ class I18N extends Component if (!isset($this->translations['yii'])) { $this->translations['yii'] = [ 'class' => 'yii\i18n\PhpMessageSource', - 'sourceLanguage' => 'en_US', + 'sourceLanguage' => 'en-US', 'basePath' => '@yii/messages', ]; } if (!isset($this->translations['app'])) { $this->translations['app'] = [ 'class' => 'yii\i18n\PhpMessageSource', - 'sourceLanguage' => 'en_US', + 'sourceLanguage' => 'en-US', 'basePath' => '@app/messages', ]; } @@ -75,7 +75,7 @@ class I18N extends Component * @param string $category the message category. * @param string $message the message to be translated. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en_US`, `en`). + * @param string $language the language code (e.g. `en-US`, `en`). * @return string the translated and formatted message. */ public function translate($category, $message, $params, $language) @@ -89,7 +89,7 @@ class I18N extends Component * * @param string $message the message to be formatted. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en_US`, `en`). + * @param string $language the language code (e.g. `en-US`, `en`). * @return string the formatted message. */ public function format($message, $params, $language) diff --git a/framework/yii/i18n/MissingTranslationEvent.php b/framework/yii/i18n/MissingTranslationEvent.php index 9ac337a..5c8ffd3 100644 --- a/framework/yii/i18n/MissingTranslationEvent.php +++ b/framework/yii/i18n/MissingTranslationEvent.php @@ -27,7 +27,7 @@ class MissingTranslationEvent extends Event */ public $category; /** - * @var string the language ID (e.g. en_US) that the message is to be translated to + * @var string the language ID (e.g. en-US) that the message is to be translated to */ public $language; } diff --git a/framework/yii/messages/config.php b/framework/yii/messages/config.php index 0f724ba..b707abb 100644 --- a/framework/yii/messages/config.php +++ b/framework/yii/messages/config.php @@ -6,7 +6,7 @@ return [ // string, required, root directory containing message translations. 'messagePath' => __DIR__, // array, required, list of language codes that the extracted messages - // should be translated to. For example, ['zh_cn', 'de']. + // should be translated to. For example, ['zh-CN', 'de']. 'languages' => ['de'], // string, the name of the function for translating messages. // Defaults to 'Yii::t'. This is used as a mark to find the messages to be diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index 0b49730..7a7cedf 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -908,11 +908,11 @@ class Request extends \yii\base\Request return isset($acceptedLanguages[0]) ? $acceptedLanguages[0] : null; } foreach ($acceptedLanguages as $acceptedLanguage) { - $acceptedLanguage = str_replace('-', '_', strtolower($acceptedLanguage)); + $acceptedLanguage = str_replace('_', '-', strtolower($acceptedLanguage)); foreach ($languages as $language) { - $language = str_replace('-', '_', strtolower($language)); - // en_us==en_us, en==en_us, en_us==en - if ($language === $acceptedLanguage || strpos($acceptedLanguage, $language . '_') === 0 || strpos($language, $acceptedLanguage . '_') === 0) { + $language = str_replace('_', '-', strtolower($language)); + // en-us==en-us, en==en-us, en-us==en + if ($language === $acceptedLanguage || strpos($acceptedLanguage, $language . '-') === 0 || strpos($language, $acceptedLanguage . '-') === 0) { return $language; } } diff --git a/tests/unit/data/i18n/messages/de-DE/test.php b/tests/unit/data/i18n/messages/de-DE/test.php new file mode 100644 index 0000000..d8c5290 --- /dev/null +++ b/tests/unit/data/i18n/messages/de-DE/test.php @@ -0,0 +1,9 @@ + 'Der Hund rennt schnell.', + 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', + 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', +]; \ No newline at end of file diff --git a/tests/unit/data/i18n/messages/de_DE/test.php b/tests/unit/data/i18n/messages/de_DE/test.php deleted file mode 100644 index d8c5290..0000000 --- a/tests/unit/data/i18n/messages/de_DE/test.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Der Hund rennt schnell.', - 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', - 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', -]; \ No newline at end of file diff --git a/tests/unit/data/i18n/messages/en-US/test.php b/tests/unit/data/i18n/messages/en-US/test.php new file mode 100644 index 0000000..83342b0 --- /dev/null +++ b/tests/unit/data/i18n/messages/en-US/test.php @@ -0,0 +1,7 @@ + 'Der Hund rennt schell.', +]; \ No newline at end of file diff --git a/tests/unit/data/i18n/messages/en_US/test.php b/tests/unit/data/i18n/messages/en_US/test.php deleted file mode 100644 index 83342b0..0000000 --- a/tests/unit/data/i18n/messages/en_US/test.php +++ /dev/null @@ -1,7 +0,0 @@ - 'Der Hund rennt schell.', -]; \ No newline at end of file diff --git a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php index 6aa8a22..bdc4e43 100644 --- a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php +++ b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php @@ -136,7 +136,7 @@ _MSG_ public function testNamedArguments($pattern, $expected, $args) { $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, $args, 'en_US'); + $result = $formatter->fallbackFormat($pattern, $args, 'en-US'); $this->assertEquals($expected, $result, $formatter->getErrorMessage()); } @@ -147,7 +147,7 @@ _MSG_ $formatter = new FallbackMessageFormatter(); $result = $formatter->fallbackFormat('{'.self::SUBJECT.'} is {'.self::N.'}', [ self::N => self::N_VALUE, - ], 'en_US'); + ], 'en-US'); $this->assertEquals($expected, $result); } @@ -157,7 +157,7 @@ _MSG_ $pattern = '{'.self::SUBJECT.'} is '.self::N; $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, [], 'en_US'); + $result = $formatter->fallbackFormat($pattern, [], 'en-US'); $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); } } @@ -168,4 +168,4 @@ class FallbackMessageFormatter extends MessageFormatter { return parent::fallbackFormat($pattern, $args, $locale); } -} \ No newline at end of file +} diff --git a/tests/unit/framework/i18n/FormatterTest.php b/tests/unit/framework/i18n/FormatterTest.php index 622c308..ed5ab33 100644 --- a/tests/unit/framework/i18n/FormatterTest.php +++ b/tests/unit/framework/i18n/FormatterTest.php @@ -29,7 +29,7 @@ class FormatterTest extends TestCase $this->markTestSkipped('intl extension is required.'); } $this->mockApplication(); - $this->formatter = new Formatter(['locale' => 'en_US']); + $this->formatter = new Formatter(['locale' => 'en-US']); } protected function tearDown() diff --git a/tests/unit/framework/i18n/I18NTest.php b/tests/unit/framework/i18n/I18NTest.php index 65d3d11..aa2356b 100644 --- a/tests/unit/framework/i18n/I18NTest.php +++ b/tests/unit/framework/i18n/I18NTest.php @@ -40,16 +40,16 @@ class I18NTest extends TestCase public function testTranslate() { $msg = 'The dog runs fast.'; - $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, [], 'en_US')); - $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, [], 'de_DE')); + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, [], 'en-US')); + $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, [], 'de-DE')); } public function testTranslateParams() { $msg = 'His speed is about {n} km/h.'; $params = ['n' => 42]; - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en_US')); - $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de_DE')); + $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); + $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de-DE')); } public function testTranslateParams2() @@ -62,22 +62,22 @@ class I18NTest extends TestCase 'n' => 42, 'name' => 'DA VINCI', // http://petrix.com/dognames/d.html ]; - $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en_US')); - $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de_DE')); + $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); + $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de-DE')); } public function testSpecialParams() { $msg = 'His speed is about {0} km/h.'; - $this->assertEquals('His speed is about 0 km/h.', $this->i18n->translate('test', $msg, 0, 'en_US')); - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, 42, 'en_US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, null, 'en_US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, [], 'en_US')); + $this->assertEquals('His speed is about 0 km/h.', $this->i18n->translate('test', $msg, 0, 'en-US')); + $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, 42, 'en-US')); + $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, null, 'en-US')); + $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, [], 'en-US')); $msg = 'His name is {name} and he is {age} years old.'; $model = new ParamModel(); - $this->assertEquals('His name is peer and he is 5 years old.', $this->i18n->translate('test', $msg, $model, 'en_US')); + $this->assertEquals('His name is peer and he is 5 years old.', $this->i18n->translate('test', $msg, $model, 'en-US')); } } @@ -85,4 +85,4 @@ class ParamModel extends Model { public $name = 'peer'; public $age = 5; -} \ No newline at end of file +} diff --git a/tests/unit/framework/i18n/MessageFormatterTest.php b/tests/unit/framework/i18n/MessageFormatterTest.php index 7bc8047..1d5d007 100644 --- a/tests/unit/framework/i18n/MessageFormatterTest.php +++ b/tests/unit/framework/i18n/MessageFormatterTest.php @@ -250,7 +250,7 @@ _MSG_ 1 => 123, 2 => 37.073 ], - 'en_US' + 'en-US' ], [ @@ -272,7 +272,7 @@ _MSG_ 'trees' => 123, 'monkeysPerTree' => 37.073 ], - 'en_US' + 'en-US' ], [ @@ -297,14 +297,14 @@ _MSG_ $this->markTestSkipped($skipMessage); } $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, $args, 'en_US'); + $result = $formatter->format($pattern, $args, 'en-US'); $this->assertEquals($expected, $result, $formatter->getErrorMessage()); } /** * @dataProvider parsePatterns */ - public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en_US') + public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en-US') { if (!extension_loaded("intl")) { $this->markTestSkipped("intl not installed. Skipping."); @@ -322,7 +322,7 @@ _MSG_ $formatter = new MessageFormatter(); $result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [ self::N => self::N_VALUE, - ], 'en_US'); + ], 'en-US'); $this->assertEquals($expected, $result, $formatter->getErrorMessage()); } @@ -331,7 +331,7 @@ _MSG_ { $pattern = '{'.self::SUBJECT.'} is '.self::N; $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, [], 'en_US'); + $result = $formatter->format($pattern, [], 'en-US'); $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); } -} \ No newline at end of file +} From f67ddb17f67cc03fd778663746ec92e073e1bde0 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 17:25:05 -0500 Subject: [PATCH 26/35] Fixes #1242: Gii Model generation added dropped table fields in Postgresql --- framework/yii/db/pgsql/Schema.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index 302843b..aa3cdc9 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -242,18 +242,17 @@ SQL; $schemaName = $this->db->quoteValue($table->schemaName); $sql = << 0 + a.attnum > 0 and t.typename != '' and c.relname = {$tableName} and d.nspname = {$schemaName} ORDER BY From 9ef3560f5aec33184b5ad6fd3eedcea6b4d4ece8 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 19 Nov 2013 18:03:52 -0500 Subject: [PATCH 27/35] Fixed test break. --- framework/yii/db/pgsql/Schema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index aa3cdc9..d7885f2 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -288,7 +288,7 @@ FROM LEFT JOIN pg_namespace d ON d.oid = c.relnamespace LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p' WHERE - a.attnum > 0 and t.typename != '' + a.attnum > 0 and t.typname != '' and c.relname = {$tableName} and d.nspname = {$schemaName} ORDER BY From 7450fc1000ff5cbb5a2c2a229a6fed673933d65d Mon Sep 17 00:00:00 2001 From: kumorig Date: Wed, 20 Nov 2013 09:26:51 +0900 Subject: [PATCH 28/35] Small edit for consistency with frontend config. Small edit for consistency with /apps/advanced/backend/config/main.php. Sorry, my OCD kicked in. --- apps/advanced/frontend/config/main.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/advanced/frontend/config/main.php b/apps/advanced/frontend/config/main.php index 49c4e55..e0fd2de 100644 --- a/apps/advanced/frontend/config/main.php +++ b/apps/advanced/frontend/config/main.php @@ -11,12 +11,12 @@ $params = array_merge( return [ 'id' => 'app-frontend', 'basePath' => dirname(__DIR__), - 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', + 'vendorPath' => $rootDir . '/vendor', 'controllerNamespace' => 'frontend\controllers', 'modules' => [ 'gii' => 'yii\gii\Module' ], - 'extensions' => require(__DIR__ . '/../../vendor/yiisoft/extensions.php'), + 'extensions' => require($rootDir . '/vendor/yiisoft/extensions.php'), 'components' => [ 'request' => [ 'enableCsrfValidation' => true, From f5219d24816c8b55aa757d37b7215905f3ee7073 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 14:14:04 +0100 Subject: [PATCH 29/35] Response status code default is 200 fixes #1220 --- framework/yii/web/Response.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php index 8934fa1..1d77d14 100644 --- a/framework/yii/web/Response.php +++ b/framework/yii/web/Response.php @@ -126,9 +126,10 @@ class Response extends \yii\base\Response */ public $charset; /** - * @var string + * @var string the HTTP status description that comes together with the status code. + * @see [[httpStatuses]] */ - public $statusText; + public $statusText = 'OK'; /** * @var string the version of the HTTP protocol to use. If not set, it will be determined via `$_SERVER['SERVER_PROTOCOL']`, * or '1.1' if that is not available. @@ -208,7 +209,7 @@ class Response extends \yii\base\Response /** * @var integer the HTTP status code to send with the response. */ - private $_statusCode; + private $_statusCode = 200; /** * @var HeaderCollection */ @@ -248,11 +249,6 @@ class Response extends \yii\base\Response */ public function setStatusCode($value, $text = null) { - if ($value === null) { - $this->_statusCode = null; - $this->statusText = null; - return; - } $this->_statusCode = (int)$value; if ($this->getIsInvalid()) { throw new InvalidParamException("The HTTP status code is invalid: $value"); @@ -297,10 +293,10 @@ class Response extends \yii\base\Response { $this->_headers = null; $this->_cookies = null; - $this->_statusCode = null; + $this->_statusCode = 200; + $this->statusText = 'OK'; $this->data = null; $this->content = null; - $this->statusText = null; } /** @@ -312,9 +308,7 @@ class Response extends \yii\base\Response return; } $statusCode = $this->getStatusCode(); - if ($statusCode !== null) { - header("HTTP/{$this->version} $statusCode {$this->statusText}"); - } + header("HTTP/{$this->version} $statusCode {$this->statusText}"); if ($this->_headers) { $headers = $this->getHeaders(); foreach ($headers as $name => $values) { From 64862f96ca05bd907d067fbc696532197d746ad7 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 14:35:08 +0100 Subject: [PATCH 30/35] disable CSRF validation after validation has failed this allows to be able to call error action. fixes #1244 --- framework/yii/web/Controller.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php index 3b08b7e..49e1ba6 100644 --- a/framework/yii/web/Controller.php +++ b/framework/yii/web/Controller.php @@ -92,6 +92,8 @@ class Controller extends \yii\base\Controller { if (parent::beforeAction($action)) { if ($this->enableCsrfValidation && !Yii::$app->getRequest()->validateCsrfToken()) { + // avoid checking again if errorAction is called to display exception + Yii::$app->getRequest()->enableCsrfValidation = false; throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.')); } return true; From 8dab87be3d72012892636d4fe73f9ff38014a6f3 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 16:17:23 +0100 Subject: [PATCH 31/35] fixed EmailValidator IDN and full pattern support also made everything conistent with client validation --- framework/yii/assets/yii.validation.js | 6 +-- framework/yii/validators/EmailValidator.php | 8 ++-- .../framework/validators/EmailValidatorTest.php | 49 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/framework/yii/assets/yii.validation.js b/framework/yii/assets/yii.validation.js index 3ce9edb..97074ac 100644 --- a/framework/yii/assets/yii.validation.js +++ b/framework/yii/assets/yii.validation.js @@ -117,16 +117,16 @@ yii.validation = (function ($) { var valid = true; if (options.enableIDN) { - var regexp = /^(.*)@(.*)$/, + var regexp = /^(.*?)$/, matches = regexp.exec(value); if (matches === null) { valid = false; } else { - value = punycode.toASCII(matches[1]) + '@' + punycode.toASCII(matches[2]); + value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4]; } } - if (!valid || !(value.match(options.pattern) && (!options.allowName || value.match(options.fullPattern)))) { + if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) { addMessage(messages, options.message, value); } }, diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php index bc105a5..238adab 100644 --- a/framework/yii/validators/EmailValidator.php +++ b/framework/yii/validators/EmailValidator.php @@ -93,15 +93,15 @@ class EmailValidator extends Validator public function validateValue($value) { // make sure string length is limited to avoid DOS attacks - if (!is_string($value) || strlen($value) >= 255) { + if (!is_string($value) || strlen($value) >= 320) { return false; } - if (($atPosition = strpos($value, '@')) === false) { + if (!preg_match('/^(.*?)$/', $value, $matches)) { return false; } - $domain = rtrim(substr($value, $atPosition + 1), '>'); + $domain = $matches[3]; if ($this->enableIDN) { - $value = idn_to_ascii(ltrim(substr($value, 0, $atPosition), '<')) . '@' . idn_to_ascii($domain); + $value = $matches[1] . idn_to_ascii($matches[2]) . '@' . idn_to_ascii($domain) . $matches[4]; } $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value); if ($valid) { diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index eee708d..462b980 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -24,6 +24,55 @@ class EmailValidatorTest extends TestCase $this->assertTrue($validator->validateValue('sam@rmcreative.ru')); $this->assertTrue($validator->validateValue('5011@gmail.com')); $this->assertFalse($validator->validateValue('rmcreative.ru')); + $this->assertFalse($validator->validateValue('Carsten Brandt ')); + $this->assertFalse($validator->validateValue('"Carsten Brandt" ')); + $this->assertFalse($validator->validateValue('')); + $this->assertFalse($validator->validateValue('info@örtliches.de')); + $this->assertFalse($validator->validateValue('sam@рмкреатиф.ru')); + + $validator->allowName = true; + + $this->assertTrue($validator->validateValue('sam@rmcreative.ru')); + $this->assertTrue($validator->validateValue('5011@gmail.com')); + $this->assertFalse($validator->validateValue('rmcreative.ru')); + $this->assertTrue($validator->validateValue('Carsten Brandt ')); + $this->assertTrue($validator->validateValue('"Carsten Brandt" ')); + $this->assertTrue($validator->validateValue('')); + $this->assertFalse($validator->validateValue('info@örtliches.de')); + $this->assertFalse($validator->validateValue('sam@рмкреатиф.ru')); + $this->assertFalse($validator->validateValue('Informtation info@oertliches.de')); + } + + public function testValidateIdnValue() + { + if (!extension_loaded("intl")) { + $this->markTestSkipped("intl not installed. Skipping."); + } + + $validator = new EmailValidator(); + $validator->enableIDN = true; + + $this->assertTrue($validator->validateValue('info@örtliches.de')); + $this->assertTrue($validator->validateValue('sam@рмкреатиф.ru')); + $this->assertTrue($validator->validateValue('sam@rmcreative.ru')); + $this->assertTrue($validator->validateValue('5011@gmail.com')); + $this->assertFalse($validator->validateValue('rmcreative.ru')); + $this->assertFalse($validator->validateValue('Carsten Brandt ')); + $this->assertFalse($validator->validateValue('"Carsten Brandt" ')); + $this->assertFalse($validator->validateValue('')); + + $validator->allowName = true; + + $this->assertTrue($validator->validateValue('info@örtliches.de')); + $this->assertTrue($validator->validateValue('Informtation ')); + $this->assertFalse($validator->validateValue('Informtation info@örtliches.de')); + $this->assertTrue($validator->validateValue('sam@рмкреатиф.ru')); + $this->assertTrue($validator->validateValue('sam@rmcreative.ru')); + $this->assertTrue($validator->validateValue('5011@gmail.com')); + $this->assertFalse($validator->validateValue('rmcreative.ru')); + $this->assertTrue($validator->validateValue('Carsten Brandt ')); + $this->assertTrue($validator->validateValue('"Carsten Brandt" ')); + $this->assertTrue($validator->validateValue('')); } public function testValidateValueMx() From 4079acf4a6e882f5ba0eef112cd62ae82dcf43d4 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 16:30:12 +0100 Subject: [PATCH 32/35] changed EmailValidator MX check to be more useful issue #1246 --- framework/yii/validators/EmailValidator.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php index 238adab..cde175a 100644 --- a/framework/yii/validators/EmailValidator.php +++ b/framework/yii/validators/EmailValidator.php @@ -38,11 +38,22 @@ class EmailValidator extends Validator */ public $allowName = false; /** - * @var boolean whether to check the MX record for the email address. - * Defaults to false. To enable it, you need to make sure the PHP function 'checkdnsrr' - * exists in your PHP installation. + * @var boolean whether to check whether the emails domain exists and has either an A or MX record. + * Be aware of the fact that this check can fail due to temporary DNS problems even if the email address is + * valid and an email would be deliverable. Defaults to false. + * @see dnsMessage */ - public $checkMX = false; + public $checkDNS = false; + /** + * @var string the error message to display when the domain of the email does not exist. + * It may contain the following placeholders which will be replaced accordingly by the validator: + * + * - `{attribute}`: the label of the attribute being validated + * - `{value}`: the value of the attribute being validated + * + * @see checkDNS + */ + public $dnsMessage; /** * @var boolean whether to check port 25 for the email address. * Defaults to false. @@ -69,6 +80,9 @@ class EmailValidator extends Validator if ($this->message === null) { $this->message = Yii::t('yii', '{attribute} is not a valid email address.'); } + if ($this->dnsMessage === null) { + $this->dnsMessage = Yii::t('yii', 'The domain of this email address does not seem to exist.'); + } } /** @@ -105,8 +119,8 @@ class EmailValidator extends Validator } $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value); if ($valid) { - if ($this->checkMX && function_exists('checkdnsrr')) { - $valid = checkdnsrr($domain, 'MX'); + if ($this->checkDNS) { + $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'); } if ($valid && $this->checkPort && function_exists('fsockopen')) { $valid = fsockopen($domain, 25) !== false; From 7b5b93efd242c2c3b7a57a6c6493b0de2cc9cdcd Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 16:46:04 +0100 Subject: [PATCH 33/35] fixed email validator test break --- tests/unit/framework/validators/EmailValidatorTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index 462b980..71d1666 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -78,10 +78,14 @@ class EmailValidatorTest extends TestCase public function testValidateValueMx() { $validator = new EmailValidator(); - $validator->checkMX = true; + $validator->checkDNS = true; $this->assertTrue($validator->validateValue('5011@gmail.com')); - $this->assertFalse($validator->validateValue('test@example.com')); + + $validator->checkDNS = false; + $this->assertTrue($validator->validateValue('test@nonexistingsubdomain.example.com')); + $validator->checkDNS = true; + $this->assertFalse($validator->validateValue('test@nonexistingsubdomain.example.com')); } public function testValidateAttribute() From 45d92f1cef3b5ffe91d21438744b15571d1530de Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 16:50:29 +0100 Subject: [PATCH 34/35] refactored emailvalidator test --- .../framework/validators/EmailValidatorTest.php | 37 ++++++++-------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index 71d1666..770914d 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -41,17 +41,23 @@ class EmailValidatorTest extends TestCase $this->assertFalse($validator->validateValue('info@örtliches.de')); $this->assertFalse($validator->validateValue('sam@рмкреатиф.ru')); $this->assertFalse($validator->validateValue('Informtation info@oertliches.de')); + $this->assertTrue($validator->validateValue('test@example.com')); + $this->assertTrue($validator->validateValue('John Smith ')); + $this->assertFalse($validator->validateValue('John Smith ')); } - public function testValidateIdnValue() + public function testValidateValueIdn() { - if (!extension_loaded("intl")) { - $this->markTestSkipped("intl not installed. Skipping."); + if (!function_exists('idn_to_ascii')) { + $this->markTestSkipped('Intl extension required'); + return; } - $validator = new EmailValidator(); $validator->enableIDN = true; + $this->assertTrue($validator->validateValue('5011@example.com')); + $this->assertTrue($validator->validateValue('example@äüößìà.de')); + $this->assertTrue($validator->validateValue('example@xn--zcack7ayc9a.de')); $this->assertTrue($validator->validateValue('info@örtliches.de')); $this->assertTrue($validator->validateValue('sam@рмкреатиф.ru')); $this->assertTrue($validator->validateValue('sam@rmcreative.ru')); @@ -73,6 +79,9 @@ class EmailValidatorTest extends TestCase $this->assertTrue($validator->validateValue('Carsten Brandt ')); $this->assertTrue($validator->validateValue('"Carsten Brandt" ')); $this->assertTrue($validator->validateValue('')); + $this->assertTrue($validator->validateValue('test@example.com')); + $this->assertTrue($validator->validateValue('John Smith ')); + $this->assertFalse($validator->validateValue('John Smith ')); } public function testValidateValueMx() @@ -96,24 +105,4 @@ class EmailValidatorTest extends TestCase $val->validateAttribute($model, 'attr_email'); $this->assertFalse($model->hasErrors('attr_email')); } - - public function testValidateValueIdn() - { - if (!function_exists('idn_to_ascii')) { - $this->markTestSkipped('Intl extension required'); - return; - } - $val = new EmailValidator(['enableIDN' => true]); - $this->assertTrue($val->validateValue('5011@example.com')); - $this->assertTrue($val->validateValue('example@äüößìà.de')); - $this->assertTrue($val->validateValue('example@xn--zcack7ayc9a.de')); - } - - public function testValidateValueWithName() - { - $val = new EmailValidator(['allowName' => true]); - $this->assertTrue($val->validateValue('test@example.com')); - $this->assertTrue($val->validateValue('John Smith ')); - $this->assertFalse($val->validateValue('John Smith ')); - } } From 070bd9625cd157f8923c50c9064a9fc2fd5c443c Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 20 Nov 2013 18:57:29 +0100 Subject: [PATCH 35/35] removed checkPort feature from email validator fixes #1246 --- framework/yii/validators/EmailValidator.php | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php index cde175a..6b5a07f 100644 --- a/framework/yii/validators/EmailValidator.php +++ b/framework/yii/validators/EmailValidator.php @@ -41,25 +41,9 @@ class EmailValidator extends Validator * @var boolean whether to check whether the emails domain exists and has either an A or MX record. * Be aware of the fact that this check can fail due to temporary DNS problems even if the email address is * valid and an email would be deliverable. Defaults to false. - * @see dnsMessage */ public $checkDNS = false; /** - * @var string the error message to display when the domain of the email does not exist. - * It may contain the following placeholders which will be replaced accordingly by the validator: - * - * - `{attribute}`: the label of the attribute being validated - * - `{value}`: the value of the attribute being validated - * - * @see checkDNS - */ - public $dnsMessage; - /** - * @var boolean whether to check port 25 for the email address. - * Defaults to false. - */ - public $checkPort = false; - /** * @var boolean whether validation process should take into account IDN (internationalized domain * names). Defaults to false meaning that validation of emails containing IDN will always fail. * Note that in order to use IDN validation you have to install and enable `intl` PHP extension, @@ -80,9 +64,6 @@ class EmailValidator extends Validator if ($this->message === null) { $this->message = Yii::t('yii', '{attribute} is not a valid email address.'); } - if ($this->dnsMessage === null) { - $this->dnsMessage = Yii::t('yii', 'The domain of this email address does not seem to exist.'); - } } /** @@ -118,13 +99,8 @@ class EmailValidator extends Validator $value = $matches[1] . idn_to_ascii($matches[2]) . '@' . idn_to_ascii($domain) . $matches[4]; } $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value); - if ($valid) { - if ($this->checkDNS) { - $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'); - } - if ($valid && $this->checkPort && function_exists('fsockopen')) { - $valid = fsockopen($domain, 25) !== false; - } + if ($valid && $this->checkDNS) { + $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'); } return $valid; }