From 4cf05205d4c10200e978040ea4df350ab1a9e857 Mon Sep 17 00:00:00 2001 From: Panagiotis Moustafellos Date: Tue, 29 Oct 2013 00:18:22 +0200 Subject: [PATCH 01/27] added cache mset() base test --- tests/unit/framework/caching/CacheTestCase.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index 9ff6409..fc84cf1 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -92,6 +92,25 @@ abstract class CacheTestCase extends TestCase $this->assertEquals('array_test', $array['array_test']); } + public function testMset() + { + $cache = $this->getCacheInstance(); + $cache->flush(); + + $this->assertTrue($cache->mset(['string_test' => 'string_test', + 'number_test' => 42, + 'array_test' => ['array_test' => 'array_test'], + ])); + + $this->assertEquals('string_test', $cache->get('string_test')); + + $this->assertEquals(42, $cache->get('number_test')); + + $array = $cache->get('array_test'); + $this->assertArrayHasKey('array_test', $array); + $this->assertEquals('array_test', $array['array_test']); + } + public function testExists() { $cache = $this->prepare(); From 8f8adb2a4868d5891e3f8fd31ac3d560d8014c20 Mon Sep 17 00:00:00 2001 From: Panagiotis Moustafellos Date: Tue, 29 Oct 2013 00:43:26 +0200 Subject: [PATCH 02/27] added phpdoc block for mset() --- framework/yii/caching/Cache.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php index f9d117d..14f16c9 100644 --- a/framework/yii/caching/Cache.php +++ b/framework/yii/caching/Cache.php @@ -93,7 +93,7 @@ abstract class Cache extends Component implements \ArrayAccess * If the given key is a string containing alphanumeric characters only and no more than 32 characters, * then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key * is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]]. - * + * * @param mixed $key the key to be normalized * @return string the generated cache key */ @@ -216,6 +216,21 @@ abstract class Cache extends Component implements \ArrayAccess } /** + * Stores multiple items in cache. Each item contains a value identified by a key. + * If the cache already contains such a key, the existing value and + * expiration time will be replaced with the new ones, respectively. + * + * @param array $items the items to be cached, as key-value pairs. Each key can be a simple string or + * a complex data structure consisting of factors representing the key. + * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. + * @return boolean whether the items are successfully stored into cache + */ + public function mset($items, $expire = 0) + { + return false; + } + + /** * Stores a value identified by a key into cache if the cache does not contain this key. * Nothing will be done if the cache already contains the key. * @param mixed $key a key identifying the value to be cached value. This can be a simple string or From 3ebbab028449b0a82683d318c0cf931050f7a40d Mon Sep 17 00:00:00 2001 From: Panagiotis Moustafellos Date: Tue, 29 Oct 2013 00:49:31 +0200 Subject: [PATCH 03/27] marked mset() test incomplete --- tests/unit/framework/caching/CacheTestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index fc84cf1..bbb312d 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -94,6 +94,8 @@ abstract class CacheTestCase extends TestCase public function testMset() { + $this->markTestIncomplete('Work in progress'); + $cache = $this->getCacheInstance(); $cache->flush(); From 6992cc2c73cc30cf02e9d93aad2946118d80c859 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 15 Nov 2013 08:44:59 -0500 Subject: [PATCH 04/27] Fixes #1196. --- extensions/gii/generators/model/Generator.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/extensions/gii/generators/model/Generator.php b/extensions/gii/generators/model/Generator.php index 32ba2e5..ea43f6b 100644 --- a/extensions/gii/generators/model/Generator.php +++ b/extensions/gii/generators/model/Generator.php @@ -115,11 +115,16 @@ class Generator extends \yii\gii\Generator */ public function autoCompleteData() { - return [ - 'tableName' => function () { - return $this->getDbConnection()->getSchema()->getTableNames(); - }, - ]; + $db = $this->getDbConnection(); + if ($db === null) { + return [ + 'tableName' => function () use ($db) { + return $db->getSchema()->getTableNames(); + }, + ]; + } else { + return []; + } } /** From 542477c3231c4430f3bcc110a4005599b15c3c8f Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 15 Nov 2013 09:18:30 -0500 Subject: [PATCH 05/27] typo fix. --- extensions/gii/generators/model/Generator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/gii/generators/model/Generator.php b/extensions/gii/generators/model/Generator.php index ea43f6b..cd2fcbf 100644 --- a/extensions/gii/generators/model/Generator.php +++ b/extensions/gii/generators/model/Generator.php @@ -116,7 +116,7 @@ class Generator extends \yii\gii\Generator public function autoCompleteData() { $db = $this->getDbConnection(); - if ($db === null) { + if ($db !== null) { return [ 'tableName' => function () use ($db) { return $db->getSchema()->getTableNames(); From ffded7a1b54d5e007d1ccc503bfb02631947384e Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 15 Nov 2013 10:15:25 -0500 Subject: [PATCH 06/27] array syntax fix. --- extensions/bootstrap/Progress.php | 2 +- extensions/swiftmailer/Mailer.php | 8 ++++---- framework/yii/web/AssetConverter.php | 10 +++++----- tests/unit/framework/mail/BaseMessageTest.php | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/bootstrap/Progress.php b/extensions/bootstrap/Progress.php index ed2d37d..184451c 100644 --- a/extensions/bootstrap/Progress.php +++ b/extensions/bootstrap/Progress.php @@ -48,7 +48,7 @@ use yii\helpers\Html; * 'bars' => [ * ['percent' => 30, 'options' => ['class' => 'bar-danger']], * ['percent' => 30, 'label' => 'test', 'options' => ['class' => 'bar-success']], - * ['percent' => 35, 'options' => array['class' => 'bar-warning']], + * ['percent' => 35, 'options' => ['class' => 'bar-warning']], * ] * ]); * ``` diff --git a/extensions/swiftmailer/Mailer.php b/extensions/swiftmailer/Mailer.php index 3418d8d..fda0477 100644 --- a/extensions/swiftmailer/Mailer.php +++ b/extensions/swiftmailer/Mailer.php @@ -17,9 +17,9 @@ use yii\mail\BaseMailer; * To use Mailer, you should configure it in the application configuration like the following, * * ~~~ - * 'components' => array( + * 'components' => [ * ... - * 'email' => array( + * 'email' => [ * 'class' => 'yii\swiftmailer\Mailer', * 'transport' => [ * 'class' => 'Swift_SmtpTransport', @@ -29,9 +29,9 @@ use yii\mail\BaseMailer; * 'port' => '587', * 'encryption' => 'tls', * ], - * ), + * ], * ... - * ), + * ], * ~~~ * * You may also skip the configuration of the [[transport]] property. In that case, the default diff --git a/framework/yii/web/AssetConverter.php b/framework/yii/web/AssetConverter.php index a93b915..1b7d1c8 100644 --- a/framework/yii/web/AssetConverter.php +++ b/framework/yii/web/AssetConverter.php @@ -74,11 +74,11 @@ class AssetConverter extends Component implements AssetConverterInterface '{from}' => escapeshellarg("$basePath/$asset"), '{to}' => escapeshellarg("$basePath/$result"), ]); - $descriptor = array( - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w'), - ); - $pipes = array(); + $descriptor = [ + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + $pipes = []; $proc = proc_open($command, $descriptor, $pipes, $basePath); $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); diff --git a/tests/unit/framework/mail/BaseMessageTest.php b/tests/unit/framework/mail/BaseMessageTest.php index d80d4f7..35fa549 100644 --- a/tests/unit/framework/mail/BaseMessageTest.php +++ b/tests/unit/framework/mail/BaseMessageTest.php @@ -69,7 +69,7 @@ class BaseMessageTest extends TestCase class TestMailer extends BaseMailer { public $messageClass = 'yiiunit\framework\mail\TestMessage'; - public $sentMessages = array(); + public $sentMessages = []; protected function sendMessage($message) { From b06caa297bc0ded3229da0ba8f3e5aff7b26beac Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 08:00:39 -0500 Subject: [PATCH 07/27] Fixes #1206. --- framework/yii/helpers/BaseHtml.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework/yii/helpers/BaseHtml.php b/framework/yii/helpers/BaseHtml.php index 71ad9ea..64b070b 100644 --- a/framework/yii/helpers/BaseHtml.php +++ b/framework/yii/helpers/BaseHtml.php @@ -653,6 +653,9 @@ class BaseHtml */ public static function dropDownList($name, $selection = null, $items = [], $options = []) { + if (!empty($options['multiple'])) { + return static::listBox($name, $selection, $items, $options); + } $options['name'] = $name; $selectOptions = static::renderSelectOptions($selection, $items, $options); return static::tag('select', "\n" . $selectOptions . "\n", $options); From a446f3a586cb84cfb049fb6fb48c971d98663d45 Mon Sep 17 00:00:00 2001 From: egorpromo Date: Sat, 16 Nov 2013 21:14:53 +0700 Subject: [PATCH 08/27] Eliminating --- framework/yii/data/Pagination.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/yii/data/Pagination.php b/framework/yii/data/Pagination.php index 5fee61c..23f8944 100644 --- a/framework/yii/data/Pagination.php +++ b/framework/yii/data/Pagination.php @@ -83,7 +83,7 @@ class Pagination extends Object public $route; /** * @var array parameters (name => value) that should be used to obtain the current page number - * and to create new pagination URLs. If not set, $_GET will be used instead. + * and to create new pagination URLs. If not set, all parameters from $_GET will be used instead. * * The array element indexed by [[pageVar]] is considered to be the current page number. * If the element does not exist, the current page number is considered 0. @@ -131,7 +131,7 @@ class Pagination extends Object public function getPage($recalculate = false) { if ($this->_page === null || $recalculate) { - $params = $this->params === null ? $_GET : $this->params; + $params = $this->params === null ? Yii::$app->request->get() : $this->params; if (isset($params[$this->pageVar]) && is_scalar($params[$this->pageVar])) { $this->_page = (int)$params[$this->pageVar] - 1; if ($this->validatePage) { @@ -169,7 +169,7 @@ class Pagination extends Object */ public function createUrl($page) { - $params = $this->params === null ? $_GET : $this->params; + $params = $this->params === null ? Yii::$app->request->get() : $this->params; if ($page > 0 || $page >= 0 && $this->forcePageVar) { $params[$this->pageVar] = $page + 1; } else { From 5b36503ca8b7617c6f6a4e12535f41863dcd1705 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 16 Nov 2013 19:38:43 +0400 Subject: [PATCH 09/27] One less SQL query for login sequence in basic and advanced apps --- apps/advanced/common/models/LoginForm.php | 19 +++++++++++++++++-- apps/basic/models/LoginForm.php | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php index 30fb39b..3a57085 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/LoginForm.php @@ -13,6 +13,7 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; + private $_user; /** * @return array the validation rules. @@ -35,7 +36,7 @@ class LoginForm extends Model */ public function validatePassword() { - $user = User::findByUsername($this->username); + $user = $this->getUserByUsername($this->username); if (!$user || !$user->validatePassword($this->password)) { $this->addError('password', 'Incorrect username or password.'); } @@ -48,11 +49,25 @@ class LoginForm extends Model public function login() { if ($this->validate()) { - $user = User::findByUsername($this->username); + $user = $this->getUserByUsername($this->username); Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); return true; } else { return false; } } + + /** + * Finds user by username + * + * @param string $username + * @return User|null + */ + private function getUserByUsername($username) + { + if ($this->_user === null) { + $this->_user = User::findByUsername($username); + } + return $this->_user; + } } diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php index ad854a2..b02f83e 100644 --- a/apps/basic/models/LoginForm.php +++ b/apps/basic/models/LoginForm.php @@ -13,6 +13,7 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; + private $_user; /** * @return array the validation rules. @@ -35,7 +36,7 @@ class LoginForm extends Model */ public function validatePassword() { - $user = User::findByUsername($this->username); + $user = $this->getUserByUsername($this->username); if (!$user || !$user->validatePassword($this->password)) { $this->addError('password', 'Incorrect username or password.'); } @@ -48,11 +49,25 @@ class LoginForm extends Model public function login() { if ($this->validate()) { - $user = User::findByUsername($this->username); + $user = $this->getUserByUsername($this->username); Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); return true; } else { return false; } } + + /** + * Finds user by username + * + * @param string $username + * @return User|null + */ + private function getUserByUsername($username) + { + if ($this->_user === null) { + $this->_user = User::findByUsername($username); + } + return $this->_user; + } } From 77840adf651c0fb5f22ff472677de8f8b815e3a0 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 16 Nov 2013 16:53:50 +0100 Subject: [PATCH 10/27] Made ActiveRecord::isPrimaryKey() public + added tests and fixed behavior --- framework/yii/db/ActiveRecord.php | 11 ++++++----- tests/unit/framework/db/ActiveRecordTest.php | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php index 9edc824..e13bf90 100644 --- a/framework/yii/db/ActiveRecord.php +++ b/framework/yii/db/ActiveRecord.php @@ -1485,18 +1485,19 @@ class ActiveRecord extends Model } /** - * @param array $keys - * @return boolean + * Returns a value indicating whether the given set of attributes represents the primary key for this model + * @param array $keys the set of attributes to check + * @return boolean whether the given set of attributes represents the primary key for this model */ - private function isPrimaryKey($keys) + public static function isPrimaryKey($keys) { - $pks = $this->primaryKey(); + $pks = static::primaryKey(); foreach ($keys as $key) { if (!in_array($key, $pks, true)) { return false; } } - return true; + return count($keys) === count($pks); } /** diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php index f96f2d3..b2981f2 100644 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ b/tests/unit/framework/db/ActiveRecordTest.php @@ -489,4 +489,21 @@ class ActiveRecordTest extends DatabaseTestCase $customers = Customer::find()->where(['status' => false])->all(); $this->assertEquals(1, count($customers)); } + + public function testIsPrimaryKey() + { + $this->assertFalse(Customer::isPrimaryKey([])); + $this->assertTrue(Customer::isPrimaryKey(['id'])); + $this->assertFalse(Customer::isPrimaryKey(['id', 'name'])); + $this->assertFalse(Customer::isPrimaryKey(['name'])); + $this->assertFalse(Customer::isPrimaryKey(['name', 'email'])); + + $this->assertFalse(OrderItem::isPrimaryKey([])); + $this->assertFalse(OrderItem::isPrimaryKey(['order_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['item_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['quantity'])); + $this->assertFalse(OrderItem::isPrimaryKey(['quantity', 'subtotal'])); + $this->assertTrue(OrderItem::isPrimaryKey(['order_id', 'item_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['order_id', 'item_id', 'quantity'])); + } } From f217948bf4a8db4dc73878a1fee8df3478bf858e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 16 Nov 2013 17:08:47 +0100 Subject: [PATCH 11/27] fixed test break after #1207 --- tests/unit/framework/data/ActiveDataProviderTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php index 4e4ca77..a5f0d14 100644 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ b/tests/unit/framework/data/ActiveDataProviderTest.php @@ -28,6 +28,9 @@ class ActiveDataProviderTest extends DatabaseTestCase { parent::setUp(); ActiveRecord::$db = $this->getConnection(); + $this->mockApplication([ + 'request' => 'yii\\web\\Request', + ]); } public function testActiveQuery() From c16c1812474dea418e73129b4034580bceb8164c Mon Sep 17 00:00:00 2001 From: egorpromo Date: Sat, 16 Nov 2013 23:25:44 +0700 Subject: [PATCH 12/27] Must be one method to get _GET. getGet() is just duplication --- framework/yii/web/Request.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index 2071afa..9e525fd 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -312,15 +312,6 @@ class Request extends \yii\base\Request } /** - * Returns the GET request parameter values. - * @return array the GET request parameter values - */ - public function getGet() - { - return $_GET; - } - - /** * Returns the named POST parameter value. * If the POST parameter does not exist, the second parameter to this method will be returned. * @param string $name the POST parameter name. If not specified, whole $_POST is returned. From 4e80dc54c28bd428260ca2fd319806cf9842213b Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 16 Nov 2013 17:24:05 +0100 Subject: [PATCH 13/27] removed hard dependency of Pagination -> web\Request issue #1207 --- framework/yii/data/Pagination.php | 9 +++++++-- tests/unit/framework/data/ActiveDataProviderTest.php | 3 --- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/framework/yii/data/Pagination.php b/framework/yii/data/Pagination.php index 23f8944..20c0fed 100644 --- a/framework/yii/data/Pagination.php +++ b/framework/yii/data/Pagination.php @@ -9,6 +9,7 @@ namespace yii\data; use Yii; use yii\base\Object; +use yii\web\Request; /** * Pagination represents information relevant to pagination of data items. @@ -131,7 +132,9 @@ class Pagination extends Object public function getPage($recalculate = false) { if ($this->_page === null || $recalculate) { - $params = $this->params === null ? Yii::$app->request->get() : $this->params; + if (($params = $this->params) === null) { + $params = (Yii::$app->request instanceof Request) ? Yii::$app->request->get : []; + } if (isset($params[$this->pageVar]) && is_scalar($params[$this->pageVar])) { $this->_page = (int)$params[$this->pageVar] - 1; if ($this->validatePage) { @@ -169,7 +172,9 @@ class Pagination extends Object */ public function createUrl($page) { - $params = $this->params === null ? Yii::$app->request->get() : $this->params; + if (($params = $this->params) === null) { + $params = (Yii::$app->request instanceof Request) ? Yii::$app->request->get : []; + } if ($page > 0 || $page >= 0 && $this->forcePageVar) { $params[$this->pageVar] = $page + 1; } else { diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php index a5f0d14..4e4ca77 100644 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ b/tests/unit/framework/data/ActiveDataProviderTest.php @@ -28,9 +28,6 @@ class ActiveDataProviderTest extends DatabaseTestCase { parent::setUp(); ActiveRecord::$db = $this->getConnection(); - $this->mockApplication([ - 'request' => 'yii\\web\\Request', - ]); } public function testActiveQuery() From effc41c1cf433b4548735cad3218e6b618457493 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 12:41:56 -0500 Subject: [PATCH 14/27] minor refactoring. --- framework/yii/data/Pagination.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/yii/data/Pagination.php b/framework/yii/data/Pagination.php index 20c0fed..dc75294 100644 --- a/framework/yii/data/Pagination.php +++ b/framework/yii/data/Pagination.php @@ -133,7 +133,8 @@ class Pagination extends Object { if ($this->_page === null || $recalculate) { if (($params = $this->params) === null) { - $params = (Yii::$app->request instanceof Request) ? Yii::$app->request->get : []; + $request = Yii::$app->getRequest(); + $params = $request instanceof Request ? $request->get() : []; } if (isset($params[$this->pageVar]) && is_scalar($params[$this->pageVar])) { $this->_page = (int)$params[$this->pageVar] - 1; @@ -173,7 +174,8 @@ class Pagination extends Object public function createUrl($page) { if (($params = $this->params) === null) { - $params = (Yii::$app->request instanceof Request) ? Yii::$app->request->get : []; + $request = Yii::$app->getRequest(); + $params = $request instanceof Request ? $request->get() : []; } if ($page > 0 || $page >= 0 && $this->forcePageVar) { $params[$this->pageVar] = $page + 1; From 5795522fc2699170c2c468c8ee1fe629cec965a5 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 16 Nov 2013 22:16:10 +0400 Subject: [PATCH 15/27] Use Yii::$app->user->login result in LoginForm --- apps/advanced/common/models/LoginForm.php | 3 +-- apps/basic/models/LoginForm.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php index 3a57085..5de2cc8 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/LoginForm.php @@ -50,8 +50,7 @@ class LoginForm extends Model { if ($this->validate()) { $user = $this->getUserByUsername($this->username); - Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); - return true; + return Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); } else { return false; } diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php index b02f83e..f16bc0e 100644 --- a/apps/basic/models/LoginForm.php +++ b/apps/basic/models/LoginForm.php @@ -50,8 +50,7 @@ class LoginForm extends Model { if ($this->validate()) { $user = $this->getUserByUsername($this->username); - Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); - return true; + return Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); } else { return false; } From a6cb556e2180d4b89d50bc1205d80bc01ae2aec3 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 16:42:03 -0500 Subject: [PATCH 16/27] Fixes #1204: the length of primary key for migration table is too long. --- framework/yii/console/controllers/MigrateController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/console/controllers/MigrateController.php b/framework/yii/console/controllers/MigrateController.php index ac941a4..0e36911 100644 --- a/framework/yii/console/controllers/MigrateController.php +++ b/framework/yii/console/controllers/MigrateController.php @@ -594,7 +594,7 @@ class MigrateController extends Controller { echo 'Creating migration history table "' . $this->migrationTable . '"...'; $this->db->createCommand()->createTable($this->migrationTable, [ - 'version' => 'varchar(255) NOT NULL PRIMARY KEY', + 'version' => 'varchar(180) NOT NULL PRIMARY KEY', 'apply_time' => 'integer', ])->execute(); $this->db->createCommand()->insert($this->migrationTable, [ From ad6411cae2efbd35e4ef4e5d0aeceb0e50368398 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 17 Nov 2013 02:18:51 +0400 Subject: [PATCH 17/27] Fixed LoginForm::getUserByUsername --- apps/advanced/common/models/LoginForm.php | 8 ++++---- apps/basic/models/LoginForm.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php index 5de2cc8..4005914 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/LoginForm.php @@ -13,7 +13,7 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; - private $_user; + private $_users = []; /** * @return array the validation rules. @@ -64,9 +64,9 @@ class LoginForm extends Model */ private function getUserByUsername($username) { - if ($this->_user === null) { - $this->_user = User::findByUsername($username); + if (empty($this->_users[$username])) { + $this->_users[$username] = User::findByUsername($username); } - return $this->_user; + return $this->_users[$username]; } } diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php index f16bc0e..d9622ad 100644 --- a/apps/basic/models/LoginForm.php +++ b/apps/basic/models/LoginForm.php @@ -13,7 +13,7 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; - private $_user; + private $_users = []; /** * @return array the validation rules. @@ -64,9 +64,9 @@ class LoginForm extends Model */ private function getUserByUsername($username) { - if ($this->_user === null) { - $this->_user = User::findByUsername($username); + if (empty($this->_users[$username])) { + $this->_users[$username] = User::findByUsername($username); } - return $this->_user; + return $this->_users[$username]; } } From 4231724ebf446331ecd9bc03f891737ea4f14a5d Mon Sep 17 00:00:00 2001 From: docsolver Date: Sun, 17 Nov 2013 00:14:02 +0100 Subject: [PATCH 18/27] Clarification about clientOptions and using JUI in AR form I accidentally made this pull request in the read-only JUI repo, so I'm doing it again here. --- extensions/jui/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/extensions/jui/README.md b/extensions/jui/README.md index f76d88e..f197c8c 100644 --- a/extensions/jui/README.md +++ b/extensions/jui/README.md @@ -6,7 +6,17 @@ and makes using JQuery UI widgets in Yii applications extremely easy. For exampl single line of code in a view file would render a JQuery UI DatePicker widget: ```php - 'start']) ?> + 'attributeName']) ?> +``` + +Configuring the Jquery UI options should be done using the clientOptions attribute: +```php + 'attributeName', 'clientOptions' => ['dateFormat' => 'yy-mm-dd']]) ?> +``` + +If you want to use the JUI widget in an ActiveRecord form, it can be done like this: +```php +field($model,'attributeName')->widget(DatePicker::className(),['clientOptions' => ['dateFormat' => 'yy-mm-dd']]) ?> ``` From 6a4ed5a1e8619d0811fea43f5994ddb32c00378e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sun, 17 Nov 2013 00:41:56 +0100 Subject: [PATCH 19/27] fixed cubrid schema primary key detection --- framework/yii/db/cubrid/Schema.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php index 0b9d0f5..3131fa8 100644 --- a/framework/yii/db/cubrid/Schema.php +++ b/framework/yii/db/cubrid/Schema.php @@ -138,11 +138,15 @@ class Schema extends \yii\db\Schema foreach ($columns as $info) { $column = $this->loadColumnSchema($info); $table->columns[$column->name] = $column; - if ($column->isPrimaryKey) { - $table->primaryKey[] = $column->name; - if ($column->autoIncrement) { - $table->sequenceName = ''; - } + } + + $primaryKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $table->name); + foreach ($primaryKeys as $key) { + $column = $table->columns[$key['ATTR_NAME']]; + $column->isPrimaryKey = true; + $table->primaryKey[] = $column->name; + if ($column->autoIncrement) { + $table->sequenceName = ''; } } From 1a7a15a3ef78c9e1f8aeb476fa11f6cf016e00f3 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 17 Nov 2013 04:00:30 +0400 Subject: [PATCH 20/27] Implemented mset, madd for cache. Added tests. --- framework/yii/caching/ApcCache.php | 22 ++++++ framework/yii/caching/Cache.php | 98 ++++++++++++++++++++++++-- framework/yii/caching/MemCache.php | 21 ++++++ framework/yii/caching/WinCache.php | 24 +++++++ tests/unit/framework/caching/CacheTestCase.php | 26 +++++-- 5 files changed, 180 insertions(+), 11 deletions(-) diff --git a/framework/yii/caching/ApcCache.php b/framework/yii/caching/ApcCache.php index 6c2754a..688c3f1 100644 --- a/framework/yii/caching/ApcCache.php +++ b/framework/yii/caching/ApcCache.php @@ -72,6 +72,17 @@ class ApcCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return array_keys(apc_store($data, null, $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 @@ -85,6 +96,17 @@ class ApcCache extends Cache } /** + * Adds multiple key-value pairs to cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return array_keys(apc_add($data, null, $expire)); + } + + /** * 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 diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php index 6471e5d..41a25b2 100644 --- a/framework/yii/caching/Cache.php +++ b/framework/yii/caching/Cache.php @@ -220,14 +220,62 @@ abstract class Cache extends Component implements \ArrayAccess * If the cache already contains such a key, the existing value and * expiration time will be replaced with the new ones, respectively. * - * @param array $items the items to be cached, as key-value pairs. Each key can be a simple string or - * a complex data structure consisting of factors representing the key. - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. + * @return boolean whether the items are successfully stored into cache + */ + public function mset($items, $expire = 0, $dependency = null) + { + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->setValues($data, $expire); + } + + /** + * Stores multiple items in cache. Each item contains a value identified by a key. + * If the cache already contains such a key, the existing value and expiration time will be preserved. + * + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. * @return boolean whether the items are successfully stored into cache */ - public function mset($items, $expire = 0) + public function madd($items, $expire = 0, $dependency = null) { - return false; + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->addValues($data, $expire); } /** @@ -342,6 +390,46 @@ abstract class Cache extends Component implements \ArrayAccess } /** + * Stores multiple key-value pairs in cache. + * The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache + * storage supports multiset, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->setValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + + /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->addValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + + /** * Returns whether there is a cache entry with a specified key. * This method is required by the interface ArrayAccess. * @param string $key a key identifying the cached value diff --git a/framework/yii/caching/MemCache.php b/framework/yii/caching/MemCache.php index 6f7a760..3391796 100644 --- a/framework/yii/caching/MemCache.php +++ b/framework/yii/caching/MemCache.php @@ -202,6 +202,27 @@ class MemCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys. Always empty in case of using memcached. + */ + protected function setValues($data, $expire) + { + if ($this->useMemcached) { + if ($expire > 0) { + $expire += time(); + } else { + $expire = 0; + } + $this->_cache->setMulti($data, $expire); + return []; + } else { + return parent::setValues($data, $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. * diff --git a/framework/yii/caching/WinCache.php b/framework/yii/caching/WinCache.php index 3679884..7f1eca8 100644 --- a/framework/yii/caching/WinCache.php +++ b/framework/yii/caching/WinCache.php @@ -72,6 +72,17 @@ class WinCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return wincache_ucache_set($data, null, $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. * @@ -86,6 +97,19 @@ class WinCache extends Cache } /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return wincache_ucache_add($data, null, $expire); + } + + /** * 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 diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index d51cebd..849cad0 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -93,15 +93,14 @@ abstract class CacheTestCase extends TestCase public function testMset() { - $this->markTestIncomplete('Work in progress'); - $cache = $this->getCacheInstance(); $cache->flush(); - $this->assertTrue($cache->mset(['string_test' => 'string_test', - 'number_test' => 42, - 'array_test' => ['array_test' => 'array_test'], - ])); + $cache->mset([ + 'string_test' => 'string_test', + 'number_test' => 42, + 'array_test' => ['array_test' => 'array_test'], + ]); $this->assertEquals('string_test', $cache->get('string_test')); @@ -185,6 +184,21 @@ abstract class CacheTestCase extends TestCase $this->assertEquals(13, $cache->get('add_test')); } + public function testMadd() + { + $cache = $this->prepare(); + + $this->assertFalse($cache->get('add_test')); + + $cache->madd([ + 'number_test' => 13, + 'add_test' => 13, + ]); + + $this->assertEquals(42, $cache->get('number_test')); + $this->assertEquals(13, $cache->get('add_test')); + } + public function testDelete() { $cache = $this->prepare(); From 979e8d1619e26adc1bdd6f75cc04b2981e100942 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 17 Nov 2013 04:19:57 +0400 Subject: [PATCH 21/27] Replaced assertTrue(file_exists with assertFileExists in FileHelperTest --- tests/unit/framework/helpers/FileHelperTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/framework/helpers/FileHelperTest.php b/tests/unit/framework/helpers/FileHelperTest.php index 3fde06e..1804d5e 100644 --- a/tests/unit/framework/helpers/FileHelperTest.php +++ b/tests/unit/framework/helpers/FileHelperTest.php @@ -126,10 +126,10 @@ class FileHelperTest extends TestCase FileHelper::copyDirectory($srcDirName, $dstDirName); - $this->assertTrue(file_exists($dstDirName), 'Destination directory does not exist!'); + $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); foreach ($files as $name => $content) { $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; - $this->assertTrue(file_exists($fileName), 'Directory file is missing!'); + $this->assertFileExists($fileName); $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); } } @@ -189,7 +189,7 @@ class FileHelperTest extends TestCase FileHelper::removeDirectory($dirName); - $this->assertFalse(file_exists($dirName), 'Unable to remove directory!'); + $this->assertFileNotExists($dirName, 'Unable to remove directory!'); // should be silent about non-existing directories FileHelper::removeDirectory($basePath . DIRECTORY_SEPARATOR . 'nonExisting'); @@ -277,7 +277,7 @@ class FileHelperTest extends TestCase $basePath = $this->testFilePath; $dirName = $basePath . DIRECTORY_SEPARATOR . 'test_dir_level_1' . DIRECTORY_SEPARATOR . 'test_dir_level_2'; $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true if directory was created!'); - $this->assertTrue(file_exists($dirName), 'Unable to create directory recursively!'); + $this->assertFileExists($dirName, 'Unable to create directory recursively!'); $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true for already existing directories!'); } From 83ab0f0655831331266b4ad680dca512b57189bd Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 20:39:51 -0500 Subject: [PATCH 22/27] minor refactoring --- apps/advanced/common/models/LoginForm.php | 19 +++++++++---------- apps/basic/models/LoginForm.php | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php index 4005914..38888d9 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/LoginForm.php @@ -13,7 +13,8 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; - private $_users = []; + + private $_user = false; /** * @return array the validation rules. @@ -36,7 +37,7 @@ class LoginForm extends Model */ public function validatePassword() { - $user = $this->getUserByUsername($this->username); + $user = $this->getUser(); if (!$user || !$user->validatePassword($this->password)) { $this->addError('password', 'Incorrect username or password.'); } @@ -49,24 +50,22 @@ class LoginForm extends Model public function login() { if ($this->validate()) { - $user = $this->getUserByUsername($this->username); - return Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); + return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); } else { return false; } } /** - * Finds user by username + * Finds user by [[username]] * - * @param string $username * @return User|null */ - private function getUserByUsername($username) + private function getUser() { - if (empty($this->_users[$username])) { - $this->_users[$username] = User::findByUsername($username); + if ($this->_user === false) { + $this->_user = User::findByUsername($this->username); } - return $this->_users[$username]; + return $this->_user; } } diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php index d9622ad..a365db7 100644 --- a/apps/basic/models/LoginForm.php +++ b/apps/basic/models/LoginForm.php @@ -13,7 +13,8 @@ class LoginForm extends Model public $username; public $password; public $rememberMe = true; - private $_users = []; + + private $_user = false; /** * @return array the validation rules. @@ -36,7 +37,7 @@ class LoginForm extends Model */ public function validatePassword() { - $user = $this->getUserByUsername($this->username); + $user = $this->getUser(); if (!$user || !$user->validatePassword($this->password)) { $this->addError('password', 'Incorrect username or password.'); } @@ -49,24 +50,22 @@ class LoginForm extends Model public function login() { if ($this->validate()) { - $user = $this->getUserByUsername($this->username); - return Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); + return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); } else { return false; } } /** - * Finds user by username + * Finds user by [[username]] * - * @param string $username * @return User|null */ - private function getUserByUsername($username) + private function getUser() { - if (empty($this->_users[$username])) { - $this->_users[$username] = User::findByUsername($username); + if ($this->_user === false) { + $this->_user = User::findByUsername($this->username); } - return $this->_users[$username]; + return $this->_user; } } From 8106cdedbf1bda6d5bb7f29367a0ab24b1bf70ce Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 21:19:34 -0500 Subject: [PATCH 23/27] Implemented DB fixture manager. --- framework/yii/test/DbFixtureManager.php | 219 ++++++++++++++++++++++++++++++++ framework/yii/test/DbTestTrait.php | 110 ++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 framework/yii/test/DbFixtureManager.php create mode 100644 framework/yii/test/DbTestTrait.php diff --git a/framework/yii/test/DbFixtureManager.php b/framework/yii/test/DbFixtureManager.php new file mode 100644 index 0000000..ed90284 --- /dev/null +++ b/framework/yii/test/DbFixtureManager.php @@ -0,0 +1,219 @@ + + * @since 2.0 + */ +class DbFixtureManager extends Component +{ + /** + * @var string the init script file that should be executed before running each test. + * This should be a path relative to [[basePath]]. + */ + public $initScript = 'init.php'; + /** + * @var string the base path containing all fixtures. This can be either a directory path or path alias. + */ + public $basePath = '@app/tests/fixtures'; + /** + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the DbFixtureManager object is created, if you want to change this property, you should only assign it + * with a DB connection object. + */ + public $db = 'db'; + /** + * @var array list of database schemas that the test tables may reside in. Defaults to + * array(''), meaning using the default schema (an empty string refers to the + * default schema). This property is mainly used when turning on and off integrity checks + * so that fixture data can be populated into the database without causing problem. + */ + public $schemas = ['']; + + private $_rows; // fixture name, row alias => row + private $_models; // fixture name, row alias => record (or class name) + private $_modelClasses; + + + /** + * Loads the specified fixtures. + * + * This method does the following things to load the fixtures: + * + * - Run [[initScript]] if any. + * - Clean up data and models loaded in memory previously. + * - Load each specified fixture by calling [[loadFixture()]]. + * + * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. + * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified + * ActiveRecord class name (e.g. `app\models\Post`). An element can be associated with a key + * which will be treated as the fixture name. + * @return array the loaded fixture data (fixture name => table rows) + * @throws InvalidConfigException if a model class specifying a fixture is not an ActiveRecord class. + */ + public function load(array $fixtures = []) + { + $this->basePath = Yii::getAlias($this->basePath); + + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new InvalidConfigException("The 'db' property must be either a DB connection instance or the application component ID of a DB connection."); + } + + foreach ($fixtures as $name => $fixture) { + if (strpos($fixture, '\\') !== false) { + $model = new $fixture; + if ($model instanceof ActiveRecord) { + $this->_modelClasses[$name] = $fixture; + $fixtures[$name] = $model->getTableSchema()->name; + } else { + throw new InvalidConfigException("Fixture '$fixture' must be an ActiveRecord class."); + } + } + } + + $this->_modelClasses = $this->_rows = $this->_models = []; + + $this->checkIntegrity(false); + + if (!empty($this->initScript)) { + $initFile = $this->basePath . '/' . $this->initScript; + if (is_file($initFile)) { + require($initFile); + } + } + + foreach ($fixtures as $name => $tableName) { + $rows = $this->loadFixture($tableName); + if (is_array($rows)) { + $this->_rows[$name] = $rows; + } + } + $this->checkIntegrity(true); + return $this->_rows; + } + + /** + * Loads the fixture for the specified table. + * + * This method does the following tasks to load the fixture for a table: + * + * - Remove existing rows in the table. + * - If there is any auto-incremental column, the corresponding sequence will be reset to 0. + * - If a fixture file is found, it will be executed, and its return value will be treated + * as rows which will then be inserted into the table. + * + * @param string $tableName table name + * @return array|boolean the loaded fixture rows indexed by row aliases (if any). + * False is returned if the table does not have a fixture. + * @throws InvalidConfigException if the specified table does not exist + */ + public function loadFixture($tableName) + { + $table = $this->db->getSchema()->getTableSchema($tableName); + if ($table === null) { + throw new InvalidConfigException("Table does not exist: $tableName"); + } + + $this->db->createCommand()->truncateTable($tableName); + + $fileName = $this->basePath . '/' . $tableName . '.php'; + if (!is_file($fileName)) { + return false; + } + + $rows = []; + foreach (require($fileName) as $alias => $row) { + $this->db->createCommand()->insert($tableName, $row)->execute(); + if ($table->sequenceName !== null) { + foreach ($table->primaryKey as $pk) { + if (!isset($row[$pk])) { + $row[$pk] = $this->db->getLastInsertID($table->sequenceName); + break; + } + } + } + $rows[$alias] = $row; + } + + return $rows; + } + + /** + * Returns the fixture data rows. + * The rows will have updated primary key values if the primary key is auto-incremental. + * @param string $fixtureName the fixture name + * @return array the fixture data rows. False is returned if there is no such fixture data. + */ + public function getRows($fixtureName) + { + return isset($this->_rows[$fixtureName]) ? $this->_rows[$fixtureName] : false; + } + + /** + * Returns the specified ActiveRecord instance in the fixture data. + * @param string $fixtureName the fixture name + * @param string $modelName the alias for the fixture data row + * @return \yii\db\ActiveRecord the ActiveRecord instance. Null is returned if there is no such fixture row. + */ + public function getModel($fixtureName, $modelName) + { + if (!isset($this->_modelClasses[$fixtureName]) || !isset($this->_rows[$fixtureName][$modelName])) { + return null; + } + if (isset($this->_models[$fixtureName][$modelName])) { + return $this->_models[$fixtureName][$modelName]; + } + $row = $this->_rows[$fixtureName][$modelName]; + /** @var \yii\db\ActiveRecord $modelClass */ + $modelClass = $this->_models[$fixtureName]; + /** @var \yii\db\ActiveRecord $model */ + $model = new $modelClass; + $keys = []; + foreach ($model->primaryKey() as $key) { + $keys[$key] = isset($row[$key]) ? $row[$key] : null; + } + return $this->_models[$fixtureName][$modelName] = $modelClass::find($keys); + } + + /** + * Enables or disables database integrity check. + * This method may be used to temporarily turn off foreign constraints check. + * @param boolean $check whether to enable database integrity check + */ + public function checkIntegrity($check) + { + foreach ($this->schemas as $schema) { + $this->db->createCommand()->checkIntegrity($check, $schema); + } + } +} diff --git a/framework/yii/test/DbTestTrait.php b/framework/yii/test/DbTestTrait.php new file mode 100644 index 0000000..8a6dc3c --- /dev/null +++ b/framework/yii/test/DbTestTrait.php @@ -0,0 +1,110 @@ +loadFixtures([ + * 'posts' => Post::className(), + * 'users' => User::className(), + * ]); + * } + * } + * ~~~ + * + * @author Qiang Xue + * @since 2.0 + */ +trait DbTestTrait +{ + /** + * Loads the specified fixtures. + * + * This method should typically be called in the setup method of test cases so that + * the fixtures are loaded before running each test method. + * + * This method does the following things: + * + * - Run [[DbFixtureManager::initScript]] if it is found under [[DbFixtureManager::basePath]]. + * - Clean up data and models loaded in memory previously. + * - Load each specified fixture: + * * Truncate the corresponding table. + * * If a fixture file named `TableName.php` is found under [[DbFixtureManager::basePath]], + * the file will be executed, and the return value will be treated as rows which will + * then be inserted into the table. + * + * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. + * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified + * ActiveRecord class name (e.g. `app\models\Post`). An element can be optionally associated with a key + * which will be treated as the fixture name. For example, + * + * ~~~ + * [ + * 'tbl_comment', + * 'users' => 'tbl_user', // 'users' is the fixture name, 'tbl_user' is a table name + * 'posts' => 'app\models\Post, // 'app\models\Post' is a model class name + * ] + * ~~~ + * + * @return array the loaded fixture data (fixture name => table rows) + */ + public function loadFixtures(array $fixtures = []) + { + return $this->getFixtureManager()->load($fixtures); + } + + /** + * Returns the DB fixture manager. + * @return DbFixtureManager the DB fixture manager + */ + public function getFixtureManager() + { + return Yii::$app->getComponent('fixture'); + } + + /** + * Returns the table rows of the named fixture. + * @param string $fixtureName the fixture name. + * @return array the named fixture table rows. False is returned if there is no such fixture data. + */ + public function getFixtureRows($fixtureName) + { + return $this->getFixtureManager()->getRows($fixtureName); + } + + /** + * Returns the named AR instance corresponding to the named fixture. + * @param string $fixtureName the fixture name. + * @param string $modelName the name of the fixture data row + * @return \yii\db\ActiveRecord the named AR instance corresponding to the named fixture. + * Null is returned if there is no such fixture or the record cannot be found. + */ + public function getFixtureModel($fixtureName, $modelName) + { + return $this->getFixtureManager()->getModel($fixtureName, $modelName); + } +} From 1c24b3e0d877d8a43908459a40cc9f846db3ca17 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 21:30:20 -0500 Subject: [PATCH 24/27] removed TestCase and WebTestCase. --- build/controllers/ClassmapController.php | 3 --- framework/yii/classes.php | 13 ++++++++++++ framework/yii/test/TestCase.php | 25 ----------------------- framework/yii/test/WebTestCase.php | 25 ----------------------- tests/unit/TestCase.php | 7 ++++++- tests/unit/framework/base/ExceptionTest.php | 2 +- tests/unit/framework/helpers/ArrayHelperTest.php | 2 +- tests/unit/framework/helpers/FileHelperTest.php | 2 +- tests/unit/framework/helpers/JsonTest.php | 2 +- tests/unit/framework/helpers/StringHelperTest.php | 4 ++-- tests/unit/framework/helpers/VarDumperTest.php | 4 ++-- 11 files changed, 27 insertions(+), 62 deletions(-) delete mode 100644 framework/yii/test/TestCase.php delete mode 100644 framework/yii/test/WebTestCase.php diff --git a/build/controllers/ClassmapController.php b/build/controllers/ClassmapController.php index 9fd84e8..a0ba886 100644 --- a/build/controllers/ClassmapController.php +++ b/build/controllers/ClassmapController.php @@ -46,10 +46,7 @@ class ClassmapController extends Controller 'except' => [ 'Yii.php', 'BaseYii.php', - '/debug/', '/console/', - '/test/', - '/gii/', ], ]; $files = FileHelper::findFiles($root, $options); diff --git a/framework/yii/classes.php b/framework/yii/classes.php index c89e4ff..9f39ee9 100644 --- a/framework/yii/classes.php +++ b/framework/yii/classes.php @@ -76,8 +76,12 @@ return [ 'yii\data\Pagination' => YII_PATH . '/data/Pagination.php', 'yii\data\Sort' => YII_PATH . '/data/Sort.php', 'yii\db\ActiveQuery' => YII_PATH . '/db/ActiveQuery.php', + 'yii\db\ActiveQueryInterface' => YII_PATH . '/db/ActiveQueryInterface.php', + 'yii\db\ActiveQueryTrait' => YII_PATH . '/db/ActiveQueryTrait.php', 'yii\db\ActiveRecord' => YII_PATH . '/db/ActiveRecord.php', 'yii\db\ActiveRelation' => YII_PATH . '/db/ActiveRelation.php', + 'yii\db\ActiveRelationInterface' => YII_PATH . '/db/ActiveRelationInterface.php', + 'yii\db\ActiveRelationTrait' => YII_PATH . '/db/ActiveRelationTrait.php', 'yii\db\ColumnSchema' => YII_PATH . '/db/ColumnSchema.php', 'yii\db\Command' => YII_PATH . '/db/Command.php', 'yii\db\Connection' => YII_PATH . '/db/Connection.php', @@ -87,6 +91,8 @@ return [ 'yii\db\Migration' => YII_PATH . '/db/Migration.php', 'yii\db\Query' => YII_PATH . '/db/Query.php', 'yii\db\QueryBuilder' => YII_PATH . '/db/QueryBuilder.php', + 'yii\db\QueryInterface' => YII_PATH . '/db/QueryInterface.php', + 'yii\db\QueryTrait' => YII_PATH . '/db/QueryTrait.php', 'yii\db\Schema' => YII_PATH . '/db/Schema.php', 'yii\db\StaleObjectException' => YII_PATH . '/db/StaleObjectException.php', 'yii\db\TableSchema' => YII_PATH . '/db/TableSchema.php', @@ -149,6 +155,10 @@ return [ 'yii\log\FileTarget' => YII_PATH . '/log/FileTarget.php', 'yii\log\Logger' => YII_PATH . '/log/Logger.php', 'yii\log\Target' => YII_PATH . '/log/Target.php', + 'yii\mail\BaseMailer' => YII_PATH . '/mail/BaseMailer.php', + 'yii\mail\BaseMessage' => YII_PATH . '/mail/BaseMessage.php', + 'yii\mail\MailerInterface' => YII_PATH . '/mail/MailerInterface.php', + 'yii\mail\MessageInterface' => YII_PATH . '/mail/MessageInterface.php', 'yii\mutex\DbMutex' => YII_PATH . '/mutex/DbMutex.php', 'yii\mutex\FileMutex' => YII_PATH . '/mutex/FileMutex.php', 'yii\mutex\Mutex' => YII_PATH . '/mutex/Mutex.php', @@ -161,6 +171,8 @@ return [ 'yii\redis\Connection' => YII_PATH . '/redis/Connection.php', 'yii\redis\Transaction' => YII_PATH . '/redis/Transaction.php', 'yii\requirements\YiiRequirementChecker' => YII_PATH . '/requirements/YiiRequirementChecker.php', + 'yii\test\DbFixtureManager' => YII_PATH . '/test/DbFixtureManager.php', + 'yii\test\DbTestTrait' => YII_PATH . '/test/DbTestTrait.php', 'yii\validators\BooleanValidator' => YII_PATH . '/validators/BooleanValidator.php', 'yii\validators\CompareValidator' => YII_PATH . '/validators/CompareValidator.php', 'yii\validators\DateValidator' => YII_PATH . '/validators/DateValidator.php', @@ -169,6 +181,7 @@ return [ 'yii\validators\ExistValidator' => YII_PATH . '/validators/ExistValidator.php', 'yii\validators\FileValidator' => YII_PATH . '/validators/FileValidator.php', 'yii\validators\FilterValidator' => YII_PATH . '/validators/FilterValidator.php', + 'yii\validators\ImageValidator' => YII_PATH . '/validators/ImageValidator.php', 'yii\validators\InlineValidator' => YII_PATH . '/validators/InlineValidator.php', 'yii\validators\NumberValidator' => YII_PATH . '/validators/NumberValidator.php', 'yii\validators\PunycodeAsset' => YII_PATH . '/validators/PunycodeAsset.php', diff --git a/framework/yii/test/TestCase.php b/framework/yii/test/TestCase.php deleted file mode 100644 index a6806b3..0000000 --- a/framework/yii/test/TestCase.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -abstract class TestCase extends \PHPUnit_Framework_TestCase -{ -} diff --git a/framework/yii/test/WebTestCase.php b/framework/yii/test/WebTestCase.php deleted file mode 100644 index 4308454..0000000 --- a/framework/yii/test/WebTestCase.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -abstract class WebTestCase extends \PHPUnit_Extensions_SeleniumTestCase -{ -} diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php index d3ac557..e83605e 100644 --- a/tests/unit/TestCase.php +++ b/tests/unit/TestCase.php @@ -2,10 +2,15 @@ namespace yiiunit; +require_once('PHPUnit/Runner/Version.php'); +spl_autoload_unregister(['Yii', 'autoload']); +require_once('PHPUnit/Autoload.php'); +spl_autoload_register(['Yii', 'autoload']); // put yii's autoloader at the end + /** * This is the base class for all yii framework unit tests. */ -abstract class TestCase extends \yii\test\TestCase +abstract class TestCase extends \PHPUnit_Framework_TestCase { public static $params; diff --git a/tests/unit/framework/base/ExceptionTest.php b/tests/unit/framework/base/ExceptionTest.php index af4293a..5a623b1 100644 --- a/tests/unit/framework/base/ExceptionTest.php +++ b/tests/unit/framework/base/ExceptionTest.php @@ -1,7 +1,7 @@ Date: Sat, 16 Nov 2013 21:30:34 -0500 Subject: [PATCH 25/27] doc fix. --- framework/yii/base/Application.php | 3 ++- framework/yii/db/ActiveRelation.php | 3 --- framework/yii/web/Request.php | 1 - framework/yii/web/Session.php | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index b729158..0af586c 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -31,7 +31,8 @@ use yii\web\HttpException; * @property \yii\web\UrlManager $urlManager The URL manager for this application. This property is read-only. * @property string $vendorPath The directory that stores vendor files. Defaults to "vendor" directory under * [[basePath]]. - * @property View $view The view object that is used to render various view files. This property is read-only. + * @property View|\yii\web\View $view The view object that is used to render various view files. This property + * is read-only. * * @author Qiang Xue * @since 2.0 diff --git a/framework/yii/db/ActiveRelation.php b/framework/yii/db/ActiveRelation.php index ea9b87a..b016c5c 100644 --- a/framework/yii/db/ActiveRelation.php +++ b/framework/yii/db/ActiveRelation.php @@ -20,9 +20,6 @@ namespace yii\db; * * If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method. * - * @property array|ActiveRelation $via the query associated with the pivot table. Please call [[via()]] - * or [[viaTable()]] to set this property instead of directly setting it. - * * @author Qiang Xue * @author Carsten Brandt * @since 2.0 diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index 9e525fd..0b49730 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -35,7 +35,6 @@ use yii\helpers\Security; * @property string $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned * if no such header is sent. This property is read-only. * @property array $delete The DELETE request parameter values. This property is read-only. - * @property array $get The GET request parameter values. This property is read-only. * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. * `http://www.yiiframework.com`). * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only. diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php index 9fba49a..894d75d 100644 --- a/framework/yii/web/Session.php +++ b/framework/yii/web/Session.php @@ -46,7 +46,7 @@ use yii\base\InvalidParamException; * call methods such as [[setFlash()]], [[getFlash()]]. * * @property array $allFlashes Flash messages (key => message). This property is read-only. - * @property array $cookieParams The session cookie parameters. + * @property array $cookieParams The session cookie parameters. This property is read-only. * @property integer $count The number of session variables. This property is read-only. * @property string $flash The key identifying the flash message. Note that flash messages and normal session * variables share the same name space. If you have a normal session variable using the same name, its value will From 684ee633f7d81afdb67ea16dffb9684fb51f85e6 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 16 Nov 2013 23:38:04 -0500 Subject: [PATCH 26/27] removed unneeded check. --- 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 2ef4ead..48d4f05 100644 --- a/framework/yii/base/Component.php +++ b/framework/yii/base/Component.php @@ -452,7 +452,7 @@ class Component extends Object $event->data = $handler[1]; call_user_func($handler[0], $event); // stop further handling if the event is handled - if ($event instanceof Event && $event->handled) { + if ($event->handled) { return; } } From a2fe1284551c5823e29559bce24504ec21ec0f29 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 17 Nov 2013 00:02:27 -0500 Subject: [PATCH 27/27] refactored query and relation. --- framework/yii/db/ActiveQuery.php | 4 ++-- framework/yii/db/ActiveQueryTrait.php | 12 +++++++----- framework/yii/db/ActiveRelationTrait.php | 7 +++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php index 4d21fbe..517bf22 100644 --- a/framework/yii/db/ActiveQuery.php +++ b/framework/yii/db/ActiveQuery.php @@ -68,7 +68,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface if (!empty($rows)) { $models = $this->createModels($rows); if (!empty($this->with)) { - $this->populateRelations($models, $this->with); + $this->findWith($this->with, $models); } return $models; } else { @@ -98,7 +98,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface } if (!empty($this->with)) { $models = [$model]; - $this->populateRelations($models, $this->with); + $this->findWith($this->with, $models); $model = $models[0]; } return $model; diff --git a/framework/yii/db/ActiveQueryTrait.php b/framework/yii/db/ActiveQueryTrait.php index 51135d8..7aae6e6 100644 --- a/framework/yii/db/ActiveQueryTrait.php +++ b/framework/yii/db/ActiveQueryTrait.php @@ -21,7 +21,7 @@ trait ActiveQueryTrait */ public $modelClass; /** - * @var array list of relations that this query should be performed with + * @var array a list of relations that this query should be performed with */ public $with; /** @@ -143,10 +143,12 @@ trait ActiveQueryTrait } /** - * @param ActiveRecord[] $models - * @param array $with + * Finds records corresponding to one or multiple relations and populates them into the primary models. + * @param array $with a list of relations that this query should be performed with. Please + * refer to [[with()]] for details about specifying this parameter. + * @param ActiveRecord[] $models the primary models */ - private function populateRelations(&$models, $with) + public function findWith($with, &$models) { $primaryModel = new $this->modelClass; $relations = $this->normalizeRelations($primaryModel, $with); @@ -155,7 +157,7 @@ trait ActiveQueryTrait // inherit asArray from primary query $relation->asArray = $this->asArray; } - $relation->findWith($name, $models); + $relation->populateRelation($name, $models); } } diff --git a/framework/yii/db/ActiveRelationTrait.php b/framework/yii/db/ActiveRelationTrait.php index 27963d0..be42eb6 100644 --- a/framework/yii/db/ActiveRelationTrait.php +++ b/framework/yii/db/ActiveRelationTrait.php @@ -73,13 +73,12 @@ trait ActiveRelationTrait /** * Finds the related records and populates them into the primary models. - * This method is internally used by [[ActiveQuery]]. Do not call it directly. * @param string $name the relation name * @param array $primaryModels primary models * @return array the related models - * @throws InvalidConfigException + * @throws InvalidConfigException if [[link]] is invalid */ - public function findWith($name, &$primaryModels) + public function populateRelation($name, &$primaryModels) { if (!is_array($this->link)) { throw new InvalidConfigException('Invalid link: it must be an array of key-value pairs.'); @@ -96,7 +95,7 @@ trait ActiveRelationTrait /** @var ActiveRelationTrait $viaQuery */ list($viaName, $viaQuery) = $this->via; $viaQuery->primaryModel = null; - $viaModels = $viaQuery->findWith($viaName, $primaryModels); + $viaModels = $viaQuery->populateRelation($viaName, $primaryModels); $this->filterByModels($viaModels); } else { $this->filterByModels($primaryModels);