Browse Source

Merge branch 'hotfix/travis-memcached' into develop

tags/2.0.0-beta
Panagiotis Moustafellos 11 years ago
parent
commit
315af43e84
  1. 3
      .gitignore
  2. 14
      .travis.yml
  3. 2
      apps/advanced/README.md
  4. 8
      apps/advanced/backend/config/main.php
  5. 30
      apps/advanced/backend/controllers/SiteController.php
  6. 29
      apps/advanced/backend/views/site/error.php
  7. 12
      apps/advanced/environments/dev/backend/config/main-local.php
  8. 2
      apps/advanced/environments/dev/backend/web/index.php
  9. 12
      apps/advanced/environments/dev/frontend/config/main-local.php
  10. 3
      apps/advanced/environments/dev/frontend/web/index.php
  11. 1
      apps/advanced/environments/dev/yii
  12. 2
      apps/advanced/environments/prod/backend/web/index.php
  13. 3
      apps/advanced/environments/prod/frontend/web/index.php
  14. 1
      apps/advanced/environments/prod/yii
  15. 9
      apps/advanced/frontend/config/main.php
  16. 26
      apps/advanced/frontend/controllers/SiteController.php
  17. 29
      apps/advanced/frontend/views/site/error.php
  18. 2
      apps/basic/README.md
  19. 7
      apps/basic/config/web.php
  20. 22
      apps/basic/controllers/SiteController.php
  21. 2
      apps/basic/views/layouts/main.php
  22. 41
      apps/basic/views/site/login.php
  23. 2
      apps/benchmark/README.md
  24. 328
      build/controllers/PhpDocController.php
  25. 102
      docs/guide/active-record.md
  26. 9
      docs/guide/bootstrap-widgets.md
  27. 17
      docs/guide/database-basics.md
  28. 18
      docs/guide/overview.md
  29. 3
      docs/guide/template.md
  30. 188
      docs/guide/validation.md
  31. 28
      extensions/mutex/yii/mutex/FileMutex.php
  32. 1
      extensions/mutex/yii/mutex/Mutex.php
  33. 4
      extensions/mutex/yii/mutex/MysqlMutex.php
  34. 41
      framework/yii/YiiBase.php
  35. 6
      framework/yii/assets/yii.js
  36. 3
      framework/yii/base/Action.php
  37. 20
      framework/yii/base/Application.php
  38. 58
      framework/yii/base/Component.php
  39. 10
      framework/yii/base/Controller.php
  40. 2
      framework/yii/base/Formatter.php
  41. 75
      framework/yii/base/Model.php
  42. 28
      framework/yii/base/Module.php
  43. 27
      framework/yii/base/Object.php
  44. 4
      framework/yii/base/Request.php
  45. 1
      framework/yii/base/Theme.php
  46. 3
      framework/yii/base/View.php
  47. 5
      framework/yii/base/Widget.php
  48. 6
      framework/yii/bootstrap/Nav.php
  49. 1
      framework/yii/caching/Cache.php
  50. 2
      framework/yii/caching/ChainedDependency.php
  51. 2
      framework/yii/caching/Dependency.php
  52. 31
      framework/yii/caching/FileCache.php
  53. 6
      framework/yii/caching/MemCache.php
  54. 2
      framework/yii/caching/RedisCache.php
  55. 2
      framework/yii/captcha/CaptchaAction.php
  56. 2
      framework/yii/captcha/CaptchaValidator.php
  57. 2
      framework/yii/console/Application.php
  58. 3
      framework/yii/console/Request.php
  59. 3
      framework/yii/console/controllers/AssetController.php
  60. 2
      framework/yii/console/controllers/HelpController.php
  61. 7
      framework/yii/data/ActiveDataProvider.php
  62. 5
      framework/yii/data/ArrayDataProvider.php
  63. 11
      framework/yii/data/DataProvider.php
  64. 17
      framework/yii/data/Pagination.php
  65. 5
      framework/yii/data/Sort.php
  66. 8
      framework/yii/db/ActiveQuery.php
  67. 70
      framework/yii/db/ActiveRecord.php
  68. 14
      framework/yii/db/ActiveRelation.php
  69. 45
      framework/yii/db/Command.php
  70. 20
      framework/yii/db/Connection.php
  71. 14
      framework/yii/db/DataReader.php
  72. 8
      framework/yii/db/Exception.php
  73. 4
      framework/yii/db/Migration.php
  74. 4
      framework/yii/db/Query.php
  75. 41
      framework/yii/db/QueryBuilder.php
  76. 31
      framework/yii/db/Schema.php
  77. 8
      framework/yii/db/TableSchema.php
  78. 3
      framework/yii/db/Transaction.php
  79. 117
      framework/yii/db/cubrid/QueryBuilder.php
  80. 259
      framework/yii/db/cubrid/Schema.php
  81. 1
      framework/yii/db/mssql/QueryBuilder.php
  82. 5
      framework/yii/db/mssql/Schema.php
  83. 23
      framework/yii/db/mssql/TableSchema.php
  84. 3
      framework/yii/db/mysql/QueryBuilder.php
  85. 4
      framework/yii/db/mysql/Schema.php
  86. 3
      framework/yii/db/pgsql/QueryBuilder.php
  87. 33
      framework/yii/db/pgsql/Schema.php
  88. 9
      framework/yii/db/redis/Connection.php
  89. 4
      framework/yii/db/redis/Transaction.php
  90. 1
      framework/yii/db/sqlite/QueryBuilder.php
  91. 8
      framework/yii/db/sqlite/Schema.php
  92. 2
      framework/yii/debug/LogTarget.php
  93. 2
      framework/yii/debug/Module.php
  94. 5
      framework/yii/debug/Panel.php
  95. 1
      framework/yii/debug/assets/main.css
  96. 4
      framework/yii/gii/CodeFile.php
  97. 28
      framework/yii/gii/Generator.php
  98. 5
      framework/yii/gii/assets/gii.js
  99. 35
      framework/yii/gii/controllers/DefaultController.php
  100. 2
      framework/yii/gii/generators/controller/Generator.php
  101. Some files were not shown because too many files have changed in this diff Show More

3
.gitignore vendored

@ -17,3 +17,6 @@ Thumbs.db
# composer itself is not needed # composer itself is not needed
composer.phar composer.phar
# Mac DS_Store Files
.DS_Store

14
.travis.yml

@ -5,14 +5,24 @@ php:
- 5.4 - 5.4
- 5.5 - 5.5
env:
- CUBRID_VERSION=9.1.0
services:
- redis-server
- memcached
before_script: before_script:
- composer self-update && composer --version - composer self-update && composer --version
- composer require satooshi/php-coveralls 0.6.* - composer require satooshi/php-coveralls 0.6.*
- mysql -e 'CREATE DATABASE yiitest;'; - mysql -e 'CREATE DATABASE yiitest;';
- psql -U postgres -c 'CREATE DATABASE yiitest;'; - psql -U postgres -c 'CREATE DATABASE yiitest;';
- tests/unit/data/travis/apc-setup.sh
- tests/unit/data/travis/memcache-setup.sh
- tests/unit/data/travis/cubrid-setup.sh
script: script:
- phpunit --coverage-clover tests/unit/runtime/coveralls/clover.xml - phpunit --coverage-clover tests/unit/runtime/coveralls/clover.xml --verbose --exclude-group mssql,oci,wincache,xcache,zenddata
after_script: after_script:
- php vendor/bin/coveralls - php vendor/bin/coveralls

2
apps/advanced/README.md

@ -74,6 +74,8 @@ You can then install the application using the following command:
php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-advanced php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-advanced
~~~ ~~~
Note that in order to install some dependencies you must have `php_openssl` extension enabled.
### Install from an Archive File ### Install from an Archive File

8
apps/advanced/backend/config/main.php

@ -17,13 +17,16 @@ return array(
'modules' => array( 'modules' => array(
), ),
'components' => array( 'components' => array(
'request' => array(
'enableCsrfValidation' => true,
),
'db' => $params['components.db'], 'db' => $params['components.db'],
'cache' => $params['components.cache'], 'cache' => $params['components.cache'],
'user' => array( 'user' => array(
'class' => 'yii\web\User',
'identityClass' => 'common\models\User', 'identityClass' => 'common\models\User',
), ),
'log' => array( 'log' => array(
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => array( 'targets' => array(
array( array(
'class' => 'yii\log\FileTarget', 'class' => 'yii\log\FileTarget',
@ -31,6 +34,9 @@ return array(
), ),
), ),
), ),
'errorHandler' => array(
'errorAction' => 'site/error',
),
), ),
'params' => $params, 'params' => $params,
); );

30
apps/advanced/backend/controllers/SiteController.php

@ -8,6 +8,36 @@ use common\models\LoginForm;
class SiteController extends Controller class SiteController extends Controller
{ {
public function behaviors()
{
return array(
'access' => array(
'class' => \yii\web\AccessControl::className(),
'rules' => array(
array(
'actions' => array('login'),
'allow' => true,
'roles' => array('?'),
),
array(
'actions' => array('logout', 'index'),
'allow' => true,
'roles' => array('@'),
),
),
),
);
}
public function actions()
{
return array(
'error' => array(
'class' => 'yii\web\ErrorAction',
),
);
}
public function actionIndex() public function actionIndex()
{ {
return $this->render('index'); return $this->render('index');

29
apps/advanced/backend/views/site/error.php

@ -0,0 +1,29 @@
<?php
use yii\helpers\Html;
/**
* @var yii\base\View $this
* @var string $name
* @var string $message
* @var Exception $exception
*/
$this->title = $name;
?>
<div class="site-error">
<h1><?php echo Html::encode($this->title); ?></h1>
<div class="alert alert-danger">
<?php echo nl2br(Html::encode($message)); ?>
</div>
<p>
The above error occurred while the Web server was processing your request.
</p>
<p>
Please contact us if you think this is a server error. Thank you.
</p>
</div>

12
apps/advanced/environments/dev/backend/config/main-local.php

@ -1,17 +1,11 @@
<?php <?php
return array( return array(
'preload' => array(
//'debug',
),
'modules' => array( 'modules' => array(
// 'debug' => array( // 'debug' => array(
// 'class' => 'yii\debug\Module', // 'class' => 'yii\debug\Module',
// ), // ),
), ),
'components' => array(
'log' => array(
'targets' => array(
// array(
// 'class' => 'yii\log\DebugTarget',
// )
),
),
),
); );

2
apps/advanced/environments/dev/backend/web/index.php

@ -1,6 +1,6 @@
<?php <?php
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/autoload.php');
require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php');

12
apps/advanced/environments/dev/frontend/config/main-local.php

@ -1,17 +1,11 @@
<?php <?php
return array( return array(
'preload' => array(
//'debug',
),
'modules' => array( 'modules' => array(
// 'debug' => array( // 'debug' => array(
// 'class' => 'yii\debug\Module', // 'class' => 'yii\debug\Module',
// ), // ),
), ),
'components' => array(
'log' => array(
'targets' => array(
// array(
// 'class' => 'yii\log\DebugTarget',
// )
),
),
),
); );

3
apps/advanced/environments/dev/frontend/web/index.php

@ -1,7 +1,6 @@
<?php <?php
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/autoload.php');
require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php');

1
apps/advanced/environments/dev/yii

@ -9,6 +9,7 @@
*/ */
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// fcgi doesn't have STDIN defined by default // fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));

2
apps/advanced/environments/prod/backend/web/index.php

@ -1,6 +1,6 @@
<?php <?php
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', false); defined('YII_DEBUG') or define('YII_DEBUG', false);
defined('YII_ENV') or define('YII_ENV', 'prod');
require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/autoload.php');
require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php');

3
apps/advanced/environments/prod/frontend/web/index.php

@ -1,7 +1,6 @@
<?php <?php
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', false); defined('YII_DEBUG') or define('YII_DEBUG', false);
defined('YII_ENV') or define('YII_ENV', 'prod');
require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/autoload.php');
require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php');

1
apps/advanced/environments/prod/yii

@ -9,6 +9,7 @@
*/ */
defined('YII_DEBUG') or define('YII_DEBUG', false); defined('YII_DEBUG') or define('YII_DEBUG', false);
defined('YII_ENV') or define('YII_ENV', 'prod');
// fcgi doesn't have STDIN defined by default // fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));

9
apps/advanced/frontend/config/main.php

@ -14,15 +14,19 @@ return array(
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'controllerNamespace' => 'frontend\controllers', 'controllerNamespace' => 'frontend\controllers',
'modules' => array( 'modules' => array(
'gii' => 'yii\gii\Module'
), ),
'components' => array( 'components' => array(
'request' => array(
'enableCsrfValidation' => true,
),
'db' => $params['components.db'], 'db' => $params['components.db'],
'cache' => $params['components.cache'], 'cache' => $params['components.cache'],
'user' => array( 'user' => array(
'class' => 'yii\web\User',
'identityClass' => 'common\models\User', 'identityClass' => 'common\models\User',
), ),
'log' => array( 'log' => array(
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => array( 'targets' => array(
array( array(
'class' => 'yii\log\FileTarget', 'class' => 'yii\log\FileTarget',
@ -30,6 +34,9 @@ return array(
), ),
), ),
), ),
'errorHandler' => array(
'errorAction' => 'site/error',
),
), ),
'params' => $params, 'params' => $params,
); );

26
apps/advanced/frontend/controllers/SiteController.php

@ -12,11 +12,37 @@ use yii\helpers\Security;
class SiteController extends Controller class SiteController extends Controller
{ {
public function behaviors()
{
return array(
'access' => array(
'class' => \yii\web\AccessControl::className(),
'only' => array('login', 'logout', 'signup'),
'rules' => array(
array(
'actions' => array('login', 'signup'),
'allow' => true,
'roles' => array('?'),
),
array(
'actions' => array('logout'),
'allow' => true,
'roles' => array('@'),
),
),
),
);
}
public function actions() public function actions()
{ {
return array( return array(
'error' => array(
'class' => 'yii\web\ErrorAction',
),
'captcha' => array( 'captcha' => array(
'class' => 'yii\captcha\CaptchaAction', 'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
), ),
); );
} }

29
apps/advanced/frontend/views/site/error.php

@ -0,0 +1,29 @@
<?php
use yii\helpers\Html;
/**
* @var yii\base\View $this
* @var string $name
* @var string $message
* @var Exception $exception
*/
$this->title = $name;
?>
<div class="site-error">
<h1><?php echo Html::encode($this->title); ?></h1>
<div class="alert alert-danger">
<?php echo nl2br(Html::encode($message)); ?>
</div>
<p>
The above error occurred while the Web server was processing your request.
</p>
<p>
Please contact us if you think this is a server error. Thank you.
</p>
</div>

2
apps/basic/README.md

@ -56,6 +56,8 @@ php composer.phar create-project --stability=dev yiisoft/yii2-app-basic yii-basi
Now you should be able to access the application using the URL `http://localhost/yii-basic/web/`, Now you should be able to access the application using the URL `http://localhost/yii-basic/web/`,
assuming `yii-basic` is directly under the document root of your Web server. assuming `yii-basic` is directly under the document root of your Web server.
Note that in order to install some dependencies you must have `php_openssl` extension enabled.
### Install from an Archive File ### Install from an Archive File

7
apps/basic/config/web.php

@ -1,9 +1,12 @@
<?php <?php
$params = require(__DIR__ . '/params.php');
$config = array( $config = array(
'id' => 'bootstrap', 'id' => 'bootstrap',
'basePath' => dirname(__DIR__), 'basePath' => dirname(__DIR__),
'components' => array( 'components' => array(
'request' => array(
'enableCsrfValidation' => true,
),
'cache' => array( 'cache' => array(
'class' => 'yii\caching\FileCache', 'class' => 'yii\caching\FileCache',
), ),
@ -23,7 +26,7 @@ $config = array(
), ),
), ),
), ),
'params' => require(__DIR__ . '/params.php'), 'params' => $params,
); );
if (YII_ENV_DEV) { if (YII_ENV_DEV) {

22
apps/basic/controllers/SiteController.php

@ -9,6 +9,28 @@ use app\models\ContactForm;
class SiteController extends Controller class SiteController extends Controller
{ {
public function behaviors()
{
return array(
'access' => array(
'class' => \yii\web\AccessControl::className(),
'only' => array('login', 'logout'),
'rules' => array(
array(
'actions' => array('login'),
'allow' => true,
'roles' => array('?'),
),
array(
'actions' => array('logout'),
'allow' => true,
'roles' => array('@'),
),
),
),
);
}
public function actions() public function actions()
{ {
return array( return array(

2
apps/basic/views/layouts/main.php

@ -36,7 +36,7 @@ app\config\AppAsset::register($this);
array('label' => 'Contact', 'url' => array('/site/contact')), array('label' => 'Contact', 'url' => array('/site/contact')),
Yii::$app->user->isGuest ? Yii::$app->user->isGuest ?
array('label' => 'Login', 'url' => array('/site/login')) : array('label' => 'Login', 'url' => array('/site/login')) :
array('label' => 'Logout (' . Yii::$app->user->identity->username .')' , 'url' => array('/site/logout')), array('label' => 'Logout (' . Html::encode(Yii::$app->user->identity->username) .')' , 'url' => array('/site/logout')),
), ),
)); ));
NavBar::end(); NavBar::end();

41
apps/basic/views/site/login.php

@ -15,20 +15,33 @@ $this->params['breadcrumbs'][] = $this->title;
<p>Please fill out the following fields to login:</p> <p>Please fill out the following fields to login:</p>
<div class="row"> <?php $form = ActiveForm::begin(array(
<div class="col-lg-3"> 'id' => 'login-form',
<?php $form = ActiveForm::begin(array('id' => 'login-form')); ?> 'options' => array('class' => 'form-horizontal'),
<?php echo $form->field($model, 'username'); ?> 'fieldConfig' => array(
<?php echo $form->field($model, 'password')->passwordInput(); ?> 'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?> 'labelOptions' => array('class' => 'col-lg-1 control-label'),
<div class="form-group"> ),
<?php echo Html::submitButton('Login', array('class' => 'btn btn-primary')); ?> )); ?>
</div>
<?php ActiveForm::end(); ?> <?php echo $form->field($model, 'username'); ?>
</div>
<div class="col-lg-5" style="color:#999;margin:1em;padding-top:60px"> <?php echo $form->field($model, 'password')->passwordInput(); ?>
You may login with <strong>admin/admin</strong> or <strong>demo/demo</strong>.<br>
To modify the username/password, please check out the code <code>app\models\User::$users</code>. <?php echo $form->field($model, 'rememberMe', array(
'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
))->checkbox(); ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?php echo Html::submitButton('Login', array('class' => 'btn btn-primary')); ?>
</div> </div>
</div> </div>
<?php ActiveForm::end(); ?>
<div class="col-lg-offset-1" style="color:#999;">
You may login with <strong>admin/admin</strong> or <strong>demo/demo</strong>.<br>
To modify the username/password, please check out the code <code>app\models\User::$users</code>.
</div>
</div> </div>

2
apps/benchmark/README.md

@ -54,3 +54,5 @@ http://localhost/yii-benchmark/index.php/site/hello
In the above, we assume `yii-benchmark` is directly under the document root of your Web server. In the above, we assume `yii-benchmark` is directly under the document root of your Web server.
Note that in order to install some dependencies you must have `php_openssl` extension enabled.

328
build/controllers/PhpDocController.php

@ -0,0 +1,328 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\build\controllers;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* PhpDocController is there to help maintaining PHPDoc annotation in class files
*
* @author Carsten Brandt <mail@cebe.cc>
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class PhpDocController extends Controller
{
public $defaultAction = 'property';
/**
* @var bool whether to update class docs directly. Setting this to false will just output docs
* for copy and paste.
*/
public $updateFiles = true;
/**
* Generates @property annotations in class files from getters and setters
*
* Property description will be taken from getter or setter or from an @property annotation
* in the getters docblock if there is one defined.
*
* See https://github.com/yiisoft/yii2/wiki/Core-framework-code-style#documentation for details.
*
* @param null $root the directory to parse files from. Defaults to YII_PATH.
*/
public function actionProperty($root=null)
{
if ($root === null) {
$root = YII_PATH;
}
$root = FileHelper::normalizePath($root);
$options = array(
'filter' => function ($path) {
if (is_file($path)) {
$file = basename($path);
if ($file[0] < 'A' || $file[0] > 'Z') {
return false;
}
}
return null;
},
'only' => array('.php'),
'except' => array(
'YiiBase.php',
'Yii.php',
'/debug/views/',
'/requirements/',
'/gii/views/',
'/gii/generators/',
),
);
$files = FileHelper::findFiles($root, $options);
$nFilesTotal = 0;
$nFilesUpdated = 0;
foreach ($files as $file) {
$result = $this->generateClassPropertyDocs($file);
if ($result !== false) {
list($className, $phpdoc) = $result;
if ($this->updateFiles) {
if ($this->updateClassPropertyDocs($file, $className, $phpdoc)) {
$nFilesUpdated++;
}
} elseif (!empty($phpdoc)) {
$this->stdout("\n[ " . $file . " ]\n\n", Console::BOLD);
$this->stdout($phpdoc);
}
}
$nFilesTotal++;
}
$this->stdout("\nParsed $nFilesTotal files.\n");
$this->stdout("Updated $nFilesUpdated files.\n");
}
public function globalOptions()
{
return array_merge(parent::globalOptions(), array('updateFiles'));
}
protected function updateClassPropertyDocs($file, $className, $propertyDoc)
{
$ref = new \ReflectionClass($className);
if ($ref->getFileName() != $file) {
$this->stderr("[ERR] Unable to create ReflectionClass for class: $className loaded class is not from file: $file\n", Console::FG_RED);
}
if (!$ref->isSubclassOf('yii\base\Object') && $className != 'yii\base\Object') {
$this->stderr("[INFO] Skipping class $className as it is not a subclass of yii\\base\\Object.\n", Console::FG_BLUE, Console::BOLD);
return false;
}
$oldDoc = $ref->getDocComment();
$newDoc = $this->cleanDocComment($this->updateDocComment($oldDoc, $propertyDoc));
$seenSince = false;
$seenAuthor = false;
// TODO move these checks to different action
$lines = explode("\n", $newDoc);
if (trim($lines[1]) == '*' || substr(trim($lines[1]), 0, 3) == '* @') {
$this->stderr("[WARN] Class $className has no short description.\n", Console::FG_YELLOW, Console::BOLD);
}
foreach($lines as $line) {
if (substr(trim($line), 0, 9) == '* @since ') {
$seenSince = true;
} elseif (substr(trim($line), 0, 10) == '* @author ') {
$seenAuthor = true;
}
}
if (!$seenSince) {
$this->stderr("[ERR] No @since found in class doc in file: $file\n", Console::FG_RED);
}
if (!$seenAuthor) {
$this->stderr("[ERR] No @author found in class doc in file: $file\n", Console::FG_RED);
}
if (trim($oldDoc) != trim($newDoc)) {
$fileContent = explode("\n", file_get_contents($file));
$start = $ref->getStartLine() - 2;
$docStart = $start - count(explode("\n", $oldDoc)) + 1;
$newFileContent = array();
$n = count($fileContent);
for($i = 0; $i < $n; $i++) {
if ($i > $start || $i < $docStart) {
$newFileContent[] = $fileContent[$i];
} else {
$newFileContent[] = trim($newDoc);
$i = $start;
}
}
file_put_contents($file, implode("\n", $newFileContent));
return true;
}
return false;
}
/**
* remove multi empty lines and trim trailing whitespace
*
* @param $doc
* @return string
*/
protected function cleanDocComment($doc)
{
$lines = explode("\n", $doc);
$n = count($lines);
for($i = 0; $i < $n; $i++) {
$lines[$i] = rtrim($lines[$i]);
if (trim($lines[$i]) == '*' && trim($lines[$i + 1]) == '*') {
unset($lines[$i]);
}
}
return implode("\n", $lines);
}
/**
* replace property annotations in doc comment
* @param $doc
* @param $properties
* @return string
*/
protected function updateDocComment($doc, $properties)
{
$lines = explode("\n", $doc);
$propertyPart = false;
$propertyPosition = false;
foreach($lines as $i => $line) {
if (substr(trim($line), 0, 12) == '* @property ') {
$propertyPart = true;
} elseif ($propertyPart && trim($line) == '*') {
$propertyPosition = $i;
$propertyPart = false;
}
if (substr(trim($line), 0, 10) == '* @author ' && $propertyPosition === false) {
$propertyPosition = $i - 1;
$propertyPart = false;
}
if ($propertyPart) {
unset($lines[$i]);
}
}
$finalDoc = '';
foreach($lines as $i => $line) {
$finalDoc .= $line . "\n";
if ($i == $propertyPosition) {
$finalDoc .= $properties;
}
}
return $finalDoc;
}
protected function generateClassPropertyDocs($fileName)
{
$phpdoc = "";
$file = str_replace("\r", "", str_replace("\t", " ", file_get_contents($fileName, true)));
$ns = $this->match('#\nnamespace (?<name>[\w\\\\]+);\n#', $file);
$namespace = reset($ns);
$namespace = $namespace['name'];
$classes = $this->match('#\n(?:abstract )?class (?<name>\w+)( |\n)(extends )?.+\{(?<content>.*)\n\}(\n|$)#', $file);
if (count($classes) > 1) {
$this->stderr("[ERR] There should be only one class in a file: $fileName\n", Console::FG_RED);
return false;
}
if (count($classes) < 1) {
$interfaces = $this->match('#\ninterface (?<name>\w+)\n\{(?<content>.+)\n\}(\n|$)#', $file);
if (count($interfaces) == 1) {
return false;
} elseif (count($interfaces) > 1) {
$this->stderr("[ERR] There should be only one interface in a file: $fileName\n", Console::FG_RED);
} else {
$this->stderr("[ERR] No class in file: $fileName\n", Console::FG_RED);
}
return false;
}
$className = null;
foreach ($classes as &$class) {
$className = $namespace . '\\' . $class['name'];
$gets = $this->match(
'#\* @return (?<type>[\w\\|\\\\\\[\\]]+)(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
'[\s\n]{2,}public function (?<kind>get)(?<name>\w+)\((?:,? ?\$\w+ ?= ?[^,]+)*\)#',
$class['content']);
$sets = $this->match(
'#\* @param (?<type>[\w\\|\\\\\\[\\]]+) \$\w+(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
'[\s\n]{2,}public function (?<kind>set)(?<name>\w+)\(\$\w+(?:, ?\$\w+ ?= ?[^,]+)*\)#',
$class['content']);
// check for @property annotations in getter and setter
$properties = $this->match(
'#\* @(?<kind>property) (?<type>[\w\\|\\\\\\[\\]]+)(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
'[\s\n]{2,}public function [g|s]et(?<name>\w+)\(((?:,? ?\$\w+ ?= ?[^,]+)*|\$\w+(?:, ?\$\w+ ?= ?[^,]+)*)\)#',
$class['content']);
$acrs = array_merge($properties, $gets, $sets);
//print_r($acrs); continue;
$props = array();
foreach ($acrs as &$acr) {
$acr['name'] = lcfirst($acr['name']);
$acr['comment'] = trim(preg_replace('#(^|\n)\s+\*\s?#', '$1 * ', $acr['comment']));
$props[$acr['name']][$acr['kind']] = array(
'type' => $acr['type'],
'comment' => $this->fixSentence($acr['comment']),
);
}
ksort($props);
if (count($props) > 0) {
$phpdoc .= " *\n";
foreach ($props as $propName => &$prop) {
$docline = ' * @';
$docline .= 'property'; // Do not use property-read and property-write as few IDEs support complex syntax.
$note = '';
if (isset($prop['get']) && isset($prop['set'])) {
if ($prop['get']['type'] != $prop['set']['type']) {
$note = ' Note that the type of this property differs in getter and setter.'
. ' See [[get'.ucfirst($propName).'()]] and [[set'.ucfirst($propName).'()]] for details.';
}
} elseif (isset($prop['get'])) {
$note = ' This property is read-only.';
// $docline .= '-read';
} elseif (isset($prop['set'])) {
$note = ' This property is write-only.';
// $docline .= '-write';
} else {
continue;
}
$docline .= ' ' . $this->getPropParam($prop, 'type') . " $$propName ";
$comment = explode("\n", $this->getPropParam($prop, 'comment') . $note);
foreach ($comment as &$cline) {
$cline = ltrim($cline, '* ');
}
$docline = wordwrap($docline . implode(' ', $comment), 110, "\n * ") . "\n";
$phpdoc .= $docline;
}
$phpdoc .= " *\n";
}
}
return array($className, $phpdoc);
}
protected function match($pattern, $subject)
{
$sets = array();
preg_match_all($pattern . 'suU', $subject, $sets, PREG_SET_ORDER);
foreach ($sets as &$set)
foreach ($set as $i => $match)
if (is_numeric($i) /*&& $i != 0*/)
unset($set[$i]);
return $sets;
}
protected function fixSentence($str)
{
// TODO fix word wrap
if ($str == '')
return '';
return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[strlen($str) - 1] != '.' ? '.' : '');
}
protected function getPropParam($prop, $param)
{
return isset($prop['property']) ? $prop['property'][$param] : (isset($prop['get']) ? $prop['get'][$param] : $prop['set'][$param]);
}
}

102
docs/guide/active-record.md

@ -1,17 +1,15 @@
Active Record Active Record
============= =============
ActiveRecord implements the [Active Record design pattern](http://en.wikipedia.org/wiki/Active_record). Active Record implements the [Active Record design pattern](http://en.wikipedia.org/wiki/Active_record).
The idea is that an [[ActiveRecord]] object is associated with a row in a database table and its attributes are mapped The premise behind Active Record is that an individual [[ActiveRecord]] object is associated with a specific row in a database table. The object's attributes are mapped to the columns of the corresponding table. Referencing an Active Record attribute is equivalent to accessing
to the columns of the corresponding table columns. Reading an ActiveRecord attribute is equivalent to accessing the corresponding table column for that record.
the corresponding table column. For example, a `Customer` object is associated with a row in the
`tbl_customer` table, and its `name` attribute is mapped to the `name` column in the `tbl_customer` table. As an example, say that the `Customer` ActiveRecord class is associated with the
To get the value of the `name` column in the table row, you can simply use the expression `$customer->name`, `tbl_customer` table. This would mean that the class's `name` attribute is automatically mapped to the `name` column in `tbl_customer`.
just like reading an object property. Thanks to Active Record, assuming the variable `$customer` is an object of type `Customer`, to get the value of the `name` column for the table row, you can use the expression `$customer->name`. In this example, Active Record is providing an object-oriented interface for accessing data stored in the database. But Active Record provides much more functionality than this.
Instead of writing raw SQL statements to perform database queries, you can call intuitive methods provided With Active Record, instead of writing raw SQL statements to perform database queries, you can call intuitive methods to achieve the same goals. For example, calling [[ActiveRecord::save()|save()]] would perform an INSERT or UPDATE query, creating or updating a row in the associated table of the ActiveRecord class:
by ActiveRecord to achieve the same goals. For example, calling [[ActiveRecord::save()|save()]] would
insert or update a row in the associated table of the ActiveRecord class:
```php ```php
$customer = new Customer(); $customer = new Customer();
@ -24,7 +22,7 @@ Declaring ActiveRecord Classes
------------------------------ ------------------------------
To declare an ActiveRecord class you need to extend [[\yii\db\ActiveRecord]] and To declare an ActiveRecord class you need to extend [[\yii\db\ActiveRecord]] and
implement the `tableName` method like the following: implement the `tableName` method:
```php ```php
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
@ -41,13 +39,19 @@ class Customer extends ActiveRecord
} }
``` ```
Connecting to Database The `tableName` method only has to return the name of the database table associated with the class.
Class instances are obtained in one of two ways:
* Using the `new` operator to create a new, empty object
* Using a method to fetch an existing record (or records) from the database
Connecting to the Database
---------------------- ----------------------
ActiveRecord relies on a [[Connection|DB connection]] to perform the underlying DB operations. ActiveRecord relies on a [[Connection|DB connection]] to perform the underlying DB operations.
By default, it assumes that there is an application component named `db` which gives the needed By default, ActiveRecord assumes that there is an application component named `db` which provides the needed
[[Connection]] instance. Usually this component is configured via application configuration [[Connection]] instance. Usually this component is configured in application configuration file:
like the following:
```php ```php
return array( return array(
@ -62,16 +66,9 @@ return array(
); );
``` ```
Please read the [Database basics](database-basics.md) section to learn more on how to configure Please read the [Database basics](database-basics.md) section to learn more on how to configure and use database connections.
and use database connections.
> Tip: To use a different database connection, you may override the [[ActiveRecord::getDb()]] method.
You may create a base ActiveRecord class and override its [[ActiveRecord::getDb()]] method. You
then extend from this base class for all those ActiveRecord classes that need to use the same
DB connection.
Querying Data from the Database
Querying Data from Database
--------------------------- ---------------------------
There are two ActiveRecord methods for querying data from database: There are two ActiveRecord methods for querying data from database:
@ -79,8 +76,8 @@ There are two ActiveRecord methods for querying data from database:
- [[ActiveRecord::find()]] - [[ActiveRecord::find()]]
- [[ActiveRecord::findBySql()]] - [[ActiveRecord::findBySql()]]
They both return an [[ActiveQuery]] instance which extends from [[Query]] and thus supports Both methods return an [[ActiveQuery]] instance, which extends [[Query]], and thus supports
the same set of flexible and powerful DB query methods. The followings are some examples, the same set of flexible and powerful DB query methods. The following examples demonstrate some of the possibilities.
```php ```php
// to retrieve all *active* customers and order them by their ID: // to retrieve all *active* customers and order them by their ID:
@ -121,27 +118,26 @@ $customers = Customer::find()->indexBy('id')->all();
Accessing Column Data Accessing Column Data
--------------------- ---------------------
ActiveRecord maps each column of the corresponding database table row to an *attribute* in the ActiveRecord ActiveRecord maps each column of the corresponding database table row to an attribute in the ActiveRecord
object. An attribute is like a regular object property whose name is the same as the corresponding column object. The attribute behaves like any regular object public property. The attribute's name will be the same as the corresponding column
name and is case-sensitive. name, and is case-sensitive.
To read the value of a column, you can use the following expression: To read the value of a column, you can use the following syntax:
```php ```php
// "id" is the name of a column in the table associated with $customer ActiveRecord object // "id" and "email" are the names of columns in the table associated with $customer ActiveRecord object
$id = $customer->id; $id = $customer->id;
// or alternatively, $email = $customer->email;
$id = $customer->getAttribute('id');
``` ```
You can get all column values through the [[ActiveRecord::attributes]] property: To change the value of a column, assign a new value to the associated property and save the object:
```php ```
$values = $customer->attributes; $customer->email = 'jane@example.com';
$customer->save();
``` ```
Manipulating Data in the Database
Manipulating Data in Database
----------------------------- -----------------------------
ActiveRecord provides the following methods to insert, update and delete data in the database: ActiveRecord provides the following methods to insert, update and delete data in the database:
@ -156,10 +152,8 @@ ActiveRecord provides the following methods to insert, update and delete data in
- [[ActiveRecord::deleteAll()|deleteAll()]] - [[ActiveRecord::deleteAll()|deleteAll()]]
Note that [[ActiveRecord::updateAll()|updateAll()]], [[ActiveRecord::updateAllCounters()|updateAllCounters()]] Note that [[ActiveRecord::updateAll()|updateAll()]], [[ActiveRecord::updateAllCounters()|updateAllCounters()]]
and [[ActiveRecord::deleteAll()|deleteAll()]] are static methods and apply to the whole database and [[ActiveRecord::deleteAll()|deleteAll()]] are static methods that apply to the whole database
table, while the rest of the methods only apply to the row associated with the ActiveRecord object. table. The other methods only apply to the row associated with the ActiveRecord object through which the method is being called.
The followings are some examples:
```php ```php
// to insert a new customer record // to insert a new customer record
@ -181,12 +175,21 @@ $customer->delete();
Customer::updateAllCounters(array('age' => 1)); Customer::updateAllCounters(array('age' => 1));
``` ```
Notice that you can always use the `save` method, and ActiveRecord will automatically perform an INSERT for new records and an UPDATE for existing ones.
Data Input and Validation
-------------------------
ActiveRecord inherits data validation and data input features from [[\yii\base\Model]]. Data validation is called
automatically when `save()` is performed. If data validation fails, the saving operation will be cancelled.
For more details refer to the [Model](model.md) section of this guide.
Querying Relational Data Querying Relational Data
------------------------ ------------------------
You can use ActiveRecord to query the relational data of a table. The relational data returned can You can use ActiveRecord to also query a table's relational data (i.e., selection of data from Table A can also pull in related data from Table B). Thanks to ActiveRecord, the relational data returned can be accessed like a property of the ActiveRecord object associated with the primary table.
be accessed like a property of the ActiveRecord object associated with the primary table.
For example, with an appropriate relation declaration, by accessing `$customer->orders` you may obtain For example, with an appropriate relation declaration, by accessing `$customer->orders` you may obtain
an array of `Order` objects which represent the orders placed by the specified customer. an array of `Order` objects which represent the orders placed by the specified customer.
@ -405,15 +408,6 @@ The [[link()]] call above will set the `customer_id` of the order to be the prim
value of `$customer` and then call [[save()]] to save the order into database. value of `$customer` and then call [[save()]] to save the order into database.
Data Input and Validation
-------------------------
ActiveRecord inherits data validation and data input features from [[\yii\base\Model]]. Data validation is called
automatically when `save()` is performed. If data validation fails, the saving operation will be cancelled.
For more details refer to the [Model](model.md) section of this guide.
Life Cycles of an ActiveRecord Object Life Cycles of an ActiveRecord Object
------------------------------------- -------------------------------------

9
docs/guide/bootstrap-widgets.md

@ -1,13 +1,12 @@
Bootstrap widgets Bootstrap widgets
================= =================
Yii includes support of [Bootstrap 3](http://getbootstrap.com/) markup and components framework out of the box. It is an Yii includes support for the [Bootstrap 3](http://getbootstrap.com/) markup and components framework out of the box. Bootstrap is an excellent, responsive framework that can greatly speed up your development process.
excellent framework that allows you to speed up development a lot.
Bootstrap is generally about two parts: The core of Bootstrap is represented by two parts:
- Basics such as grid system, typography, helper classes and responsive utilities. - CSS basics, such as grid layout system, typography, helper classes, and responsive utilities.
- Ready to use components such as menus, pagination, modal boxes, tabs etc. - Ready to use components, such as menus, pagination, modal boxes, tabs etc.
Basics Basics
------ ------

17
docs/guide/database-basics.md

@ -2,8 +2,14 @@ Database basics
=============== ===============
Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/manual/en/ref.pdo.php). It provides Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/manual/en/ref.pdo.php). It provides
uniform API and solves some inconsistencies between different DBMS. By default Yii supports MySQL, SQLite, PostgreSQL, uniform API and solves some inconsistencies between different DBMS. By default Yii supports the following DBMS:
Oracle and MSSQL.
- [MySQL](http://www.mysql.com/)
- [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/)
- [CUBRID](http://www.cubrid.org/) (version 9.1.0 and higher).
- Oracle
- MSSQL
Configuration Configuration
@ -22,6 +28,7 @@ return array(
'dsn' => 'mysql:host=localhost;dbname=mydatabase', // MySQL, MariaDB 'dsn' => 'mysql:host=localhost;dbname=mydatabase', // MySQL, MariaDB
//'dsn' => 'sqlite:/path/to/database/file', // SQLite //'dsn' => 'sqlite:/path/to/database/file', // SQLite
//'dsn' => 'pgsql:host=localhost;port=5432;dbname=mydatabase', // PostgreSQL //'dsn' => 'pgsql:host=localhost;port=5432;dbname=mydatabase', // PostgreSQL
//'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', // CUBRID
//'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver //'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver
//'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver //'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver
//'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver //'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver
@ -34,8 +41,10 @@ return array(
// ... // ...
); );
``` ```
Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) for more details
on the format of the DSN string.
After the component is configured you can access it using the following syntax: After the connection component is configured you can access it using the following syntax:
```php ```php
$connection = \Yii::$app->db; $connection = \Yii::$app->db;
@ -79,7 +88,7 @@ When only a single row is returned:
```php ```php
$command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=1'); $command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=1');
$post = $command->query(); $post = $command->queryOne();
``` ```
When there are multiple values from the same column: When there are multiple values from the same column:

18
docs/guide/overview.md

@ -1,8 +1,7 @@
What is Yii What is Yii
=========== ===========
Yii is a high-performance, component-based PHP framework for developing Yii is a high-performance, component-based PHP framework for rapidly developing large-scale Web applications. Yii enables maximum reusability in Web
large-scale Web applications rapidly. It enables maximum reusability in Web
programming and can significantly accelerate your Web application development programming and can significantly accelerate your Web application development
process. The name Yii (pronounced `Yee` or `[ji:]`) is an acronym for process. The name Yii (pronounced `Yee` or `[ji:]`) is an acronym for
**Yes It Is!**. **Yes It Is!**.
@ -12,7 +11,7 @@ Requirements
------------ ------------
To run a Yii-powered Web application, you need a Web server that supports To run a Yii-powered Web application, you need a Web server that supports
PHP 5.3.?. PHP 5.3.? or greater.
For developers who want to use Yii, understanding object-oriented For developers who want to use Yii, understanding object-oriented
programming (OOP) is very helpful, because Yii is a pure OOP framework. programming (OOP) is very helpful, because Yii is a pure OOP framework.
@ -31,10 +30,9 @@ management systems (CMS), e-commerce systems, etc.
How does Yii Compare with Other Frameworks? How does Yii Compare with Other Frameworks?
------------------------------------------- -------------------------------------------
- Like most PHP frameworks, Yii is an MVC (Model-View-Controller) framework. - Like most PHP frameworks, Yii is uses the MVC (Model-View-Controller) design approach.
- It is a fullstack framework providing many solutions and components such as logging, session management, caching etc. - Yii is a fullstack framework providing many solutions and components, such as logging, session management, caching etc.
- It has a good balance of simplicity and features. - Yii strikes a good balance between simplicity and features.
- Syntax and overall development usability are taken seriously. - Syntax and overall development usability are taken seriously by the Yii development team.
- Performance is one of the key goals. - Performance is one of the key goals for the Yii framework.
- We are constantly watching other web frameworks out there and getting the best ideas in. Initial Yii release was heavily - The Yii development team is constantly watching what other Web frameworks are doing to see what best practices and features should be incorporated into Yii. The initial Yii release was heavily influenced by Ruby on Rails. Still, no framework or feature is being blindly copied into Yii; all decisions are based upon what's best for Web developers and in keeping with Yii's philosophy.
influenced by Ruby on Rails. Still, we aren't blindly copying anything.

3
docs/guide/template.md

@ -1,8 +1,7 @@
Using template engines Using template engines
====================== ======================
By default Yii uses PHP as template language but you can configure it to be able By default Yii uses PHP as template language, but you can configure it to support other rendering engines, such as [Twig](http://twig.sensiolabs.org/) or [Smarty](http://www.smarty.net/).
to render templates with special engines such as Twig or Smarty.
The component responsible for rendering a view is called `view`. You can add The component responsible for rendering a view is called `view`. You can add
a custom template engines as follows: a custom template engines as follows:

188
docs/guide/validation.md

@ -7,22 +7,176 @@ In order to learn model validation basics please refer to [Model, Validation sub
Standard Yii validators Standard Yii validators
----------------------- -----------------------
- `boolean`: [[BooleanValidator]] Standard Yii validators could be specified using aliases instead of referring to class names. Here's the list of all
- `captcha`: [[CaptchaValidator]] validators budled with Yii with their most useful properties:
- `compare`: [[CompareValidator]]
- `date`: [[DateValidator]] ### `boolean`: [[BooleanValidator]]
- `default`: [[DefaultValueValidator]]
- `double`: [[NumberValidator]] Checks if the attribute value is a boolean value.
- `email`: [[EmailValidator]]
- `exist`: [[ExistValidator]] - `trueValue`, the value representing true status. _(1)_
- `file`: [[FileValidator]] - `falseValue`, the value representing false status. _(0)_
- `filter`: [[FilterValidator]] - `strict`, whether to compare the type of the value and `trueValue`/`falseValue`. _(false)_
- `in`: [[RangeValidator]]
- `integer`: [[NumberValidator]] ### `captcha`: [[CaptchaValidator]]
- `match`: [[RegularExpressionValidator]]
- `required`: [[RequiredValidator]] Validates that the attribute value is the same as the verification code displayed in the CAPTCHA. Should be used together
- `string`: [[StringValidator]] with [[CaptchaAction]].
- `unique`: [[UniqueValidator]]
- `url`: [[UrlValidator]] - `caseSensitive` whether the comparison is case sensitive. _(false)_
- `captchaAction` the route of the controller action that renders the CAPTCHA image. _('site/captcha')_
### `compare`: [[CompareValidator]]
Compares the specified attribute value with another value and validates if they are equal.
- `compareAttribute` the name of the attribute to be compared with. _(currentAttribute_repeat)_
- `compareValue` the constant value to be compared with.
- `operator` the operator for comparison. _('==')_
### `date`: [[DateValidator]]
Verifies if the attribute represents a date, time or datetime in a proper format.
- `format` the date format that the value being validated should follow accodring to [[http://www.php.net/manual/en/datetime.createfromformat.php]]. _('Y-m-d')_
- `timestampAttribute` the name of the attribute to receive the parsing result.
### `default`: [[DefaultValueValidator]]
Sets the attribute to be the specified default value.
- `value` the default value to be set to the specified attributes.
### `double`: [[NumberValidator]]
Validates that the attribute value is a number.
- `max` limit of the number. _(null)_
- `min` lower limit of the number. _(null)_
### `email`: [[EmailValidator]]
Validates that the attribute value is a valid email address.
- `allowName` whether to allow name in the email address (e.g. `John Smith <john.smith@example.com>`). _(false)_.
- `checkMX` whether to check the MX record for the email address. _(false)_
- `checkPort` whether to check port 25 for the email address. _(false)_
- `enableIDN` whether validation process should take into account IDN (internationalized domain names). _(false)_
### `exist`: [[ExistValidator]]
Validates that the attribute value exists in a table.
- `className` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
validated. _(ActiveRecord class of the attribute being validated)_
- `attributeName` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
_(name of the attribute being validated)_
### `file`: [[FileValidator]]
Verifies if an attribute is receiving a valid uploaded file.
- `types` a list of file name extensions that are allowed to be uploaded. _(any)_
- `minSize` the minimum number of bytes required for the uploaded file.
- `maxSize` the maximum number of bytes required for the uploaded file.
- `maxFiles` the maximum file count the given attribute can hold. _(1)_
### `filter`: [[FilterValidator]]
Converts the attribute value according to a filter.
- `filter` PHP callback that defines a filter.
Typically a callback is either the name of PHP function:
```php
array('password', 'filter', 'filter' => 'trim'),
```
Or an anonymous function:
```php
array('text', 'filter', 'filter' => function ($value) {
// here we are removing all swear words from text
return $newValue;
}),
```
### `in`: [[RangeValidator]]
Validates that the attribute value is among a list of values.
- `range` list of valid values that the attribute value should be among.
- `strict` whether the comparison is strict (both type and value must be the same). _(false)_
- `not` whether to invert the validation logic. _(false)_
### `integer`: [[NumberValidator]]
Validates that the attribute value is an integer number.
- `max` limit of the number. _(null)_
- `min` lower limit of the number. _(null)_
### `match`: [[RegularExpressionValidator]]
Validates that the attribute value matches the specified pattern defined by regular expression.
- `pattern` the regular expression to be matched with.
- `not` whether to invert the validation logic. _(false)_
### `required`: [[RequiredValidator]]
Validates that the specified attribute does not have null or empty value.
- `requiredValue` the desired value that the attribute must have. _(any)_
- `strict` whether the comparison between the attribute value and [[requiredValue]] is strict. _(false)_
### `safe`: [[SafeValidator]]
Serves as a dummy validator whose main purpose is to mark the attributes to be safe for massive assignment.
### `string`: [[StringValidator]]
Validates that the attribute value is of certain length.
- `length` specifies the length limit of the value to be validated. Can be `exactly X`, `array(min X)`, `array(min X, max Y)`.
- `max` maximum length. If not set, it means no maximum length limit.
- `min` minimum length. If not set, it means no minimum length limit.
- `encoding` the encoding of the string value to be validated. _([[\yii\base\Application::charset]])_
### `unique`: [[UniqueValidator]]
Validates that the attribute value is unique in the corresponding database table.
- `className` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
validated. _(ActiveRecord class of the attribute being validated)_
- `attributeName` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
_(name of the attribute being validated)_
### `url`: [[UrlValidator]]
Validates that the attribute value is a valid http or https URL.
- `validSchemes` list of URI schemes which should be considered valid. _array('http', 'https')_
- `defaultScheme` the default URI scheme. If the input doesn't contain the scheme part, the default scheme will be
prepended to it. _(null)_
- `enableIDN` whether validation process should take into account IDN (internationalized domain names). _(false)_
Validating values out of model context
--------------------------------------
Sometimes you need to validate a value that is not bound to any model such as email. In Yii `Validator` class has
`validateValue` method that can help you with it. Not all validator classes have it implemented but the ones that can
operate without model do. In our case to validate an email we can do the following:
```php
$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
if ($validator->validateValue($email)) {
echo 'Email is valid.';
} else {
echo 'Email is not valid.'
}
```
TBD: refer to http://www.yiiframework.com/wiki/56/ for the format TBD: refer to http://www.yiiframework.com/wiki/56/ for the format

28
extensions/mutex/yii/mutex/FileMutex.php

@ -9,6 +9,7 @@ namespace yii\mutex;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\FileHelper;
/** /**
* @author resurtm <resurtm@gmail.com> * @author resurtm <resurtm@gmail.com>
@ -18,10 +19,23 @@ class FileMutex extends Mutex
{ {
/** /**
* @var string the directory to store mutex files. You may use path alias here. * @var string the directory to store mutex files. You may use path alias here.
* If not set, it will use the "mutex" subdirectory under the application runtime path. * Defaults to the "mutex" subdirectory under the application runtime path.
*/ */
public $mutexPath = '@runtime/mutex'; public $mutexPath = '@runtime/mutex';
/** /**
* @var integer the permission to be set for newly created mutex files.
* This value will be used by PHP chmod() function. No umask will be applied.
* If not set, the permission will be determined by the current environment.
*/
public $fileMode;
/**
* @var integer the permission to be set for newly created directories.
* This value will be used by PHP chmod() function. No umask will be applied.
* Defaults to 0775, meaning the directory is read-writable by owner and group,
* but read-only for other users.
*/
public $dirMode = 0775;
/**
* @var resource[] stores all opened lock files. Keys are lock names and values are file handles. * @var resource[] stores all opened lock files. Keys are lock names and values are file handles.
*/ */
private $_files = array(); private $_files = array();
@ -39,22 +53,26 @@ class FileMutex extends Mutex
} }
$this->mutexPath = Yii::getAlias($this->mutexPath); $this->mutexPath = Yii::getAlias($this->mutexPath);
if (!is_dir($this->mutexPath)) { if (!is_dir($this->mutexPath)) {
mkdir($this->mutexPath, 0777, true); FileHelper::createDirectory($this->mutexPath, $this->dirMode, true);
} }
} }
/** /**
* This method should be extended by concrete mutex implementations. Acquires lock by given name. * Acquires lock by given name.
* @param string $name of the lock to be acquired. * @param string $name of the lock to be acquired.
* @param integer $timeout to wait for lock to become released. * @param integer $timeout to wait for lock to become released.
* @return boolean acquiring result. * @return boolean acquiring result.
*/ */
protected function acquireLock($name, $timeout = 0) protected function acquireLock($name, $timeout = 0)
{ {
$file = fopen($this->mutexPath . '/' . md5($name) . '.lock', 'w+'); $fileName = $this->mutexPath . '/' . md5($name) . '.lock';
$file = fopen($fileName, 'w+');
if ($file === false) { if ($file === false) {
return false; return false;
} }
if ($this->fileMode !== null) {
@chmod($fileName, $this->fileMode);
}
$waitTime = 0; $waitTime = 0;
while (!flock($file, LOCK_EX | LOCK_NB)) { while (!flock($file, LOCK_EX | LOCK_NB)) {
$waitTime++; $waitTime++;
@ -69,7 +87,7 @@ class FileMutex extends Mutex
} }
/** /**
* This method should be extended by concrete mutex implementations. Releases lock by given name. * Releases lock by given name.
* @param string $name of the lock to be released. * @param string $name of the lock to be released.
* @return boolean release result. * @return boolean release result.
*/ */

1
extensions/mutex/yii/mutex/Mutex.php

@ -45,6 +45,7 @@ abstract class Mutex extends Component
} }
/** /**
* Acquires lock by given name.
* @param string $name of the lock to be acquired. Must be unique. * @param string $name of the lock to be acquired. Must be unique.
* @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return
* false immediately in case lock was already acquired. * false immediately in case lock was already acquired.

4
extensions/mutex/yii/mutex/MysqlMutex.php

@ -29,7 +29,7 @@ class MysqlMutex extends Mutex
} }
/** /**
* This method should be extended by concrete mutex implementations. Acquires lock by given name. * Acquires lock by given name.
* @param string $name of the lock to be acquired. * @param string $name of the lock to be acquired.
* @param integer $timeout to wait for lock to become released. * @param integer $timeout to wait for lock to become released.
* @return boolean acquiring result. * @return boolean acquiring result.
@ -43,7 +43,7 @@ class MysqlMutex extends Mutex
} }
/** /**
* This method should be extended by concrete mutex implementations. Releases lock by given name. * Releases lock by given name.
* @param string $name of the lock to be released. * @param string $name of the lock to be released.
* @return boolean release result. * @return boolean release result.
* @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock

41
framework/yii/YiiBase.php

@ -100,7 +100,6 @@ class YiiBase
*/ */
public static $objectConfig = array(); public static $objectConfig = array();
private static $_imported = array(); // alias => class name or directory
/** /**
* @return string the version of Yii framework * @return string the version of Yii framework
@ -111,40 +110,6 @@ class YiiBase
} }
/** /**
* Imports a class by its alias.
*
* This method is provided to support autoloading of non-namespaced classes.
* Such a class can be specified in terms of an alias. For example, the alias `@old/code/Sample`
* may represent the `Sample` class under the directory `@old/code` (a path alias).
*
* By importing a class, the class is put in an internal storage such that when
* the class is used for the first time, the class autoloader will be able to
* find the corresponding class file and include it. For this reason, this method
* is much lighter than `include()`.
*
* You may import the same class multiple times. Only the first importing will count.
*
* @param string $alias the class to be imported. This may be either a class alias or a fully-qualified class name.
* If the latter, it will be returned back without change.
* @return string the actual class name that `$alias` refers to
* @throws Exception if the alias is invalid
*/
public static function import($alias)
{
if (strncmp($alias, '@', 1)) {
return $alias;
} else {
$alias = static::getAlias($alias);
if (!isset(self::$_imported[$alias])) {
$className = basename($alias);
self::$_imported[$alias] = $className;
self::$classMap[$className] = $alias . '.php';
}
return self::$_imported[$alias];
}
}
/**
* Imports a set of namespaces. * Imports a set of namespaces.
* *
* By importing a namespace, the method will create an alias for the directory corresponding * By importing a namespace, the method will create an alias for the directory corresponding
@ -370,7 +335,7 @@ class YiiBase
include($classFile); include($classFile);
if (!class_exists($className, false) && !interface_exists($className, false) && if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) &&
(!function_exists('trait_exists') || !trait_exists($className, false))) { (!function_exists('trait_exists') || !trait_exists($className, false))) {
throw new UnknownClassException("Unable to find '$className' in file: $classFile"); throw new UnknownClassException("Unable to find '$className' in file: $classFile");
} }
@ -431,10 +396,6 @@ class YiiBase
throw new InvalidConfigException('Object configuration must be an array containing a "class" element.'); throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
} }
if (!class_exists($class, false)) {
$class = static::import($class);
}
$class = ltrim($class, '\\'); $class = ltrim($class, '\\');
if (isset(self::$objectConfig[$class])) { if (isset(self::$objectConfig[$class])) {

6
framework/yii/assets/yii.js

@ -43,7 +43,13 @@
*/ */
yii = (function ($) { yii = (function ($) {
var pub = { var pub = {
// version of Yii framework
version: '2.0', version: '2.0',
// CSRF token name and value. If this is set and a form is created and submitted using JavaScript
// via POST, the CSRF token should be submitted too to pass CSRF validation.
csrfVar: undefined,
csrfToken: undefined,
initModule: function (module) { initModule: function (module) {
if (module.isActive === undefined || module.isActive) { if (module.isActive === undefined || module.isActive) {
if ($.isFunction(module.init)) { if ($.isFunction(module.init)) {

3
framework/yii/base/Action.php

@ -28,6 +28,9 @@ use Yii;
* And the parameters provided for the action are: `array('id' => 1)`. * And the parameters provided for the action are: `array('id' => 1)`.
* Then the `run()` method will be invoked as `run(1)` automatically. * Then the `run()` method will be invoked as `run(1)` automatically.
* *
* @property string $uniqueId The unique ID of this action among the whole application. This property is
* read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

20
framework/yii/base/Application.php

@ -14,6 +14,24 @@ use yii\web\HttpException;
/** /**
* Application is the base class for all application classes. * Application is the base class for all application classes.
* *
* @property \yii\rbac\Manager $authManager The auth manager for this application. This property is read-only.
* @property \yii\caching\Cache $cache The cache application component. Null if the component is not enabled.
* This property is read-only.
* @property \yii\db\Connection $db The database connection. This property is read-only.
* @property ErrorHandler $errorHandler The error handler application component. This property is read-only.
* @property \yii\base\Formatter $formatter The formatter application component. This property is read-only.
* @property \yii\i18n\I18N $i18N The internationalization component. This property is read-only.
* @property \yii\log\Logger $log The log component. This property is read-only.
* @property \yii\web\Request|\yii\console\Request $request The request component. This property is read-only.
* @property string $runtimePath The directory that stores runtime files. Defaults to the "runtime"
* subdirectory under [[basePath]].
* @property string $timeZone The time zone used by this application.
* @property string $uniqueId The unique ID of the module. This property is read-only.
* @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.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
@ -68,7 +86,7 @@ abstract class Application extends Module
*/ */
public $controller; public $controller;
/** /**
* @var mixed the layout that should be applied for views in this application. Defaults to 'main'. * @var string|boolean the layout that should be applied for views in this application. Defaults to 'main'.
* If this is false, layout will be disabled. * If this is false, layout will be disabled.
*/ */
public $layout = 'main'; public $layout = 'main';

58
framework/yii/base/Component.php

@ -11,6 +11,9 @@ use Yii;
/** /**
* @include @yii/base/Component.md * @include @yii/base/Component.md
*
* @property Behavior[] $behaviors List of behaviors attached to this component. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
@ -35,9 +38,9 @@ class Component extends Object
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `$value = $component->property;`. * will be implicitly called when executing `$value = $component->property;`.
* @param string $name the property name * @param string $name the property name
* @return mixed the property value, event handlers attached to the event, * @return mixed the property value or the value of a behavior's property
* the behavior, or the value of a behavior's property
* @throws UnknownPropertyException if the property is not defined * @throws UnknownPropertyException if the property is not defined
* @throws InvalidCallException if the property is write-only.
* @see __set * @see __set
*/ */
public function __get($name) public function __get($name)
@ -55,7 +58,11 @@ class Component extends Object
} }
} }
} }
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); if (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
} }
/** /**
@ -172,9 +179,8 @@ class Component extends Object
/** /**
* Calls the named method which is not a class method. * Calls the named method which is not a class method.
* If the name refers to a component property whose value is *
* an anonymous function, the method will execute the function. * This method will check if any attached behavior has
* Otherwise, it will check if any attached behavior has
* the named method and will execute it if available. * the named method and will execute it if available.
* *
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
@ -186,17 +192,9 @@ class Component extends Object
*/ */
public function __call($name, $params) public function __call($name, $params)
{ {
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
$func = $this->$getter();
if ($func instanceof \Closure) {
return call_user_func_array($func, $params);
}
}
$this->ensureBehaviors(); $this->ensureBehaviors();
foreach ($this->_behaviors as $object) { foreach ($this->_behaviors as $object) {
if (method_exists($object, $name)) { if ($object->hasMethod($name)) {
return call_user_func_array(array($object, $name), $params); return call_user_func_array(array($object, $name), $params);
} }
} }
@ -261,8 +259,8 @@ class Component extends Object
return true; return true;
} }
} }
return false;
} }
return false;
} }
/** /**
@ -291,8 +289,34 @@ class Component extends Object
return true; return true;
} }
} }
return false;
} }
return false;
}
/**
* Returns a value indicating whether a method is defined.
* A method is defined if:
*
* - the class has a method with the specified name
* - an attached behavior has a method with the given name (when `$checkBehaviors` is true).
*
* @param string $name the property name
* @param boolean $checkBehaviors whether to treat behaviors' methods as methods of this component
* @return boolean whether the property is defined
*/
public function hasMethod($name, $checkBehaviors = true)
{
if (method_exists($this, $name)) {
return true;
} elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->hasMethod($name)) {
return true;
}
}
}
return false;
} }
/** /**

10
framework/yii/base/Controller.php

@ -12,6 +12,16 @@ use Yii;
/** /**
* Controller is the base class for classes containing controller logic. * Controller is the base class for classes containing controller logic.
* *
* @property array $actionParams The request parameters (name-value pairs) to be used for action parameter
* binding. This property is read-only.
* @property string $route The route (module ID, controller ID and action ID) of the current request. This
* property is read-only.
* @property string $uniqueId The controller ID that is prefixed with the module ID (if any). This property is
* read-only.
* @property View $view The view object that can be used to render views or view files.
* @property string $viewPath The directory containing the view files for this controller. This property is
* read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/base/Formatter.php

@ -309,7 +309,7 @@ class Formatter extends Component
/** /**
* Normalizes the given datetime value as one that can be taken by various date/time formatting methods. * Normalizes the given datetime value as one that can be taken by various date/time formatting methods.
* @param mixed $value the datetime value to be normalized. * @param mixed $value the datetime value to be normalized.
* @return mixed the normalized datetime value * @return integer the normalized datetime value
*/ */
protected function normalizeDatetimeValue($value) protected function normalizeDatetimeValue($value)
{ {

75
framework/yii/base/Model.php

@ -36,11 +36,17 @@ use yii\validators\Validator;
* You may directly use Model to store model data, or extend it with customization. * You may directly use Model to store model data, or extend it with customization.
* You may also customize Model by attaching [[ModelBehavior|model behaviors]]. * You may also customize Model by attaching [[ModelBehavior|model behaviors]].
* *
* @property ArrayObject $validators All the validators declared in the model. * @property \yii\validators\Validator[] $activeValidators The validators applicable to the current
* @property array $activeValidators The validators applicable to the current [[scenario]]. * [[scenario]]. This property is read-only.
* @property array $errors Errors for all attributes or the specified attribute. Empty array is returned if no error.
* @property array $attributes Attribute values (name => value). * @property array $attributes Attribute values (name => value).
* @property string $scenario The scenario that this model is in. * @property array $errors An array of errors for all attributes. Empty array is returned if no error. The
* result is a two-dimensional array. See [[getErrors()]] for detailed description. This property is read-only.
* @property array $firstErrors The first errors. An empty array will be returned if there is no error. This
* property is read-only.
* @property ArrayIterator $iterator An iterator for traversing the items in the list. This property is
* read-only.
* @property string $scenario The scenario that this model is in. Defaults to [[DEFAULT_SCENARIO]].
* @property ArrayObject $validators All the validators declared in the model. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -48,6 +54,11 @@ use yii\validators\Validator;
class Model extends Component implements IteratorAggregate, ArrayAccess class Model extends Component implements IteratorAggregate, ArrayAccess
{ {
/** /**
* The name of the default scenario.
*/
const DEFAULT_SCENARIO = 'default';
/**
* @event ModelEvent an event raised at the beginning of [[validate()]]. You may set * @event ModelEvent an event raised at the beginning of [[validate()]]. You may set
* [[ModelEvent::isValid]] to be false to stop the validation. * [[ModelEvent::isValid]] to be false to stop the validation.
*/ */
@ -68,7 +79,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
/** /**
* @var string current scenario * @var string current scenario
*/ */
private $_scenario = 'default'; private $_scenario = self::DEFAULT_SCENARIO;
/** /**
* Returns the validation rules for attributes. * Returns the validation rules for attributes.
@ -105,6 +116,10 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* function validatorName($attribute, $params) * function validatorName($attribute, $params)
* ~~~ * ~~~
* *
* In the above `$attribute` refers to currently validated attribute name while `$params` contains an array of
* validator configuration options such as `max` in case of `length` validator. Currently validate attribute value
* can be accessed as `$this->[$attribute]`.
*
* Yii also provides a set of [[Validator::builtInValidators|built-in validators]]. * Yii also provides a set of [[Validator::builtInValidators|built-in validators]].
* They each has an alias name which can be used when specifying a validation rule. * They each has an alias name which can be used when specifying a validation rule.
* *
@ -153,23 +168,39 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* If an attribute should NOT be massively assigned (thus considered unsafe), * If an attribute should NOT be massively assigned (thus considered unsafe),
* please prefix the attribute with an exclamation character (e.g. '!rank'). * please prefix the attribute with an exclamation character (e.g. '!rank').
* *
* The default implementation of this method will return a 'default' scenario * The default implementation of this method will return all scenarios found in the [[rules()]]
* which corresponds to all attributes listed in the validation rules applicable * declaration. A special scenario named [[DEFAULT_SCENARIO]] will contain all attributes
* to the 'default' scenario. * found in the [[rules()]]. Each scenario will be associated with the attributes that
* are being validated by the validation rules that apply to the scenario.
* *
* @return array a list of scenarios and the corresponding active attributes. * @return array a list of scenarios and the corresponding active attributes.
*/ */
public function scenarios() public function scenarios()
{ {
$attributes = array(); $scenarios = array();
foreach ($this->getActiveValidators() as $validator) { $defaults = array();
foreach ($validator->attributes as $name) { /** @var $validator Validator */
$attributes[$name] = true; foreach ($this->getValidators() as $validator) {
if (empty($validator->on)) {
foreach ($validator->attributes as $attribute) {
$defaults[$attribute] = true;
}
} else {
foreach ($validator->on as $scenario) {
foreach ($validator->attributes as $attribute) {
$scenarios[$scenario][$attribute] = true;
}
}
} }
} }
return array( foreach ($scenarios as $scenario => $attributes) {
'default' => array_keys($attributes), foreach (array_keys($defaults) as $attribute) {
); $attributes[$attribute] = true;
}
$scenarios[$scenario] = array_keys($attributes);
}
$scenarios[self::DEFAULT_SCENARIO] = array_keys($defaults);
return $scenarios;
} }
/** /**
@ -244,8 +275,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* after the actual validation, respectively. If [[beforeValidate()]] returns false, * after the actual validation, respectively. If [[beforeValidate()]] returns false,
* the validation will be cancelled and [[afterValidate()]] will not be called. * the validation will be cancelled and [[afterValidate()]] will not be called.
* *
* Errors found during the validation can be retrieved via [[getErrors()]] * Errors found during the validation can be retrieved via [[getErrors()]],
* and [[getError()]]. * [[getFirstErrors()]] and [[getFirstError()]].
* *
* @param array $attributes list of attributes that should be validated. * @param array $attributes list of attributes that should be validated.
* If this parameter is empty, it means any attribute listed in the applicable * If this parameter is empty, it means any attribute listed in the applicable
@ -423,6 +454,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
/** /**
* Returns the errors for all attribute or a single attribute. * Returns the errors for all attribute or a single attribute.
* @param string $attribute attribute name. Use null to retrieve errors for all attributes. * @param string $attribute attribute name. Use null to retrieve errors for all attributes.
* @property array An array of errors for all attributes. Empty array is returned if no error.
* The result is a two-dimensional array. See [[getErrors()]] for detailed description.
* @return array errors for all attributes or the specified attribute. Empty array is returned if no error. * @return array errors for all attributes or the specified attribute. Empty array is returned if no error.
* Note that when returning errors for all attributes, the result is a two-dimensional array, like the following: * Note that when returning errors for all attributes, the result is a two-dimensional array, like the following:
* *
@ -438,7 +471,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* ) * )
* ~~~ * ~~~
* *
* @see getError * @see getFirstErrors
* @see getFirstError
*/ */
public function getErrors($attribute = null) public function getErrors($attribute = null)
{ {
@ -452,6 +486,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
/** /**
* Returns the first error of every attribute in the model. * Returns the first error of every attribute in the model.
* @return array the first errors. An empty array will be returned if there is no error. * @return array the first errors. An empty array will be returned if there is no error.
* @see getErrors
* @see getFirstError
*/ */
public function getFirstErrors() public function getFirstErrors()
{ {
@ -473,6 +509,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* @param string $attribute attribute name. * @param string $attribute attribute name.
* @return string the error message. Null is returned if no error. * @return string the error message. Null is returned if no error.
* @see getErrors * @see getErrors
* @see getFirstErrors
*/ */
public function getFirstError($attribute) public function getFirstError($attribute)
{ {
@ -581,7 +618,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* Scenario affects how validation is performed and which attributes can * Scenario affects how validation is performed and which attributes can
* be massively assigned. * be massively assigned.
* *
* @return string the scenario that this model is in. Defaults to 'default'. * @return string the scenario that this model is in. Defaults to [[DEFAULT_SCENARIO]].
*/ */
public function getScenario() public function getScenario()
{ {

28
framework/yii/base/Module.php

@ -20,16 +20,16 @@ use Yii;
* [[components|Components]] may be registered with the module so that they are globally * [[components|Components]] may be registered with the module so that they are globally
* accessible within the module. * accessible within the module.
* *
* @property string $uniqueId An ID that uniquely identifies this module among all modules within * @property array $aliases List of path aliases to be defined. The array keys are alias names (must start
* the current application. * with '@') and the array values are the corresponding paths or aliases. See [[setAliases()]] for an example.
* @property string $basePath The root directory of the module. Defaults to the directory containing the module class. * This property is write-only.
* @property string $controllerPath The directory containing the controller classes. Defaults to "[[basePath]]/controllers". * @property string $basePath The root directory of the module.
* @property string $viewPath The directory containing the view files within this module. Defaults to "[[basePath]]/views". * @property array $components The components (indexed by their IDs).
* @property string $layoutPath The directory containing the layout view files within this module. Defaults to "[[viewPath]]/layouts". * @property string $controllerPath The directory that contains the controller classes.
* @property array $modules The configuration of the currently installed modules (module ID => configuration). * @property string $layoutPath The root directory of layout files. Defaults to "[[viewPath]]/layouts".
* @property array $components The components (indexed by their IDs) registered within this module. * @property array $modules The modules (indexed by their IDs).
* @property array $import List of aliases to be imported. This property is write-only. * @property string $uniqueId The unique ID of the module. This property is read-only.
* @property array $aliases List of aliases to be defined. This property is write-only. * @property string $viewPath The root directory of view files. Defaults to "[[basePath]]/view".
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -304,6 +304,9 @@ abstract class Module extends Component
* Defines path aliases. * Defines path aliases.
* This method calls [[Yii::setAlias()]] to register the path aliases. * This method calls [[Yii::setAlias()]] to register the path aliases.
* This method is provided so that you can define path aliases when configuring a module. * This method is provided so that you can define path aliases when configuring a module.
* @property array list of path aliases to be defined. The array keys are alias names
* (must start with '@') and the array values are the corresponding paths or aliases.
* See [[setAliases()]] for an example.
* @param array $aliases list of path aliases to be defined. The array keys are alias names * @param array $aliases list of path aliases to be defined. The array keys are alias names
* (must start with '@') and the array values are the corresponding paths or aliases. * (must start with '@') and the array values are the corresponding paths or aliases.
* For example, * For example,
@ -335,10 +338,9 @@ abstract class Module extends Component
/** /**
* Retrieves the named module. * Retrieves the named module.
* @param string $id module ID (case-sensitive) * @param string $id module ID (case-sensitive).
* @param boolean $load whether to load the module if it is not yet loaded. * @param boolean $load whether to load the module if it is not yet loaded.
* @return Module|null the module instance, null if the module * @return Module|null the module instance, null if the module does not exist.
* does not exist.
* @see hasModule() * @see hasModule()
*/ */
public function getModule($id, $load = true) public function getModule($id, $load = true)

27
framework/yii/base/Object.php

@ -61,8 +61,7 @@ class Object implements Arrayable
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `$value = $object->property;`. * will be implicitly called when executing `$value = $object->property;`.
* @param string $name the property name * @param string $name the property name
* @return mixed the property value, event handlers attached to the event, * @return mixed the property value
* the named behavior, or the value of a behavior's property
* @throws UnknownPropertyException if the property is not defined * @throws UnknownPropertyException if the property is not defined
* @see __set * @see __set
*/ */
@ -71,6 +70,8 @@ class Object implements Arrayable
$getter = 'get' . $name; $getter = 'get' . $name;
if (method_exists($this, $getter)) { if (method_exists($this, $getter)) {
return $this->$getter(); return $this->$getter();
} elseif (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
} else { } else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
} }
@ -142,8 +143,6 @@ class Object implements Arrayable
/** /**
* Calls the named method which is not a class method. * Calls the named method which is not a class method.
* If the name refers to a component property whose value is
* an anonymous function, the method will execute the function.
* *
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
* will be implicitly called when an unknown method is being invoked. * will be implicitly called when an unknown method is being invoked.
@ -154,13 +153,6 @@ class Object implements Arrayable
*/ */
public function __call($name, $params) public function __call($name, $params)
{ {
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
$func = $this->$getter();
if ($func instanceof \Closure) {
return call_user_func_array($func, $params);
}
}
throw new UnknownMethodException('Unknown method: ' . get_class($this) . "::$name()"); throw new UnknownMethodException('Unknown method: ' . get_class($this) . "::$name()");
} }
@ -220,6 +212,19 @@ class Object implements Arrayable
} }
/** /**
* Returns a value indicating whether a method is defined.
*
* The default implementation is a call to php function `method_exists()`.
* You may override this method when you implemented the php magic method `__call()`.
* @param string $name the property name
* @return boolean whether the property is defined
*/
public function hasMethod($name)
{
return method_exists($this, $name);
}
/**
* Converts the object into an array. * Converts the object into an array.
* The default implementation will return all public property values as an array. * The default implementation will return all public property values as an array.
* @return array the array representation of the object * @return array the array representation of the object

4
framework/yii/base/Request.php

@ -8,6 +8,10 @@
namespace yii\base; namespace yii\base;
/** /**
*
* @property boolean $isConsoleRequest The value indicating whether the current request is made via console.
* @property string $scriptFile Entry script file path (processed w/ realpath()).
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

1
framework/yii/base/Theme.php

@ -41,7 +41,6 @@ use yii\helpers\FileHelper;
* that contains the entry script of the application. If your theme is designed to handle modules, * that contains the entry script of the application. If your theme is designed to handle modules,
* you may configure the [[pathMap]] property like described above. * you may configure the [[pathMap]] property like described above.
* *
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

3
framework/yii/base/View.php

@ -21,6 +21,9 @@ use yii\widgets\FragmentCache;
* *
* View provides a set of methods (e.g. [[render()]]) for rendering purpose. * View provides a set of methods (e.g. [[render()]]) for rendering purpose.
* *
* @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application
* component.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

5
framework/yii/base/Widget.php

@ -12,6 +12,11 @@ use Yii;
/** /**
* Widget is the base class for widgets. * Widget is the base class for widgets.
* *
* @property string $id ID of the widget.
* @property View $view The view object that can be used to render views or view files.
* @property string $viewPath The directory containing the view files for this widget. This property is
* read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

6
framework/yii/bootstrap/Nav.php

@ -56,7 +56,7 @@ class Nav extends Widget
{ {
/** /**
* @var array list of items in the nav widget. Each array element represents a single * @var array list of items in the nav widget. Each array element represents a single
* menu item with the following structure: * menu item which can be either a string or an array with the following structure:
* *
* - label: string, required, the nav item label. * - label: string, required, the nav item label.
* - url: optional, the item's URL. Defaults to "#". * - url: optional, the item's URL. Defaults to "#".
@ -66,6 +66,8 @@ class Nav extends Widget
* - active: boolean, optional, whether the item should be on active state or not. * - active: boolean, optional, whether the item should be on active state or not.
* - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget, * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget,
* or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus. * or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus.
*
* If a menu item is a string, it will be rendered directly without HTML encoding.
*/ */
public $items = array(); public $items = array();
/** /**
@ -137,7 +139,7 @@ class Nav extends Widget
/** /**
* Renders a widget's item. * Renders a widget's item.
* @param mixed $item the item to render. * @param string|array $item the item to render.
* @return string the rendering result. * @return string the rendering result.
* @throws InvalidConfigException * @throws InvalidConfigException
*/ */

1
framework/yii/caching/Cache.php

@ -47,7 +47,6 @@ use yii\helpers\StringHelper;
* - [[deleteValue()]]: delete the value with the specified key from cache * - [[deleteValue()]]: delete the value with the specified key from cache
* - [[flushValues()]]: delete all values from cache * - [[flushValues()]]: delete all values from cache
* *
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/caching/ChainedDependency.php

@ -14,8 +14,6 @@ namespace yii\caching;
* considered changed; When [[dependOnAll]] is false, if one of the dependencies has NOT changed, * considered changed; When [[dependOnAll]] is false, if one of the dependencies has NOT changed,
* this dependency is considered NOT changed. * this dependency is considered NOT changed.
* *
* @property boolean $hasChanged Whether the dependency is changed or not.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/caching/Dependency.php

@ -13,8 +13,6 @@ namespace yii\caching;
* Child classes should override its [[generateDependencyData()]] for generating * Child classes should override its [[generateDependencyData()]] for generating
* the actual dependency data. * the actual dependency data.
* *
* @property boolean $hasChanged Whether the dependency has changed.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

31
framework/yii/caching/FileCache.php

@ -8,6 +8,7 @@
namespace yii\caching; namespace yii\caching;
use Yii; use Yii;
use yii\helpers\FileHelper;
/** /**
* FileCache implements a cache component using files. * FileCache implements a cache component using files.
@ -45,6 +46,20 @@ class FileCache extends Cache
* This number should be between 0 and 1000000. A value 0 means no GC will be performed at all. * This number should be between 0 and 1000000. A value 0 means no GC will be performed at all.
**/ **/
public $gcProbability = 10; public $gcProbability = 10;
/**
* @var integer the permission to be set for newly created cache files.
* This value will be used by PHP chmod() function. No umask will be applied.
* If not set, the permission will be determined by the current environment.
*/
public $fileMode;
/**
* @var integer the permission to be set for newly created directories.
* This value will be used by PHP chmod() function. No umask will be applied.
* Defaults to 0775, meaning the directory is read-writable by owner and group,
* but read-only for other users.
*/
public $dirMode = 0775;
/** /**
* Initializes this component by ensuring the existence of the cache path. * Initializes this component by ensuring the existence of the cache path.
@ -54,7 +69,7 @@ class FileCache extends Cache
parent::init(); parent::init();
$this->cachePath = Yii::getAlias($this->cachePath); $this->cachePath = Yii::getAlias($this->cachePath);
if (!is_dir($this->cachePath)) { if (!is_dir($this->cachePath)) {
mkdir($this->cachePath, 0777, true); FileHelper::createDirectory($this->cachePath, $this->dirMode, true);
} }
} }
@ -71,11 +86,7 @@ class FileCache extends Cache
public function exists($key) public function exists($key)
{ {
$cacheFile = $this->getCacheFile($this->buildKey($key)); $cacheFile = $this->getCacheFile($this->buildKey($key));
if (($time = @filemtime($cacheFile)) > time()) { return @filemtime($cacheFile) > time();
return true;
} else {
return false;
}
} }
/** /**
@ -87,7 +98,7 @@ class FileCache extends Cache
protected function getValue($key) protected function getValue($key)
{ {
$cacheFile = $this->getCacheFile($key); $cacheFile = $this->getCacheFile($key);
if (($time = @filemtime($cacheFile)) > time()) { if (@filemtime($cacheFile) > time()) {
return @file_get_contents($cacheFile); return @file_get_contents($cacheFile);
} else { } else {
return false; return false;
@ -112,10 +123,12 @@ class FileCache extends Cache
$cacheFile = $this->getCacheFile($key); $cacheFile = $this->getCacheFile($key);
if ($this->directoryLevel > 0) { if ($this->directoryLevel > 0) {
@mkdir(dirname($cacheFile), 0777, true); @FileHelper::createDirectory(dirname($cacheFile), $this->dirMode, true);
} }
if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) { if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) {
@chmod($cacheFile, 0777); if ($this->fileMode !== null) {
@chmod($cacheFile, $this->fileMode);
}
return @touch($cacheFile, $expire); return @touch($cacheFile, $expire);
} else { } else {
return false; return false;

6
framework/yii/caching/MemCache.php

@ -52,8 +52,10 @@ use yii\base\InvalidConfigException;
* In the above, two memcache servers are used: server1 and server2. You can configure more properties of * In the above, two memcache servers are used: server1 and server2. You can configure more properties of
* each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options. * each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options.
* *
* @property \Memcache|\Memcached $memCache The memcache instance (or memcached if [[useMemcached]] is true) used by this component. * @property \Memcache|\Memcached $memcache The memcache (or memcached) object used by this cache component.
* @property MemCacheServer[] $servers List of memcache server configurations. * This property is read-only.
* @property MemCacheServer[] $servers List of memcache server configurations. Note that the type of this
* property differs in getter and setter. See [[getServers()]] and [[setServers()]] for details.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0

2
framework/yii/caching/RedisCache.php

@ -39,6 +39,8 @@ use yii\db\redis\Connection;
* ) * )
* ~~~ * ~~~
* *
* @property \yii\db\redis\Connection $connection This property is read-only.
*
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/captcha/CaptchaAction.php

@ -29,6 +29,8 @@ use yii\base\InvalidConfigException;
* to be validated by the 'captcha' validator. * to be validated by the 'captcha' validator.
* 3. In the controller view, insert a [[Captcha]] widget in the form. * 3. In the controller view, insert a [[Captcha]] widget in the form.
* *
* @property string $verifyCode The verification code. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/captcha/CaptchaValidator.php

@ -18,6 +18,8 @@ use yii\validators\Validator;
* *
* CaptchaValidator should be used together with [[CaptchaAction]]. * CaptchaValidator should be used together with [[CaptchaAction]].
* *
* @property \yii\captcha\CaptchaAction $captchaAction The action object. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/console/Application.php

@ -45,6 +45,8 @@ use yii\base\InvalidRouteException;
* yii help * yii help
* ~~~ * ~~~
* *
* @property Response $response The response component. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

3
framework/yii/console/Request.php

@ -8,6 +8,9 @@
namespace yii\console; namespace yii\console;
/** /**
*
* @property array $params The command line arguments. It does not include the entry script name.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

3
framework/yii/console/controllers/AssetController.php

@ -28,7 +28,8 @@ use yii\console\Controller;
* Note: by default this command relies on an external tools to perform actual files compression, * Note: by default this command relies on an external tools to perform actual files compression,
* check [[jsCompressor]] and [[cssCompressor]] for more details. * check [[jsCompressor]] and [[cssCompressor]] for more details.
* *
* @property array|\yii\web\AssetManager $assetManager asset manager, which will be used for assets processing. * @property \yii\web\AssetManager $assetManager Asset manager instance. Note that the type of this property
* differs in getter and setter. See [[getAssetManager()]] and [[setAssetManager()]] for details.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0

2
framework/yii/console/controllers/HelpController.php

@ -31,6 +31,8 @@ use yii\helpers\Inflector;
* In the above, if the command name is not provided, all * In the above, if the command name is not provided, all
* available commands will be displayed. * available commands will be displayed.
* *
* @property array $commands All available command names. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

7
framework/yii/data/ActiveDataProvider.php

@ -9,7 +9,6 @@ namespace yii\data;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\base\Model; use yii\base\Model;
use yii\db\Query; use yii\db\Query;
use yii\db\ActiveQuery; use yii\db\ActiveQuery;
@ -49,6 +48,12 @@ use yii\db\Connection;
* $posts = $provider->getModels(); * $posts = $provider->getModels();
* ~~~ * ~~~
* *
* @property integer $count The number of data models in the current page. This property is read-only.
* @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
* uniquely identified by the corresponding key value in this array. This property is read-only.
* @property array $models The list of data models in the current page. This property is read-only.
* @property integer $totalCount Total number of possible data models.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

5
framework/yii/data/ArrayDataProvider.php

@ -47,6 +47,11 @@ use yii\helpers\ArrayHelper;
* Note: if you want to use the sorting feature, you must configure the [[sort]] property * Note: if you want to use the sorting feature, you must configure the [[sort]] property
* so that the provider knows which columns can be sorted. * so that the provider knows which columns can be sorted.
* *
* @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
* uniquely identified by the corresponding key value in this array.
* @property array $models The list of data models in the current page.
* @property integer $totalCount Total number of possible data models.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

11
framework/yii/data/DataProvider.php

@ -16,6 +16,13 @@ use yii\base\InvalidParamException;
* *
* It implements the [[getPagination()]] and [[getSort()]] methods as specified by the [[IDataProvider]] interface. * It implements the [[getPagination()]] and [[getSort()]] methods as specified by the [[IDataProvider]] interface.
* *
* @property integer $count The number of data models in the current page. This property is read-only.
* @property Pagination|boolean $pagination The pagination object. If this is false, it means the pagination
* is disabled. Note that the type of this property differs in getter and setter. See [[getPagination()]] and
* [[setPagination()]] for details.
* @property Sort|boolean $sort The sorting object. If this is false, it means the sorting is disabled. Note
* that the type of this property differs in getter and setter. See [[getSort()]] and [[setSort()]] for details.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
@ -32,7 +39,7 @@ abstract class DataProvider extends Component implements IDataProvider
private $_pagination; private $_pagination;
/** /**
* @return Pagination the pagination object. If this is false, it means the pagination is disabled. * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled.
*/ */
public function getPagination() public function getPagination()
{ {
@ -75,7 +82,7 @@ abstract class DataProvider extends Component implements IDataProvider
} }
/** /**
* @return Sort the sorting object. If this is false, it means the sorting is disabled. * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled.
*/ */
public function getSort() public function getSort()
{ {

17
framework/yii/data/Pagination.php

@ -53,12 +53,13 @@ use yii\base\Object;
* )); * ));
* ~~~ * ~~~
* *
* @property integer $pageCount Number of pages. * @property integer $limit The limit of the data. This may be used to set the LIMIT value for a SQL statement
* @property integer $page The zero-based index of the current page. * for fetching the current page of data. Note that if the page size is infinite, a value -1 will be returned.
* @property integer $offset The offset of the data. This may be used to set the * This property is read-only.
* OFFSET value for a SQL statement for fetching the current page of data. * @property integer $offset The offset of the data. This may be used to set the OFFSET value for a SQL
* @property integer $limit The limit of the data. This may be used to set the * statement for fetching the current page of data. This property is read-only.
* LIMIT value for a SQL statement for fetching the current page of data. * @property integer $page The zero-based current page number.
* @property integer $pageCount Number of pages. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -97,10 +98,10 @@ class Pagination extends Object
*/ */
public $validatePage = true; public $validatePage = true;
/** /**
* @var integer number of items on each page. Defaults to 10. * @var integer number of items on each page. Defaults to 20.
* If it is less than 1, it means the page size is infinite, and thus a single page contains all items. * If it is less than 1, it means the page size is infinite, and thus a single page contains all items.
*/ */
public $pageSize = 10; public $pageSize = 20;
/** /**
* @var integer total number of items. * @var integer total number of items.
*/ */

5
framework/yii/data/Sort.php

@ -65,6 +65,11 @@ use yii\helpers\Inflector;
* sorted by the orders specified by the Sort object. In the view, we show two hyperlinks * sorted by the orders specified by the Sort object. In the view, we show two hyperlinks
* that can lead to pages with the data sorted by the corresponding attributes. * 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.
* @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.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

8
framework/yii/db/ActiveQuery.php

@ -156,6 +156,8 @@ class ActiveQuery extends Query
if ($db === null) { if ($db === null) {
$db = $modelClass::getDb(); $db = $modelClass::getDb();
} }
$params = $this->params;
if ($this->sql === null) { if ($this->sql === null) {
if ($this->from === null) { if ($this->from === null) {
$tableName = $modelClass::tableName(); $tableName = $modelClass::tableName();
@ -164,11 +166,9 @@ class ActiveQuery extends Query
} }
$this->from = array($tableName); $this->from = array($tableName);
} }
/** @var $qb QueryBuilder */ list ($this->sql, $params) = $db->getQueryBuilder()->build($this);
$qb = $db->getQueryBuilder();
$this->sql = $qb->build($this);
} }
return $db->createCommand($this->sql, $this->params); return $db->createCommand($this->sql, $params);
} }
/** /**

70
framework/yii/db/ActiveRecord.php

@ -22,13 +22,16 @@ use yii\helpers\Inflector;
* *
* @include @yii/db/ActiveRecord.md * @include @yii/db/ActiveRecord.md
* *
* @property Connection $db the database connection used by this AR class. * @property array $dirtyAttributes The changed attribute values (name-value pairs). This property is
* @property TableSchema $tableSchema the schema information of the DB table associated with this AR class. * read-only.
* @property array $oldAttributes the old attribute values (name-value pairs). * @property boolean $isNewRecord Whether the record is new and should be inserted when calling [[save()]].
* @property array $dirtyAttributes the changed attribute values (name-value pairs). * @property array $oldAttributes The old attribute values (name-value pairs).
* @property boolean $isNewRecord whether the record is new and should be inserted when calling [[save()]]. * @property mixed $oldPrimaryKey The old primary key value. An array (column name => column value) is
* @property mixed $primaryKey the primary key value. * returned if the primary key is composite or `$asArray` is true. A string is returned otherwise (null will be
* @property mixed $oldPrimaryKey the old primary key value. * returned if the key value is null). This property is read-only.
* @property mixed $primaryKey The primary key value. An array (column name => column value) is returned if
* the primary key is composite or `$asArray` is true. A string is returned otherwise (null will be returned if
* the key value is null). This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -746,21 +749,21 @@ class ActiveRecord extends Model
return false; return false;
} }
$db = static::getDb(); $db = static::getDb();
$transaction = $this->isTransactional(self::OP_INSERT) && $db->getTransaction() === null ? $db->beginTransaction() : null; if ($this->isTransactional(self::OP_INSERT) && $db->getTransaction() === null) {
try { $transaction = $db->beginTransaction();
$result = $this->insertInternal($attributes); try {
if ($transaction !== null) { $result = $this->insertInternal($attributes);
if ($result === false) { if ($result === false) {
$transaction->rollback(); $transaction->rollback();
} else { } else {
$transaction->commit(); $transaction->commit();
} }
} } catch (\Exception $e) {
} catch (\Exception $e) {
if ($transaction !== null) {
$transaction->rollback(); $transaction->rollback();
throw $e;
} }
throw $e; } else {
$result = $this->insertInternal($attributes);
} }
return $result; return $result;
} }
@ -856,21 +859,21 @@ class ActiveRecord extends Model
return false; return false;
} }
$db = static::getDb(); $db = static::getDb();
$transaction = $this->isTransactional(self::OP_UPDATE) && $db->getTransaction() === null ? $db->beginTransaction() : null; if ($this->isTransactional(self::OP_UPDATE) && $db->getTransaction() === null) {
try { $transaction = $db->beginTransaction();
$result = $this->updateInternal($attributes); try {
if ($transaction !== null) { $result = $this->updateInternal($attributes);
if ($result === false) { if ($result === false) {
$transaction->rollback(); $transaction->rollback();
} else { } else {
$transaction->commit(); $transaction->commit();
} }
} } catch (\Exception $e) {
} catch (\Exception $e) {
if ($transaction !== null) {
$transaction->rollback(); $transaction->rollback();
throw $e;
} }
throw $e; } else {
$result = $this->updateInternal($attributes);
} }
return $result; return $result;
} }
@ -886,6 +889,7 @@ class ActiveRecord extends Model
} }
$values = $this->getDirtyAttributes($attributes); $values = $this->getDirtyAttributes($attributes);
if (empty($values)) { if (empty($values)) {
$this->afterSave(false);
return 0; return 0;
} }
$condition = $this->getOldPrimaryKey(true); $condition = $this->getOldPrimaryKey(true);
@ -1007,6 +1011,16 @@ class ActiveRecord extends Model
} }
/** /**
* Sets the value indicating whether the record is new.
* @param boolean $value whether the record is new and should be inserted when calling [[save()]].
* @see getIsNewRecord
*/
public function setIsNewRecord($value)
{
$this->_oldAttributes = $value ? null : $this->_attributes;
}
/**
* Initializes the object. * Initializes the object.
* This method is called at the end of the constructor. * This method is called at the end of the constructor.
* The default implementation will trigger an [[EVENT_INIT]] event. * The default implementation will trigger an [[EVENT_INIT]] event.
@ -1031,16 +1045,6 @@ class ActiveRecord extends Model
} }
/** /**
* Sets the value indicating whether the record is new.
* @param boolean $value whether the record is new and should be inserted when calling [[save()]].
* @see getIsNewRecord
*/
public function setIsNewRecord($value)
{
$this->_oldAttributes = $value ? null : $this->_attributes;
}
/**
* This method is called at the beginning of inserting or updating a record. * This method is called at the beginning of inserting or updating a record.
* The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true, * The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true,
* or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false. * or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false.

14
framework/yii/db/ActiveRelation.php

@ -50,6 +50,16 @@ class ActiveRelation extends ActiveQuery
*/ */
public $via; public $via;
/**
* Clones internal objects.
*/
public function __clone()
{
if (is_object($this->via)) {
// make a clone of "via" object so that the same query object can be reused multiple times
$this->via = clone $this->via;
}
}
/** /**
* Specifies the relation associated with the pivot table. * Specifies the relation associated with the pivot table.
@ -297,7 +307,7 @@ class ActiveRelation extends ActiveQuery
/** @var $primaryModel ActiveRecord */ /** @var $primaryModel ActiveRecord */
$primaryModel = reset($primaryModels); $primaryModel = reset($primaryModels);
$db = $primaryModel->getDb(); $db = $primaryModel->getDb();
$sql = $db->getQueryBuilder()->build($this); list ($sql, $params) = $db->getQueryBuilder()->build($this);
return $db->createCommand($sql, $this->params)->queryAll(); return $db->createCommand($sql, $params)->queryAll();
} }
} }

45
framework/yii/db/Command.php

@ -44,7 +44,9 @@ use yii\caching\Cache;
* *
* To build SELECT SQL statements, please use [[QueryBuilder]] instead. * To build SELECT SQL statements, please use [[QueryBuilder]] instead.
* *
* @property string $sql the SQL statement to be executed * @property string $rawSql The raw SQL with parameter values inserted into the corresponding placeholders in
* [[sql]]. This property is read-only.
* @property string $sql The SQL statement to be executed.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -60,7 +62,7 @@ class Command extends \yii\base\Component
*/ */
public $pdoStatement; public $pdoStatement;
/** /**
* @var mixed the default fetch mode for this command. * @var integer the default fetch mode for this command.
* @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php
*/ */
public $fetchMode = \PDO::FETCH_ASSOC; public $fetchMode = \PDO::FETCH_ASSOC;
@ -102,7 +104,7 @@ class Command extends \yii\base\Component
* Returns the raw SQL by inserting parameter values into the corresponding placeholders in [[sql]]. * Returns the raw SQL by inserting parameter values into the corresponding placeholders in [[sql]].
* Note that the return value of this method should mainly be used for logging purpose. * Note that the return value of this method should mainly be used for logging purpose.
* It is likely that this method returns an invalid SQL due to improper replacement of parameter placeholders. * It is likely that this method returns an invalid SQL due to improper replacement of parameter placeholders.
* @return string the raw SQL * @return string the raw SQL with parameter values inserted into the corresponding placeholders in [[sql]].
*/ */
public function getRawSql() public function getRawSql()
{ {
@ -179,7 +181,7 @@ class Command extends \yii\base\Component
{ {
$this->prepare(); $this->prepare();
if ($dataType === null) { if ($dataType === null) {
$this->pdoStatement->bindParam($name, $value, $this->getPdoType($value)); $this->pdoStatement->bindParam($name, $value, $this->db->schema->getPdoType($value));
} elseif ($length === null) { } elseif ($length === null) {
$this->pdoStatement->bindParam($name, $value, $dataType); $this->pdoStatement->bindParam($name, $value, $dataType);
} elseif ($driverOptions === null) { } elseif ($driverOptions === null) {
@ -206,7 +208,7 @@ class Command extends \yii\base\Component
{ {
$this->prepare(); $this->prepare();
if ($dataType === null) { if ($dataType === null) {
$this->pdoStatement->bindValue($name, $value, $this->getPdoType($value)); $this->pdoStatement->bindValue($name, $value, $this->db->schema->getPdoType($value));
} else { } else {
$this->pdoStatement->bindValue($name, $value, $dataType); $this->pdoStatement->bindValue($name, $value, $dataType);
} }
@ -234,7 +236,7 @@ class Command extends \yii\base\Component
$type = $value[1]; $type = $value[1];
$value = $value[0]; $value = $value[0];
} else { } else {
$type = $this->getPdoType($value); $type = $this->db->schema->getPdoType($value);
} }
$this->pdoStatement->bindValue($name, $value, $type); $this->pdoStatement->bindValue($name, $value, $type);
$this->_params[$name] = $value; $this->_params[$name] = $value;
@ -244,25 +246,6 @@ class Command extends \yii\base\Component
} }
/** /**
* Determines the PDO type for the give PHP data value.
* @param mixed $data the data whose PDO type is to be determined
* @return integer the PDO type
* @see http://www.php.net/manual/en/pdo.constants.php
*/
private function getPdoType($data)
{
static $typeMap = array(
'boolean' => \PDO::PARAM_BOOL,
'integer' => \PDO::PARAM_INT,
'string' => \PDO::PARAM_STR,
'resource' => \PDO::PARAM_LOB,
'NULL' => \PDO::PARAM_NULL,
);
$type = gettype($data);
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
}
/**
* Executes the SQL statement. * Executes the SQL statement.
* This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs. * This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
* No result set will be returned. * No result set will be returned.
@ -312,7 +295,7 @@ class Command extends \yii\base\Component
/** /**
* Executes the SQL statement and returns ALL rows at once. * Executes the SQL statement and returns ALL rows at once.
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return array all rows of the query result. Each array element is an array representing a row of data. * @return array all rows of the query result. Each array element is an array representing a row of data.
* An empty array is returned if the query results in nothing. * An empty array is returned if the query results in nothing.
@ -326,7 +309,7 @@ class Command extends \yii\base\Component
/** /**
* Executes the SQL statement and returns the first row of the result. * Executes the SQL statement and returns the first row of the result.
* This method is best used when only the first row of result is needed for a query. * This method is best used when only the first row of result is needed for a query.
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query * @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
* results in nothing. * results in nothing.
@ -369,7 +352,7 @@ class Command extends \yii\base\Component
/** /**
* Performs the actual DB query of a SQL statement. * Performs the actual DB query of a SQL statement.
* @param string $method method of PDOStatement to be called * @param string $method method of PDOStatement to be called
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return mixed the method execution result * @return mixed the method execution result
* @throws Exception if the query causes any problem * @throws Exception if the query causes any problem
@ -470,7 +453,7 @@ class Command extends \yii\base\Component
* ))->execute(); * ))->execute();
* ~~~ * ~~~
* *
* Not that the values in each row must match the corresponding column names. * Note that the values in each row must match the corresponding column names.
* *
* @param string $table the table that new rows will be inserted into. * @param string $table the table that new rows will be inserted into.
* @param array $columns the column names * @param array $columns the column names
@ -499,7 +482,7 @@ class Command extends \yii\base\Component
* *
* @param string $table the table to be updated. * @param string $table the table to be updated.
* @param array $columns the column data (name => value) to be updated. * @param array $columns the column data (name => value) to be updated.
* @param mixed $condition the condition that will be put in the WHERE part. Please * @param string|array $condition the condition that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify condition. * refer to [[Query::where()]] on how to specify condition.
* @param array $params the parameters to be bound to the command * @param array $params the parameters to be bound to the command
* @return Command the command object itself * @return Command the command object itself
@ -523,7 +506,7 @@ class Command extends \yii\base\Component
* Note that the created command is not executed until [[execute()]] is called. * Note that the created command is not executed until [[execute()]] is called.
* *
* @param string $table the table where the data will be deleted from. * @param string $table the table where the data will be deleted from.
* @param mixed $condition the condition that will be put in the WHERE part. Please * @param string|array $condition the condition that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify condition. * refer to [[Query::where()]] on how to specify condition.
* @param array $params the parameters to be bound to the command * @param array $params the parameters to be bound to the command
* @return Command the command object itself * @return Command the command object itself

20
framework/yii/db/Connection.php

@ -89,13 +89,16 @@ use yii\caching\Cache;
* ) * )
* ~~~ * ~~~
* *
* @property string $driverName Name of the DB driver. This property is read-only.
* @property boolean $isActive Whether the DB connection is established. This property is read-only. * @property boolean $isActive Whether the DB connection is established. This property is read-only.
* @property Transaction $transaction The currently active transaction. Null if no active transaction. * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the
* @property Schema $schema The database schema information for the current connection. * sequence object. This property is read-only.
* @property QueryBuilder $queryBuilder The query builder. * @property QueryBuilder $queryBuilder The query builder for the current DB connection. This property is
* @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the sequence object. * read-only.
* @property string $driverName Name of the DB driver currently being used. * @property Schema $schema The schema information for the database opened by this connection. This property
* @property array $querySummary The statistical results of SQL queries. * is read-only.
* @property Transaction $transaction The currently active transaction. Null if no active transaction. This
* property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -198,7 +201,7 @@ class Connection extends Component
public $queryCache = 'cache'; public $queryCache = 'cache';
/** /**
* @var string the charset used for database connection. The property is only used * @var string the charset used for database connection. The property is only used
* for MySQL and PostgreSQL databases. Defaults to null, meaning using default charset * for MySQL, PostgreSQL and CUBRID databases. Defaults to null, meaning using default charset
* as specified by the database. * as specified by the database.
* *
* Note that if you're using GBK or BIG5 then it's highly recommended to * Note that if you're using GBK or BIG5 then it's highly recommended to
@ -241,6 +244,7 @@ class Connection extends Component
'oci' => 'yii\db\oci\Schema', // Oracle driver 'oci' => 'yii\db\oci\Schema', // Oracle driver
'mssql' => 'yii\db\mssql\Schema', // older MSSQL driver on MS Windows hosts 'mssql' => 'yii\db\mssql\Schema', // older MSSQL driver on MS Windows hosts
'dblib' => 'yii\db\mssql\Schema', // dblib drivers on GNU/Linux (and maybe other OSes) hosts 'dblib' => 'yii\db\mssql\Schema', // dblib drivers on GNU/Linux (and maybe other OSes) hosts
'cubrid' => 'yii\db\cubrid\Schema', // CUBRID
); );
/** /**
* @var Transaction the currently active transaction * @var Transaction the currently active transaction
@ -358,7 +362,7 @@ class Connection extends Component
if ($this->emulatePrepare !== null && constant('PDO::ATTR_EMULATE_PREPARES')) { if ($this->emulatePrepare !== null && constant('PDO::ATTR_EMULATE_PREPARES')) {
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->emulatePrepare); $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->emulatePrepare);
} }
if ($this->charset !== null && in_array($this->getDriverName(), array('pgsql', 'mysql', 'mysqli'))) { if ($this->charset !== null && in_array($this->getDriverName(), array('pgsql', 'mysql', 'mysqli', 'cubrid'))) {
$this->pdo->exec('SET NAMES ' . $this->pdo->quote($this->charset)); $this->pdo->exec('SET NAMES ' . $this->pdo->quote($this->charset));
} }
$this->trigger(self::EVENT_AFTER_OPEN); $this->trigger(self::EVENT_AFTER_OPEN);

14
framework/yii/db/DataReader.php

@ -39,10 +39,10 @@ use yii\base\InvalidCallException;
* [[fetchMode]]. See the [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * [[fetchMode]]. See the [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for more details about possible fetch mode. * for more details about possible fetch mode.
* *
* @property boolean $isClosed whether the reader is closed or not. * @property integer $columnCount The number of columns in the result set. This property is read-only.
* @property integer $rowCount number of rows contained in the result. * @property integer $fetchMode Fetch mode. This property is write-only.
* @property integer $columnCount the number of columns in the result set. * @property boolean $isClosed Whether the reader is closed or not. This property is read-only.
* @property mixed $fetchMode fetch mode used when retrieving the data. * @property integer $rowCount Number of rows contained in the result. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -73,7 +73,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable
* Binds a column to a PHP variable. * Binds a column to a PHP variable.
* When rows of data are being fetched, the corresponding column value * When rows of data are being fetched, the corresponding column value
* will be set in the variable. Note, the fetch mode must include PDO::FETCH_BOUND. * will be set in the variable. Note, the fetch mode must include PDO::FETCH_BOUND.
* @param mixed $column Number of the column (1-indexed) or name of the column * @param integer|string $column Number of the column (1-indexed) or name of the column
* in the result set. If using the column name, be aware that the name * in the result set. If using the column name, be aware that the name
* should match the case of the column, as returned by the driver. * should match the case of the column, as returned by the driver.
* @param mixed $value Name of the PHP variable to which the column will be bound. * @param mixed $value Name of the PHP variable to which the column will be bound.
@ -91,7 +91,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable
/** /**
* Set the default fetch mode for this statement * Set the default fetch mode for this statement
* @param mixed $mode fetch mode * @param integer $mode fetch mode
* @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php
*/ */
public function setFetchMode($mode) public function setFetchMode($mode)
@ -112,7 +112,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable
/** /**
* Returns a single column from the next row of a result set. * Returns a single column from the next row of a result set.
* @param integer $columnIndex zero-based column index * @param integer $columnIndex zero-based column index
* @return mixed the column of the current row, false if no more row available * @return mixed the column of the current row, false if no more rows available
*/ */
public function readColumn($columnIndex) public function readColumn($columnIndex)
{ {

8
framework/yii/db/Exception.php

@ -16,19 +16,19 @@ namespace yii\db;
class Exception extends \yii\base\Exception class Exception extends \yii\base\Exception
{ {
/** /**
* @var mixed the error info provided by a PDO exception. This is the same as returned * @var array the error info provided by a PDO exception. This is the same as returned
* by [PDO::errorInfo](http://www.php.net/manual/en/pdo.errorinfo.php). * by [PDO::errorInfo](http://www.php.net/manual/en/pdo.errorinfo.php).
*/ */
public $errorInfo; public $errorInfo = array();
/** /**
* Constructor. * Constructor.
* @param string $message PDO error message * @param string $message PDO error message
* @param mixed $errorInfo PDO error info * @param array $errorInfo PDO error info
* @param integer $code PDO error code * @param integer $code PDO error code
* @param \Exception $previous The previous exception used for the exception chaining. * @param \Exception $previous The previous exception used for the exception chaining.
*/ */
public function __construct($message, $errorInfo = null, $code = 0, \Exception $previous = null) public function __construct($message, $errorInfo = array(), $code = 0, \Exception $previous = null)
{ {
$this->errorInfo = $errorInfo; $this->errorInfo = $errorInfo;
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);

4
framework/yii/db/Migration.php

@ -162,7 +162,7 @@ class Migration extends \yii\base\Component
* The method will properly escape the column names and bind the values to be updated. * The method will properly escape the column names and bind the values to be updated.
* @param string $table the table to be updated. * @param string $table the table to be updated.
* @param array $columns the column data (name => value) to be updated. * @param array $columns the column data (name => value) to be updated.
* @param mixed $condition the conditions that will be put in the WHERE part. Please * @param array|string $condition the conditions that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify conditions. * refer to [[Query::where()]] on how to specify conditions.
* @param array $params the parameters to be bound to the query. * @param array $params the parameters to be bound to the query.
*/ */
@ -177,7 +177,7 @@ class Migration extends \yii\base\Component
/** /**
* Creates and executes a DELETE SQL statement. * Creates and executes a DELETE SQL statement.
* @param string $table the table where the data will be deleted from. * @param string $table the table where the data will be deleted from.
* @param mixed $condition the conditions that will be put in the WHERE part. Please * @param array|string $condition the conditions that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify conditions. * refer to [[Query::where()]] on how to specify conditions.
* @param array $params the parameters to be bound to the query. * @param array $params the parameters to be bound to the query.
*/ */

4
framework/yii/db/Query.php

@ -149,8 +149,8 @@ class Query extends Component
if ($db === null) { if ($db === null) {
$db = Yii::$app->getDb(); $db = Yii::$app->getDb();
} }
$sql = $db->getQueryBuilder()->build($this); list ($sql, $params) = $db->getQueryBuilder()->build($this);
return $db->createCommand($sql, $this->params); return $db->createCommand($sql, $params);
} }
/** /**

41
framework/yii/db/QueryBuilder.php

@ -55,22 +55,24 @@ class QueryBuilder extends \yii\base\Object
/** /**
* Generates a SELECT SQL statement from a [[Query]] object. * Generates a SELECT SQL statement from a [[Query]] object.
* @param Query $query the [[Query]] object from which the SQL statement will be generated * @param Query $query the [[Query]] object from which the SQL statement will be generated
* @return string the generated SQL statement * @return array the generated SQL statement (the first array element) and the corresponding
* parameters to be bound to the SQL statement (the second array element).
*/ */
public function build($query) public function build($query)
{ {
$params = $query->params;
$clauses = array( $clauses = array(
$this->buildSelect($query->select, $query->distinct, $query->selectOption), $this->buildSelect($query->select, $query->distinct, $query->selectOption),
$this->buildFrom($query->from), $this->buildFrom($query->from),
$this->buildJoin($query->join, $query->params), $this->buildJoin($query->join, $params),
$this->buildWhere($query->where, $query->params), $this->buildWhere($query->where, $params),
$this->buildGroupBy($query->groupBy), $this->buildGroupBy($query->groupBy),
$this->buildHaving($query->having, $query->params), $this->buildHaving($query->having, $params),
$this->buildUnion($query->union, $query->params), $this->buildUnion($query->union, $params),
$this->buildOrderBy($query->orderBy), $this->buildOrderBy($query->orderBy),
$this->buildLimit($query->limit, $query->offset), $this->buildLimit($query->limit, $query->offset),
); );
return implode($this->separator, array_filter($clauses)); return array(implode($this->separator, array_filter($clauses)), $params);
} }
/** /**
@ -132,7 +134,7 @@ class QueryBuilder extends \yii\base\Object
* ))->execute(); * ))->execute();
* ~~~ * ~~~
* *
* Not that the values in each row must match the corresponding column names. * Note that the values in each row must match the corresponding column names.
* *
* @param string $table the table that new rows will be inserted into. * @param string $table the table that new rows will be inserted into.
* @param array $columns the column names * @param array $columns the column names
@ -161,7 +163,7 @@ class QueryBuilder extends \yii\base\Object
* *
* @param string $table the table to be updated. * @param string $table the table to be updated.
* @param array $columns the column data (name => value) to be updated. * @param array $columns the column data (name => value) to be updated.
* @param mixed $condition the condition that will be put in the WHERE part. Please * @param array|string $condition the condition that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify condition. * refer to [[Query::where()]] on how to specify condition.
* @param array $params the binding parameters that will be modified by this method * @param array $params the binding parameters that will be modified by this method
* so that they can be bound to the DB command later. * so that they can be bound to the DB command later.
@ -205,7 +207,7 @@ class QueryBuilder extends \yii\base\Object
* The method will properly escape the table and column names. * The method will properly escape the table and column names.
* *
* @param string $table the table where the data will be deleted from. * @param string $table the table where the data will be deleted from.
* @param mixed $condition the condition that will be put in the WHERE part. Please * @param array|string $condition the condition that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify condition. * refer to [[Query::where()]] on how to specify condition.
* @param array $params the binding parameters that will be modified by this method * @param array $params the binding parameters that will be modified by this method
* so that they can be bound to the DB command later. * so that they can be bound to the DB command later.
@ -459,7 +461,7 @@ class QueryBuilder extends \yii\base\Object
* The sequence will be reset such that the primary key of the next new row inserted * The sequence will be reset such that the primary key of the next new row inserted
* will have the specified value or 1. * will have the specified value or 1.
* @param string $table the name of the table whose primary key sequence will be reset * @param string $table the name of the table whose primary key sequence will be reset
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set, * @param array|string $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1. * the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence * @return string the SQL statement for resetting sequence
* @throws NotSupportedException if this is not supported by the underlying DBMS * @throws NotSupportedException if this is not supported by the underlying DBMS
@ -489,6 +491,7 @@ class QueryBuilder extends \yii\base\Object
* physical types): * physical types):
* *
* - `pk`: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY" * - `pk`: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY"
* - `bigpk`: an auto-incremental primary key type, will be converted into "bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY"
* - `string`: string type, will be converted into "varchar(255)" * - `string`: string type, will be converted into "varchar(255)"
* - `text`: a long string type, will be converted into "text" * - `text`: a long string type, will be converted into "text"
* - `smallint`: a small integer type, will be converted into "smallint(6)" * - `smallint`: a small integer type, will be converted into "smallint(6)"
@ -718,9 +721,11 @@ class QueryBuilder extends \yii\base\Object
} }
foreach ($unions as $i => $union) { foreach ($unions as $i => $union) {
if ($union instanceof Query) { if ($union instanceof Query) {
// save the original parameters so that we can restore them later to prevent from modifying the query object
$originalParams = $union->params;
$union->addParams($params); $union->addParams($params);
$unions[$i] = $this->build($union); list ($unions[$i], $params) = $this->build($union);
$params = $union->params; $union->params = $originalParams;
} }
} }
return "UNION (\n" . implode("\n) UNION (\n", $unions) . "\n)"; return "UNION (\n" . implode("\n) UNION (\n", $unions) . "\n)";
@ -799,7 +804,7 @@ class QueryBuilder extends \yii\base\Object
$parts = array(); $parts = array();
foreach ($condition as $column => $value) { foreach ($condition as $column => $value) {
if (is_array($value)) { // IN condition if (is_array($value)) { // IN condition
$parts[] = $this->buildInCondition('in', array($column, $value), $params); $parts[] = $this->buildInCondition('IN', array($column, $value), $params);
} else { } else {
if (strpos($column, '(') === false) { if (strpos($column, '(') === false) {
$column = $this->db->quoteColumnName($column); $column = $this->db->quoteColumnName($column);
@ -908,11 +913,6 @@ class QueryBuilder extends \yii\base\Object
protected function buildCompositeInCondition($operator, $columns, $values, &$params) protected function buildCompositeInCondition($operator, $columns, $values, &$params)
{ {
foreach ($columns as $i => $column) {
if (strpos($column, '(') === false) {
$columns[$i] = $this->db->quoteColumnName($column);
}
}
$vss = array(); $vss = array();
foreach ($values as $value) { foreach ($values as $value) {
$vs = array(); $vs = array();
@ -927,6 +927,11 @@ class QueryBuilder extends \yii\base\Object
} }
$vss[] = '(' . implode(', ', $vs) . ')'; $vss[] = '(' . implode(', ', $vs) . ')';
} }
foreach ($columns as $i => $column) {
if (strpos($column, '(') === false) {
$columns[$i] = $this->db->quoteColumnName($column);
}
}
return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')'; return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')';
} }

31
framework/yii/db/Schema.php

@ -19,9 +19,12 @@ use yii\caching\GroupDependency;
* *
* Schema represents the database schema information that is DBMS specific. * Schema represents the database schema information that is DBMS specific.
* *
* @property QueryBuilder $queryBuilder the query builder for the DBMS represented by this schema * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the
* @property array $tableNames the names of all tables in this database. * sequence object. This property is read-only.
* @property array $tableSchemas the schema information for all tables in this database. * @property QueryBuilder $queryBuilder The query builder for this connection. This property is read-only.
* @property string[] $tableNames All table names in the database. This property is read-only.
* @property TableSchema[] $tableSchemas The metadata for all tables in the database. Each array element is an
* instance of [[TableSchema]] or its child class. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -32,6 +35,7 @@ abstract class Schema extends Object
* The followings are the supported abstract column data types. * The followings are the supported abstract column data types.
*/ */
const TYPE_PK = 'pk'; const TYPE_PK = 'pk';
const TYPE_BIGPK = 'bigpk';
const TYPE_STRING = 'string'; const TYPE_STRING = 'string';
const TYPE_TEXT = 'text'; const TYPE_TEXT = 'text';
const TYPE_SMALLINT = 'smallint'; const TYPE_SMALLINT = 'smallint';
@ -213,7 +217,7 @@ abstract class Schema extends Object
* This method should be overridden by child classes in order to support this feature * This method should be overridden by child classes in order to support this feature
* because the default implementation simply throws an exception. * because the default implementation simply throws an exception.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO the schema name prefix. * @return array all table names in the database. The names have NO schema name prefix.
* @throws NotSupportedException if this method is called * @throws NotSupportedException if this method is called
*/ */
protected function findTableNames($schema = '') protected function findTableNames($schema = '')
@ -373,4 +377,23 @@ abstract class Schema extends Object
return 'string'; return 'string';
} }
} }
/**
* Determines the PDO type for the give PHP data value.
* @param mixed $data the data whose PDO type is to be determined
* @return integer the PDO type
* @see http://www.php.net/manual/en/pdo.constants.php
*/
public function getPdoType($data)
{
static $typeMap = array( // php type => PDO type
'boolean' => \PDO::PARAM_BOOL,
'integer' => \PDO::PARAM_INT,
'string' => \PDO::PARAM_STR,
'resource' => \PDO::PARAM_LOB,
'NULL' => \PDO::PARAM_NULL,
);
$type = gettype($data);
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
}
} }

8
framework/yii/db/TableSchema.php

@ -13,7 +13,7 @@ use yii\base\InvalidParamException;
/** /**
* TableSchema represents the metadata of a database table. * TableSchema represents the metadata of a database table.
* *
* @property array $columnNames list of column names * @property array $columnNames List of column names. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
@ -21,12 +21,6 @@ use yii\base\InvalidParamException;
class TableSchema extends Object class TableSchema extends Object
{ {
/** /**
* @var string name of the catalog (database) that this table belongs to.
* Defaults to null, meaning no catalog (or the current database).
* This property is only meaningful for MSSQL.
*/
public $catalogName;
/**
* @var string name of the schema that this table belongs to. * @var string name of the schema that this table belongs to.
*/ */
public $schemaName; public $schemaName;

3
framework/yii/db/Transaction.php

@ -29,7 +29,8 @@ use yii\base\InvalidConfigException;
* } * }
* ~~~ * ~~~
* *
* @property boolean $isActive Whether the transaction is active. This property is read-only. * @property boolean $isActive Whether this transaction is active. Only an active transaction can [[commit()]]
* or [[rollback()]]. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0

117
framework/yii/db/cubrid/QueryBuilder.php

@ -0,0 +1,117 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\cubrid;
use yii\base\InvalidParamException;
/**
* QueryBuilder is the query builder for CUBRID databases (version 9.1.x and higher).
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class QueryBuilder extends \yii\db\QueryBuilder
{
/**
* @var array mapping from abstract column types (keys) to physical column types (values).
*/
public $typeMap = array(
Schema::TYPE_PK => 'int NOT NULL AUTO_INCREMENT PRIMARY KEY',
Schema::TYPE_BIGPK => 'bigint NOT NULL AUTO_INCREMENT PRIMARY KEY',
Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_TEXT => 'varchar',
Schema::TYPE_SMALLINT => 'smallint',
Schema::TYPE_INTEGER => 'int',
Schema::TYPE_BIGINT => 'bigint',
Schema::TYPE_FLOAT => 'float(7)',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'blob',
Schema::TYPE_BOOLEAN => 'smallint',
Schema::TYPE_MONEY => 'decimal(19,4)',
);
/**
* Creates a SQL statement for resetting the sequence value of a table's primary key.
* The sequence will be reset such that the primary key of the next new row inserted
* will have the specified value or 1.
* @param string $tableName the name of the table whose primary key sequence will be reset
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
$table = $this->db->getTableSchema($tableName);
if ($table !== null && $table->sequenceName !== null) {
$tableName = $this->db->quoteTableName($tableName);
if ($value === null) {
$key = reset($table->primaryKey);
$value = (int)$this->db->createCommand("SELECT MAX(`$key`) FROM " . $this->db->schema->quoteTableName($tableName))->queryScalar() + 1;
} else {
$value = (int)$value;
}
return "ALTER TABLE " . $this->db->schema->quoteTableName($tableName) . " AUTO_INCREMENT=$value;";
} elseif ($table === null) {
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidParamException("There is not sequence associated with table '$tableName'.");
}
}
/**
* Generates a batch INSERT SQL statement.
* For example,
*
* ~~~
* $connection->createCommand()->batchInsert('tbl_user', array('name', 'age'), array(
* array('Tom', 30),
* array('Jane', 20),
* array('Linda', 25),
* ))->execute();
* ~~~
*
* Note that the values in each row must match the corresponding column names.
*
* @param string $table the table that new rows will be inserted into.
* @param array $columns the column names
* @param array $rows the rows to be batch inserted into the table
* @return string the batch INSERT SQL statement
*/
public function batchInsert($table, $columns, $rows)
{
if (($tableSchema = $this->db->getTableSchema($table)) !== null) {
$columnSchemas = $tableSchema->columns;
} else {
$columnSchemas = array();
}
foreach ($columns as $i => $name) {
$columns[$i] = $this->db->quoteColumnName($name);
}
$values = array();
foreach ($rows as $row) {
$vs = array();
foreach ($row as $i => $value) {
if (!is_array($value) && isset($columnSchemas[$columns[$i]])) {
$value = $columnSchemas[$columns[$i]]->typecast($value);
}
$vs[] = is_string($value) ? $this->db->quoteValue($value) : $value;
}
$values[] = '(' . implode(', ', $vs) . ')';
}
return 'INSERT INTO ' . $this->db->quoteTableName($table)
. ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values);
}
}

259
framework/yii/db/cubrid/Schema.php

@ -0,0 +1,259 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\cubrid;
use yii\db\Expression;
use yii\db\TableSchema;
use yii\db\ColumnSchema;
/**
* Schema is the class for retrieving metadata from a CUBRID database (version 9.1.x and higher).
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Schema extends \yii\db\Schema
{
/**
* @var array mapping from physical column types (keys) to abstract column types (values)
* Please refer to [CUBRID manual](http://www.cubrid.org/manual/91/en/sql/datatype.html) for
* details on data types.
*/
public $typeMap = array(
// Numeric data types
'short' => self::TYPE_SMALLINT,
'smallint' => self::TYPE_SMALLINT,
'int' => self::TYPE_INTEGER,
'integer' => self::TYPE_INTEGER,
'bigint' => self::TYPE_BIGINT,
'numeric' => self::TYPE_DECIMAL,
'decimal' => self::TYPE_DECIMAL,
'float' => self::TYPE_FLOAT,
'real' => self::TYPE_FLOAT,
'double' => self::TYPE_FLOAT,
'double precision' => self::TYPE_FLOAT,
'monetary' => self::TYPE_MONEY,
// Date/Time data types
'date' => self::TYPE_DATE,
'time' => self::TYPE_TIME,
'timestamp' => self::TYPE_TIMESTAMP,
'datetime' => self::TYPE_DATETIME,
// String data types
'char' => self::TYPE_STRING,
'varchar' => self::TYPE_STRING,
'char varying' => self::TYPE_STRING,
'nchar' => self::TYPE_STRING,
'nchar varying' => self::TYPE_STRING,
'string' => self::TYPE_STRING,
// BLOB/CLOB data types
'blob' => self::TYPE_BINARY,
'clob' => self::TYPE_BINARY,
// Bit string data types
'bit' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING,
// Collection data types (considered strings for now)
'set' => self::TYPE_STRING,
'multiset' => self::TYPE_STRING,
'list' => self::TYPE_STRING,
'sequence' => self::TYPE_STRING,
'enum' => self::TYPE_STRING,
);
/**
* Quotes a table name for use in a query.
* A simple table name has no schema prefix.
* @param string $name table name
* @return string the properly quoted table name
*/
public function quoteSimpleTableName($name)
{
return strpos($name, '"') !== false ? $name : '"' . $name . '"';
}
/**
* Quotes a column name for use in a query.
* A simple column name has no prefix.
* @param string $name column name
* @return string the properly quoted column name
*/
public function quoteSimpleColumnName($name)
{
return strpos($name, '"') !== false || $name === '*' ? $name : '"' . $name . '"';
}
/**
* Quotes a string value for use in a query.
* Note that if the parameter is not a string, it will be returned without change.
* @param string $str string to be quoted
* @return string the properly quoted string
* @see http://www.php.net/manual/en/function.PDO-quote.php
*/
public function quoteValue($str)
{
if (!is_string($str)) {
return $str;
}
$this->db->open();
// workaround for broken PDO::quote() implementation in CUBRID 9.1.0 http://jira.cubrid.org/browse/APIS-658
if (version_compare($this->db->pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION), '9.1.0', '<=')) {
return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
} else {
return $this->db->pdo->quote($str);
}
}
/**
* Creates a query builder for the CUBRID database.
* @return QueryBuilder query builder instance
*/
public function createQueryBuilder()
{
return new QueryBuilder($this->db);
}
/**
* Loads the metadata for the specified table.
* @param string $name table name
* @return TableSchema driver dependent table metadata. Null if the table does not exist.
*/
protected function loadTableSchema($name)
{
$this->db->open();
$tableInfo = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name);
if (isset($tableInfo[0]['NAME'])) {
$table = new TableSchema();
$table->name = $tableInfo[0]['NAME'];
$sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name);
$columns = $this->db->createCommand($sql)->queryAll();
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 = '';
}
}
}
$foreignKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name);
foreach($foreignKeys as $key) {
if (isset($table->foreignKeys[$key['FK_NAME']])) {
$table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME'];
} else {
$table->foreignKeys[$key['FK_NAME']] = array(
$key['PKTABLE_NAME'],
$key['FKCOLUMN_NAME'] => $key['PKCOLUMN_NAME']
);
}
}
$table->foreignKeys = array_values($table->foreignKeys);
return $table;
} else {
return null;
}
}
/**
* Loads the column information into a [[ColumnSchema]] object.
* @param array $info column information
* @return ColumnSchema the column schema object
*/
protected function loadColumnSchema($info)
{
$column = new ColumnSchema();
$column->name = $info['Field'];
$column->allowNull = $info['Null'] === 'YES';
$column->isPrimaryKey = strpos($info['Key'], 'PRI') !== false;
$column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false;
$column->dbType = strtolower($info['Type']);
$column->unsigned = strpos($column->dbType, 'unsigned') !== false;
$column->type = self::TYPE_STRING;
if (preg_match('/^([\w ]+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
$type = $matches[1];
if (isset($this->typeMap[$type])) {
$column->type = $this->typeMap[$type];
}
if (!empty($matches[2])) {
if ($type === 'enum') {
$values = explode(',', $matches[2]);
foreach ($values as $i => $value) {
$values[$i] = trim($value, "'");
}
$column->enumValues = $values;
} else {
$values = explode(',', $matches[2]);
$column->size = $column->precision = (int)$values[0];
if (isset($values[1])) {
$column->scale = (int)$values[1];
}
}
}
}
$column->phpType = $this->getColumnPhpType($column);
if ($column->type === 'timestamp' && $info['Default'] === 'CURRENT_TIMESTAMP' ||
$column->type === 'datetime' && $info['Default'] === 'SYS_DATETIME' ||
$column->type === 'date' && $info['Default'] === 'SYS_DATE' ||
$column->type === 'time' && $info['Default'] === 'SYS_TIME'
) {
$column->defaultValue = new Expression($info['Default']);
} else {
$column->defaultValue = $column->typecast($info['Default']);
}
return $column;
}
/**
* Returns all table names in the database.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO schema name prefix.
*/
protected function findTableNames($schema = '')
{
$this->db->open();
$tables = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE);
$tableNames = array();
foreach($tables as $table) {
// do not list system tables
if ($table['TYPE'] != 0) {
$tableNames[] = $table['NAME'];
}
}
return $tableNames;
}
/**
* Determines the PDO type for the give PHP data value.
* @param mixed $data the data whose PDO type is to be determined
* @return integer the PDO type
* @see http://www.php.net/manual/en/pdo.constants.php
*/
public function getPdoType($data)
{
static $typeMap = array(
'boolean' => \PDO::PARAM_INT, // CUBRID PDO does not support PARAM_BOOL
'integer' => \PDO::PARAM_INT,
'string' => \PDO::PARAM_STR,
'resource' => \PDO::PARAM_LOB,
'NULL' => \PDO::PARAM_NULL,
);
$type = gettype($data);
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
}
}

1
framework/yii/db/mssql/QueryBuilder.php

@ -22,6 +22,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/ */
public $typeMap = array( public $typeMap = array(
Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY', Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY',
Schema::TYPE_BIGPK => 'bigint IDENTITY PRIMARY KEY',
Schema::TYPE_STRING => 'varchar(255)', Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_TEXT => 'text', Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint(6)', Schema::TYPE_SMALLINT => 'smallint(6)',

5
framework/yii/db/mssql/Schema.php

@ -7,7 +7,6 @@
namespace yii\db\mssql; namespace yii\db\mssql;
use yii\db\TableSchema;
use yii\db\ColumnSchema; use yii\db\ColumnSchema;
/** /**
@ -332,10 +331,8 @@ SQL;
/** /**
* Returns all table names in the database. * Returns all table names in the database.
* This method should be overridden by child classes in order to support this feature
* because the default implementation simply throws an exception.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO the schema name prefix. * @return array all table names in the database. The names have NO schema name prefix.
*/ */
protected function findTableNames($schema = '') protected function findTableNames($schema = '')
{ {

23
framework/yii/db/mssql/TableSchema.php

@ -0,0 +1,23 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mssql;
/**
* TableSchema represents the metadata of a database table.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class TableSchema extends \yii\db\TableSchema
{
/**
* @var string name of the catalog (database) that this table belongs to.
* Defaults to null, meaning no catalog (or the current database).
*/
public $catalogName;
}

3
framework/yii/db/mysql/QueryBuilder.php

@ -23,6 +23,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/ */
public $typeMap = array( public $typeMap = array(
Schema::TYPE_PK => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', Schema::TYPE_PK => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY',
Schema::TYPE_BIGPK => 'bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY',
Schema::TYPE_STRING => 'varchar(255)', Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_TEXT => 'text', Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint(6)', Schema::TYPE_SMALLINT => 'smallint(6)',
@ -152,7 +153,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* ))->execute(); * ))->execute();
* ~~~ * ~~~
* *
* Not that the values in each row must match the corresponding column names. * Note that the values in each row must match the corresponding column names.
* *
* @param string $table the table that new rows will be inserted into. * @param string $table the table that new rows will be inserted into.
* @param array $columns the column names * @param array $columns the column names

4
framework/yii/db/mysql/Schema.php

@ -236,10 +236,8 @@ class Schema extends \yii\db\Schema
/** /**
* Returns all table names in the database. * Returns all table names in the database.
* This method should be overridden by child classes in order to support this feature
* because the default implementation simply throws an exception.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO the schema name prefix. * @return array all table names in the database. The names have NO schema name prefix.
*/ */
protected function findTableNames($schema = '') protected function findTableNames($schema = '')
{ {

3
framework/yii/db/pgsql/QueryBuilder.php

@ -21,7 +21,8 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @var array mapping from abstract column types (keys) to physical column types (values). * @var array mapping from abstract column types (keys) to physical column types (values).
*/ */
public $typeMap = array( public $typeMap = array(
Schema::TYPE_PK => 'serial not null primary key', Schema::TYPE_PK => 'serial NOT NULL PRIMARY KEY',
Schema::TYPE_BIGPK => 'bigserial NOT NULL PRIMARY KEY',
Schema::TYPE_STRING => 'varchar(255)', Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_TEXT => 'text', Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint', Schema::TYPE_SMALLINT => 'smallint',

33
framework/yii/db/pgsql/Schema.php

@ -129,6 +129,35 @@ class Schema extends \yii\db\Schema
} }
/** /**
* Returns all table names in the database.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* If not empty, the returned table names will be prefixed with the schema name.
* @return array all table names in the database.
*/
protected function findTableNames($schema = '')
{
if ($schema === '') {
$schema = $this->defaultSchema;
}
$sql = <<<EOD
SELECT table_name, table_schema FROM information_schema.tables
WHERE table_schema=:schema AND table_type='BASE TABLE'
EOD;
$command = $this->db->createCommand($sql);
$command->bindParam(':schema', $schema);
$rows = $command->queryAll();
$names = array();
foreach ($rows as $row) {
if ($schema === $this->defaultSchema) {
$names[] = $row['table_name'];
} else {
$names[] = $row['table_schema'] . '.' . $row['table_name'];
}
}
return $names;
}
/**
* Collects the foreign key column details for the given table. * Collects the foreign key column details for the given table.
* @param TableSchema $table the table metadata * @param TableSchema $table the table metadata
*/ */
@ -171,7 +200,7 @@ SQL;
} }
$citem = array($foreignTable); $citem = array($foreignTable);
foreach ($columns as $idx => $column) { foreach ($columns as $idx => $column) {
$citem[] = array($fcolumns[$idx] => $column); $citem[$fcolumns[$idx]] = $column;
} }
$table->foreignKeys[] = $citem; $table->foreignKeys[] = $citem;
} }
@ -226,7 +255,7 @@ SELECT
information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t)) information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t))
AS numeric AS numeric
) AS size, ) AS size,
a.attnum = any (ct.conkey) as is_pkey a.attnum = any (ct.conkey) as is_pkey
FROM FROM
pg_class c pg_class c
LEFT JOIN pg_attribute a ON a.attrelid = c.oid LEFT JOIN pg_attribute a ON a.attrelid = c.oid

9
framework/yii/db/redis/Connection.php

@ -13,16 +13,19 @@ use \yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use \yii\db\Exception; use \yii\db\Exception;
use yii\helpers\Inflector; use yii\helpers\Inflector;
use yii\helpers\StringHelper;
/** /**
* *
*
*
* @method mixed set($key, $value) Set the string value of a key * @method mixed set($key, $value) Set the string value of a key
* @method mixed get($key) Set the string value of a key * @method mixed get($key) Set the string value of a key
* TODO document methods * TODO document methods
* *
* @property string $driverName Name of the DB driver. This property is read-only.
* @property boolean $isActive Whether the DB connection is established. This property is read-only.
* @property Transaction $transaction The currently active transaction. Null if no active transaction. This
* property is read-only.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class Connection extends Component class Connection extends Component

4
framework/yii/db/redis/Transaction.php

@ -15,8 +15,10 @@ use yii\db\Exception;
/** /**
* Transaction represents a DB transaction. * Transaction represents a DB transaction.
* *
* @property boolean $isActive Whether the transaction is active. This property is read-only. * @property boolean $isActive Whether this transaction is active. Only an active transaction can [[commit()]]
* or [[rollBack()]]. This property is read-only.
* *
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class Transaction extends \yii\base\Object class Transaction extends \yii\base\Object

1
framework/yii/db/sqlite/QueryBuilder.php

@ -24,6 +24,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/ */
public $typeMap = array( public $typeMap = array(
Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL', Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
Schema::TYPE_BIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
Schema::TYPE_STRING => 'varchar(255)', Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_TEXT => 'text', Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint', Schema::TYPE_SMALLINT => 'smallint',

8
framework/yii/db/sqlite/Schema.php

@ -126,7 +126,13 @@ class Schema extends \yii\db\Schema
$sql = "PRAGMA foreign_key_list(" . $this->quoteSimpleTableName($table->name) . ')'; $sql = "PRAGMA foreign_key_list(" . $this->quoteSimpleTableName($table->name) . ')';
$keys = $this->db->createCommand($sql)->queryAll(); $keys = $this->db->createCommand($sql)->queryAll();
foreach ($keys as $key) { foreach ($keys as $key) {
$table->foreignKeys[] = array($key['table'], $key['from'] => $key['to']); $id = (int)$key['id'];
if (!isset($table->foreignKeys[$id])) {
$table->foreignKeys[$id] = array($key['table'], $key['from'] => $key['to']);
} else {
// composite FK
$table->foreignKeys[$id][$key['from']] = $key['to'];
}
} }
} }

2
framework/yii/debug/LogTarget.php

@ -11,6 +11,8 @@ use Yii;
use yii\log\Target; use yii\log\Target;
/** /**
* The debug LogTarget is used to store logs for later use in the debugger tool
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

2
framework/yii/debug/Module.php

@ -12,6 +12,8 @@ use yii\base\View;
use yii\web\HttpException; use yii\web\HttpException;
/** /**
* The Yii Debug Module provides the debug toolbar and debugger
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

5
framework/yii/debug/Panel.php

@ -14,6 +14,11 @@ use yii\base\Component;
* Panel is a base class for debugger panel classes. It defines how data should be collected, * Panel is a base class for debugger panel classes. It defines how data should be collected,
* what should be displayed at debug toolbar and on debugger details view. * what should be displayed at debug toolbar and on debugger details view.
* *
* @property string $detail Content that is displayed in debugger detail view. This property is read-only.
* @property string $name Name of the panel. This property is read-only.
* @property string $summary Content that is displayed at debug toolbar. This property is read-only.
* @property string $url URL pointing to panel detail view. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

1
framework/yii/debug/assets/main.css

@ -131,6 +131,7 @@ ul.trace {
margin: 2px 0 0 0; margin: 2px 0 0 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
white-space: normal;
} }
.callout-danger { .callout-danger {

4
framework/yii/gii/CodeFile.php

@ -16,6 +16,10 @@ use yii\helpers\StringHelper;
/** /**
* CodeFile represents a code file to be generated. * CodeFile represents a code file to be generated.
* *
* @property string $relativePath The code file path relative to the application base path. This property is
* read-only.
* @property string $type The code file extension (e.g. php, txt). This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

28
framework/yii/gii/Generator.php

@ -27,6 +27,12 @@ use yii\base\View;
* - [[generate()]]: generates the code based on the current user input and the specified code template files. * - [[generate()]]: generates the code based on the current user input and the specified code template files.
* This is the place where main code generation code resides. * This is the place where main code generation code resides.
* *
* @property string $description The detailed description of the generator. This property is read-only.
* @property string $stickyDataFile The file path that stores the sticky attribute values. This property is
* read-only.
* @property string $templatePath The root path of the template files that are currently being used. This
* property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
@ -319,6 +325,28 @@ abstract class Generator extends Model
} }
/** /**
* An inline validator that checks if the attribute value refers to a valid namespaced class name.
* The validator will check if the directory containing the new class file exist or not.
* @param string $attribute the attribute being validated
* @param array $params the validation options
*/
public function validateNewClass($attribute, $params)
{
$class = ltrim($this->$attribute, '\\');
if (($pos = strrpos($class, '\\')) === false) {
$this->addError($attribute, "The class name must contain fully qualified namespace name.");
} else {
$ns = substr($class, 0, $pos);
$path = Yii::getAlias('@' . str_replace('\\', '/', $ns), false);
if ($path === false) {
$this->addError($attribute, "The class namespace is invalid: $ns");
} elseif (!is_dir($path)) {
$this->addError($attribute, "Please make sure the directory containing this class exists: $path");
}
}
}
/**
* @param string $value the attribute to be validated * @param string $value the attribute to be validated
* @return boolean whether the value is a reserved PHP keyword. * @return boolean whether the value is a reserved PHP keyword.
*/ */

5
framework/yii/gii/assets/gii.js

@ -76,6 +76,11 @@ yii.gii = (function ($) {
initPreviewDiffLinks(); initPreviewDiffLinks();
initConfirmationCheckboxes(); initConfirmationCheckboxes();
// model generator: hide class name input when table name input contains *
$('#model-generator #generator-tablename').on('change', function () {
$('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1);
}).change();
// hide Generate button if any input is changed // hide Generate button if any input is changed
$('.default-view .form-group input,select,textarea').change(function () { $('.default-view .form-group input,select,textarea').change(function () {
$('.default-view-results,.default-view-files').hide(); $('.default-view-results,.default-view-files').hide();

35
framework/yii/gii/controllers/DefaultController.php

@ -7,6 +7,7 @@
namespace yii\gii\controllers; namespace yii\gii\controllers;
use Yii;
use yii\web\Controller; use yii\web\Controller;
use yii\web\HttpException; use yii\web\HttpException;
@ -35,7 +36,7 @@ class DefaultController extends Controller
public function actionView($id) public function actionView($id)
{ {
$generator = $this->loadGenerator($id); $generator = $this->loadGenerator($id);
$params = array('generator' => $generator); $params = array('generator' => $generator, 'id' => $id);
if (isset($_POST['preview']) || isset($_POST['generate'])) { if (isset($_POST['preview']) || isset($_POST['generate'])) {
if ($generator->validate()) { if ($generator->validate()) {
$generator->saveStickyAttributes(); $generator->saveStickyAttributes();
@ -86,6 +87,26 @@ class DefaultController extends Controller
throw new HttpException(404, "Code file not found: $file"); throw new HttpException(404, "Code file not found: $file");
} }
/**
* Runs an action defined in the generator.
* Given an action named "xyz", the method "actionXyz()" in the generator will be called.
* If the method does not exist, a 400 HTTP exception will be thrown.
* @param string $id the ID of the generator
* @param string $name the action name
* @return mixed the result of the action.
* @throws HttpException if the action method does not exist.
*/
public function actionAction($id, $name)
{
$generator = $this->loadGenerator($id);
$method = 'action' . $name;
if (method_exists($generator, $method)) {
return $generator->$method();
} else {
throw new HttpException(400, "Unknown generator action: $name");
}
}
public function createUrl($route, $params = array()) public function createUrl($route, $params = array())
{ {
if (!isset($params['id']) && $this->generator !== null) { if (!isset($params['id']) && $this->generator !== null) {
@ -99,6 +120,18 @@ class DefaultController extends Controller
return parent::createUrl($route, $params); return parent::createUrl($route, $params);
} }
public function createActionUrl($name, $params = array())
{
foreach ($this->module->generators as $id => $generator) {
if ($generator === $this->generator) {
$params['id'] = $id;
break;
}
}
$params['name'] = $name;
return parent::createUrl('action', $params);
}
/** /**
* Loads the generator with the specified ID. * Loads the generator with the specified ID.
* @param string $id the ID of the generator to be loaded. * @param string $id the ID of the generator to be loaded.

2
framework/yii/gii/generators/controller/Generator.php

@ -78,7 +78,7 @@ class Generator extends \yii\gii\Generator
'baseClass' => 'Base Class', 'baseClass' => 'Base Class',
'controller' => 'Controller ID', 'controller' => 'Controller ID',
'actions' => 'Action IDs', 'actions' => 'Action IDs',
'ns' => 'Namespace', 'ns' => 'Controller Namespace',
); );
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save