diff --git a/apps/advanced/README.md b/apps/advanced/README.md index 1afef67..00beb56 100644 --- a/apps/advanced/README.md +++ b/apps/advanced/README.md @@ -76,6 +76,13 @@ php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-a Note that in order to install some dependencies you must have `php_openssl` extension enabled. +After the application is installed, switch to the project folder and run the following command +to initialize the application: + +~~~ +./init (init on Windows) +~~~ + ### Install from an Archive File diff --git a/apps/advanced/backend/assets/.gitkeep b/apps/advanced/backend/assets/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/apps/advanced/backend/assets/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/apps/advanced/backend/config/AppAsset.php b/apps/advanced/backend/assets/AppAsset.php similarity index 94% rename from apps/advanced/backend/config/AppAsset.php rename to apps/advanced/backend/assets/AppAsset.php index 2fd15ca..bd5c3a0 100644 --- a/apps/advanced/backend/config/AppAsset.php +++ b/apps/advanced/backend/assets/AppAsset.php @@ -5,7 +5,7 @@ * @license http://www.yiiframework.com/license/ */ -namespace backend\config; +namespace backend\assets; use yii\web\AssetBundle; diff --git a/apps/advanced/backend/config/main.php b/apps/advanced/backend/config/main.php index 07658dd..f2745e2 100644 --- a/apps/advanced/backend/config/main.php +++ b/apps/advanced/backend/config/main.php @@ -1,5 +1,5 @@ 'app-backend', 'basePath' => dirname(__DIR__), - 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', + 'vendorPath' => $rootDir . '/vendor', 'preload' => ['log'], 'controllerNamespace' => 'backend\controllers', 'modules' => [], - 'extensions' => require(__DIR__ . '/../../vendor/yiisoft/extensions.php'), + 'extensions' => require($rootDir . '/vendor/yiisoft/extensions.php'), 'components' => [ 'request' => [ 'enableCsrfValidation' => true, diff --git a/apps/advanced/backend/controllers/SiteController.php b/apps/advanced/backend/controllers/SiteController.php index 6850fe9..ecf684c 100644 --- a/apps/advanced/backend/controllers/SiteController.php +++ b/apps/advanced/backend/controllers/SiteController.php @@ -50,7 +50,7 @@ class SiteController extends Controller $model = new LoginForm(); if ($model->load($_POST) && $model->login()) { - return $this->goHome(); + return $this->goBack(); } else { return $this->render('login', [ 'model' => $model, diff --git a/apps/advanced/backend/views/layouts/main.php b/apps/advanced/backend/views/layouts/main.php index 0e9d501..9f0280d 100644 --- a/apps/advanced/backend/views/layouts/main.php +++ b/apps/advanced/backend/views/layouts/main.php @@ -1,13 +1,13 @@ @@ -38,16 +38,16 @@ AppAsset::register($this); $menuItems[] = ['label' => 'Logout (' . Yii::$app->user->identity->username .')' , 'url' => ['/site/logout']]; } echo Nav::widget([ - 'options' => ['class' => 'navbar-nav pull-right'], + 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => $menuItems, ]); NavBar::end(); ?>
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]); ?> + ]) ?>
diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php index 339005b..30fb39b 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/LoginForm.php @@ -21,7 +21,7 @@ class LoginForm extends Model { return [ // username and password are both required - ['username, password', 'required'], + [['username', 'password'], 'required'], // password is validated by validatePassword() ['password', 'validatePassword'], // rememberMe must be a boolean value diff --git a/apps/advanced/composer.json b/apps/advanced/composer.json index 17b5106..9fd15d2 100644 --- a/apps/advanced/composer.json +++ b/apps/advanced/composer.json @@ -23,8 +23,7 @@ }, "scripts": { "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission", - "./init" + "yii\\composer\\Installer::setPermission" ] }, "extra": { diff --git a/apps/advanced/frontend/assets/.gitkeep b/apps/advanced/frontend/assets/.gitkeep deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/frontend/assets/.gitkeep +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/frontend/config/AppAsset.php b/apps/advanced/frontend/assets/AppAsset.php similarity index 94% rename from apps/advanced/frontend/config/AppAsset.php rename to apps/advanced/frontend/assets/AppAsset.php index 98306e3..03c5382 100644 --- a/apps/advanced/frontend/config/AppAsset.php +++ b/apps/advanced/frontend/assets/AppAsset.php @@ -5,7 +5,7 @@ * @license http://www.yiiframework.com/license/ */ -namespace frontend\config; +namespace frontend\assets; use yii\web\AssetBundle; diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php index 02b9bca..184d16c 100644 --- a/apps/advanced/frontend/controllers/SiteController.php +++ b/apps/advanced/frontend/controllers/SiteController.php @@ -60,7 +60,7 @@ class SiteController extends Controller $model = new LoginForm(); if ($model->load($_POST) && $model->login()) { - return $this->goHome(); + return $this->goBack(); } else { return $this->render('login', [ 'model' => $model, diff --git a/apps/advanced/frontend/models/ContactForm.php b/apps/advanced/frontend/models/ContactForm.php index a3c56b8..0a664ad 100644 --- a/apps/advanced/frontend/models/ContactForm.php +++ b/apps/advanced/frontend/models/ContactForm.php @@ -23,7 +23,7 @@ class ContactForm extends Model { return [ // name, email, subject and body are required - ['name, email, subject, body', 'required'], + [['name', 'email', 'subject', 'body'], 'required'], // email has to be a valid email address ['email', 'email'], // verifyCode needs to be entered correctly diff --git a/apps/advanced/frontend/views/emails/passwordResetToken.php b/apps/advanced/frontend/views/emails/passwordResetToken.php index ac2155c..b617bd9 100644 --- a/apps/advanced/frontend/views/emails/passwordResetToken.php +++ b/apps/advanced/frontend/views/emails/passwordResetToken.php @@ -9,8 +9,8 @@ use yii\helpers\Html; $resetLink = Yii::$app->urlManager->createAbsoluteUrl('site/reset-password', ['token' => $user->password_reset_token]); ?> -Hello username)?>, +Hello username) ?>, Follow the link below to reset your password: - + diff --git a/apps/advanced/frontend/views/layouts/main.php b/apps/advanced/frontend/views/layouts/main.php index 5da179c..7b2ce6f 100644 --- a/apps/advanced/frontend/views/layouts/main.php +++ b/apps/advanced/frontend/views/layouts/main.php @@ -1,14 +1,14 @@ @@ -42,17 +42,17 @@ AppAsset::register($this); $menuItems[] = ['label' => 'Logout (' . Yii::$app->user->identity->username .')' , 'url' => ['/site/logout']]; } echo Nav::widget([ - 'options' => ['class' => 'navbar-nav pull-right'], + 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => $menuItems, ]); NavBar::end(); ?>
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]); ?> - + ]) ?> +
diff --git a/apps/advanced/frontend/views/site/login.php b/apps/advanced/frontend/views/site/login.php index 74c5ffa..75dd4ca 100644 --- a/apps/advanced/frontend/views/site/login.php +++ b/apps/advanced/frontend/views/site/login.php @@ -22,7 +22,7 @@ $this->params['breadcrumbs'][] = $this->title; field($model, 'password')->passwordInput() ?> field($model, 'rememberMe')->checkbox() ?>
- If you forgot your password you can . + If you forgot your password you can .
'btn btn-primary']) ?> diff --git a/apps/basic/config/AppAsset.php b/apps/basic/assets/AppAsset.php similarity index 95% rename from apps/basic/config/AppAsset.php rename to apps/basic/assets/AppAsset.php index 87f6f8b..c964d36 100644 --- a/apps/basic/config/AppAsset.php +++ b/apps/basic/assets/AppAsset.php @@ -5,7 +5,7 @@ * @license http://www.yiiframework.com/license/ */ -namespace app\config; +namespace app\assets; use yii\web\AssetBundle; diff --git a/apps/basic/codeception.yml b/apps/basic/codeception.yml index 5b1f441..b6adeb5 100644 --- a/apps/basic/codeception.yml +++ b/apps/basic/codeception.yml @@ -6,7 +6,6 @@ paths: settings: bootstrap: _bootstrap.php suite_class: \PHPUnit_Framework_TestSuite - colors: true memory_limit: 1024M log: true modules: diff --git a/apps/basic/config/console.php b/apps/basic/config/console.php index c70993e..6f3f9a8 100644 --- a/apps/basic/config/console.php +++ b/apps/basic/config/console.php @@ -1,7 +1,7 @@ 'bootstrap-console', + 'id' => 'basic-console', 'basePath' => dirname(__DIR__), 'preload' => ['log'], 'controllerPath' => dirname(__DIR__) . '/commands', diff --git a/apps/basic/config/web.php b/apps/basic/config/web.php index 1f6c51f..cf921b0 100644 --- a/apps/basic/config/web.php +++ b/apps/basic/config/web.php @@ -1,7 +1,7 @@ 'bootstrap', + 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 'components' => [ diff --git a/apps/basic/models/ContactForm.php b/apps/basic/models/ContactForm.php index 58f8d26..1344562 100644 --- a/apps/basic/models/ContactForm.php +++ b/apps/basic/models/ContactForm.php @@ -23,7 +23,7 @@ class ContactForm extends Model { return [ // name, email, subject and body are required - ['name, email, subject, body', 'required'], + [['name', 'email', 'subject', 'body'], 'required'], // email has to be a valid email address ['email', 'email'], // verifyCode needs to be entered correctly diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php index 339cf31..ad854a2 100644 --- a/apps/basic/models/LoginForm.php +++ b/apps/basic/models/LoginForm.php @@ -21,7 +21,7 @@ class LoginForm extends Model { return [ // username and password are both required - ['username, password', 'required'], + [['username', 'password'], 'required'], // password is validated by validatePassword() ['password', 'validatePassword'], // rememberMe must be a boolean value diff --git a/apps/basic/tests/README.md b/apps/basic/tests/README.md new file mode 100644 index 0000000..c87f762 --- /dev/null +++ b/apps/basic/tests/README.md @@ -0,0 +1,20 @@ +This folder contains various tests for the basic application. +These tests are developed with [Codeception PHP Testing Framework](http://codeception.com/). + +To run the tests, follow these steps: + +1. [Install Codeception](http://codeception.com/quickstart) if you do not have it yet. +2. Create test configuration files based on your environment: + - Copy `acceptance.suite.dist.yml` to `acceptance.suite.yml` and customize it; + - Copy `functional.suite.dist.yml` to `functional.suite.yml` and customize it; + - Copy `unit.suite.dist.yml` to `unit.suite.yml` and customize it. +3. Switch to the parent folder and run tests: + +``` +cd .. +php codecept.phar build // rebuild test scripts, only need to be run once +php codecept.phar run // run all available tests +``` + +Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for +more details about writing acceptance, functional and unit tests. diff --git a/apps/basic/tests/acceptance/WebGuy.php b/apps/basic/tests/acceptance/WebGuy.php index e6cc370..f08ed9c 100644 --- a/apps/basic/tests/acceptance/WebGuy.php +++ b/apps/basic/tests/acceptance/WebGuy.php @@ -17,13 +17,21 @@ use Codeception\Module\WebHelper; * @method void expect($prediction) * @method void amGoingTo($argumentation) * @method void am($role) - * @method void lookForwardTo($role) + * @method void lookForwardTo($achieveValue) + * @method void offsetGet($offset) + * @method void offsetSet($offset, $value) + * @method void offsetExists($offset) + * @method void offsetUnset($offset) */ class WebGuy extends \Codeception\AbstractGuy { /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Submits a form located on page. * Specify the form by it's css or xpath selector. * Fill the form fields values as array. @@ -36,7 +44,7 @@ class WebGuy extends \Codeception\AbstractGuy * * ``` php * submitForm('#login', ['login' => 'davert', 'password' => '123456']); + * $I->submitForm('#login', array('login' => 'davert', 'password' => '123456')); * * ``` * @@ -55,20 +63,18 @@ class WebGuy extends \Codeception\AbstractGuy * * ``` php * submitForm('#userForm', ['user' => ['login' => 'Davert', 'password' => '123456', 'agree' => true]]); + * $I->submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true))); * * ``` * Note, that pricing plan will be set to Paid, as it's selected on page. * * @param $selector * @param $params - * @see PhpBrowser::submitForm() + * @see Codeception\Module\PhpBrowser::submitForm() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function submitForm($selector, $params) { - $this->scenario->action('submitForm', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('submitForm', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -78,6 +84,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * If your page triggers an ajax request, you can perform it manually. * This action sends a POST ajax request with specified params. * Additional params can be passed as array. @@ -89,20 +99,18 @@ class WebGuy extends \Codeception\AbstractGuy * * ``` php * sendAjaxPostRequest('/updateSettings', ['notifications' => true]; // POST - * $I->sendAjaxGetRequest('/updateSettings', ['notifications' => true]; // GET + * $I->sendAjaxPostRequest('/updateSettings', array('notifications' => true); // POST + * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true); // GET * * ``` * * @param $uri * @param $params - * @see PhpBrowser::sendAjaxPostRequest() + * @see Codeception\Module\PhpBrowser::sendAjaxPostRequest() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function sendAjaxPostRequest($uri, $params = null) { - $this->scenario->action('sendAjaxPostRequest', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -112,6 +120,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * If your page triggers an ajax request, you can perform it manually. * This action sends a GET ajax request with specified params. * @@ -119,13 +131,11 @@ class WebGuy extends \Codeception\AbstractGuy * * @param $uri * @param $params - * @see PhpBrowser::sendAjaxGetRequest() + * @see Codeception\Module\PhpBrowser::sendAjaxGetRequest() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function sendAjaxGetRequest($uri, $params = null) { - $this->scenario->action('sendAjaxGetRequest', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -135,14 +145,34 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Asserts that current page has 404 response status code. + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\PhpBrowser::seePageNotFound() + * @return \Codeception\Maybe + */ + public function canSeePageNotFound() { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Asserts that current page has 404 response status code. - * @see PhpBrowser::seePageNotFound() + * @see Codeception\Module\PhpBrowser::seePageNotFound() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seePageNotFound() { - $this->scenario->assertion('seePageNotFound', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -152,17 +182,40 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that response code is equal to value provided. + * + * @param $code + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\PhpBrowser::seeResponseCodeIs() + * @return \Codeception\Maybe + */ + public function canSeeResponseCodeIs($code) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that response code is equal to value provided. * * @param $code * @return mixed - * @see PhpBrowser::seeResponseCodeIs() + * @see Codeception\Module\PhpBrowser::seeResponseCodeIs() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeResponseCodeIs($code) { - $this->scenario->assertion('seeResponseCodeIs', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -172,17 +225,19 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Adds HTTP authentication via username/password. * * @param $username * @param $password - * @see PhpBrowser::amHttpAuthenticated() + * @see Codeception\Module\PhpBrowser::amHttpAuthenticated() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amHttpAuthenticated($username, $password) { - $this->scenario->condition('amHttpAuthenticated', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -192,6 +247,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Low-level API method. * If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly * @@ -202,12 +261,12 @@ class WebGuy extends \Codeception\AbstractGuy * // from the official Guzzle manual * $I->amGoingTo('Sign all requests with OAuth'); * $I->executeInGuzzle(function (\Guzzle\Http\Client $client) { - * $client->addSubscriber(new Guzzle\Plugin\Oauth\OauthPlugin([ + * $client->addSubscriber(new Guzzle\Plugin\Oauth\OauthPlugin(array( * 'consumer_key' => '***', * 'consumer_secret' => '***', * 'token' => '***', * 'token_secret' => '***' - * ])); + * ))); * }); * ?> * ``` @@ -216,13 +275,135 @@ class WebGuy extends \Codeception\AbstractGuy * If Codeception lacks important Guzzle Client methods implement then and submit patches. * * @param callable $function - * @see PhpBrowser::executeInGuzzle() + * @see Codeception\Module\PhpBrowser::executeInGuzzle() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function executeInGuzzle($function) { - $this->scenario->action('executeInGuzzle', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('executeInGuzzle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is checked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. + * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> + * ``` + * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\PhpBrowser::seeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function canSeeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is checked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. + * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> + * ``` + * + * @param $checkbox + * @see Codeception\Module\PhpBrowser::seeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function seeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is unchecked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> + * ``` + * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\PhpBrowser::dontSeeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function cantSeeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is unchecked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> + * ``` + * + * @param $checkbox + * @see Codeception\Module\PhpBrowser::dontSeeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function dontSeeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -232,16 +413,18 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Opens the page. * * @param $page - * @see Mink::amOnPage() + * @see Codeception\Util\Mink::amOnPage() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amOnPage($page) { - $this->scenario->condition('amOnPage', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -251,6 +434,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Sets 'url' configuration parameter to hosts subdomain. * It does not open a page on subdomain. Use `amOnPage` for that * @@ -267,13 +454,54 @@ class WebGuy extends \Codeception\AbstractGuy * ``` * @param $subdomain * @return mixed - * @see Mink::amOnSubdomain() + * @see Codeception\Util\Mink::amOnSubdomain() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amOnSubdomain($subdomain) { - $this->scenario->condition('amOnSubdomain', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amOnSubdomain', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * @param string $text + * @param string $selector + * + * @return void + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSee() + * @return \Codeception\Maybe + */ + public function cantSee($text, $selector = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * @param string $text + * @param string $selector + * + * @return void + * @see Codeception\Util\Mink::dontSee() + * @return \Codeception\Maybe + */ + public function dontSee($text, $selector = null) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -283,36 +511,42 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Check if current page doesn't contain the text specified. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Check if current page contains the text specified. * Specify the css selector to match only specific region. * * Examples: * - * ```php + * ``` php * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath + * $I->see('Logout'); // I can suppose user is logged in + * $I->see('Sign Up','h1'); // I can suppose it's a signup page + * $I->see('Sign Up','//body/h1'); // with XPath + * ?> * ``` * * @param $text * @param null $selector - * @see Mink::dontSee() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::see() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSee($text, $selector = null) { - $this->scenario->action('dontSee', func_get_args()); + public function canSee($text, $selector = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Check if current page contains the text specified. * Specify the css selector to match only specific region. * @@ -323,18 +557,16 @@ class WebGuy extends \Codeception\AbstractGuy * $I->see('Logout'); // I can suppose user is logged in * $I->see('Sign Up','h1'); // I can suppose it's a signup page * $I->see('Sign Up','//body/h1'); // with XPath - * + * ?> * ``` * * @param $text * @param null $selector - * @see Mink::see() + * @see Codeception\Util\Mink::see() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function see($text, $selector = null) { - $this->scenario->assertion('see', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('see', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -344,6 +576,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if there is a link with text specified. * Specify url to match link with exact this url. * @@ -353,18 +589,47 @@ class WebGuy extends \Codeception\AbstractGuy * seeLink('Logout'); // matches Logout * $I->seeLink('Logout','/logout'); // matches Logout + * ?> + * ``` * + * @param $text + * @param null $url + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeLink() + * @return \Codeception\Maybe + */ + public function canSeeLink($text, $url = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if there is a link with text specified. + * Specify url to match link with exact this url. + * + * Examples: + * + * ``` php + * seeLink('Logout'); // matches Logout + * $I->seeLink('Logout','/logout'); // matches Logout + * ?> * ``` * * @param $text * @param null $url - * @see Mink::seeLink() + * @see Codeception\Util\Mink::seeLink() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeLink($text, $url = null) { - $this->scenario->assertion('seeLink', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -374,6 +639,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if page doesn't contain the link with text specified. * Specify url to narrow the results. * @@ -382,18 +651,46 @@ class WebGuy extends \Codeception\AbstractGuy * ``` php * dontSeeLink('Logout'); // I suppose user is not logged in + * ?> + * ``` * + * @param $text + * @param null $url + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeLink() + * @return \Codeception\Maybe + */ + public function cantSeeLink($text, $url = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if page doesn't contain the link with text specified. + * Specify url to narrow the results. + * + * Examples: + * + * ``` php + * dontSeeLink('Logout'); // I suppose user is not logged in + * ?> * ``` * * @param $text * @param null $url - * @see Mink::dontSeeLink() + * @see Codeception\Util\Mink::dontSeeLink() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeLink($text, $url = null) { - $this->scenario->action('dontSeeLink', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -403,6 +700,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Perform a click on link or button. * Link or button are found by their names or CSS selector. * Submits a form if button is a submit type. @@ -431,13 +732,11 @@ class WebGuy extends \Codeception\AbstractGuy * ``` * @param $link * @param $context - * @see Mink::click() + * @see Codeception\Util\Mink::click() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function click($link, $context = null) { - $this->scenario->action('click', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('click', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -447,22 +746,50 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if element exists on a page, matching it by CSS or XPath + * + * ``` php + * seeElement('.error'); + * $I->seeElement('//form/input[1]'); + * ?> + * ``` + * @param $selector + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeElement() + * @return \Codeception\Maybe + */ + public function canSeeElement($selector) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if element exists on a page, matching it by CSS or XPath * * ``` php * seeElement('.error'); - * $I->seeElement(//form/input[1]); + * $I->seeElement('//form/input[1]'); * ?> * ``` * @param $selector - * @see Mink::seeElement() + * @see Codeception\Util\Mink::seeElement() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeElement($selector) { - $this->scenario->assertion('seeElement', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -472,22 +799,54 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if element does not exist (or is visible) on a page, matching it by CSS or XPath + * + * Example: + * + * ``` php + * dontSeeElement('.error'); + * $I->dontSeeElement('//form/input[1]'); + * ?> + * ``` + * @param $selector + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeElement() + * @return \Codeception\Maybe + */ + public function cantSeeElement($selector) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if element does not exist (or is visible) on a page, matching it by CSS or XPath * + * Example: + * * ``` php * dontSeeElement('.error'); - * $I->dontSeeElement(//form/input[1]); + * $I->dontSeeElement('//form/input[1]'); * ?> * ``` * @param $selector - * @see Mink::dontSeeElement() + * @see Codeception\Util\Mink::dontSeeElement() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeElement($selector) { - $this->scenario->action('dontSeeElement', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -497,14 +856,16 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Reloads current page - * @see Mink::reloadPage() + * @see Codeception\Util\Mink::reloadPage() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function reloadPage() { - $this->scenario->action('reloadPage', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('reloadPage', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -514,14 +875,16 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Moves back in history - * @see Mink::moveBack() + * @see Codeception\Util\Mink::moveBack() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function moveBack() { - $this->scenario->action('moveBack', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('moveBack', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -531,14 +894,16 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Moves forward in history - * @see Mink::moveForward() + * @see Codeception\Util\Mink::moveForward() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function moveForward() { - $this->scenario->action('moveForward', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('moveForward', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -548,17 +913,27 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Fills a text field or textarea with value. + * + * Example: + * + * ``` php + * fillField("//input[@type='text']", "Hello World!"); + * ?> + * ``` * * @param $field * @param $value - * @see Mink::fillField() + * @see Codeception\Util\Mink::fillField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function fillField($field, $value) { - $this->scenario->action('fillField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('fillField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -568,27 +943,265 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Selects an option in select tag or in radio button group. * * Example: * * ``` php * selectOption('form select[name=account]', 'Premium'); - * $I->selectOption('form input[name=payment]', 'Monthly'); - * $I->selectOption('//form/select[@name=account]', 'Monthly'); + * $I->selectOption('form select[name=account]', 'Premium'); + * $I->selectOption('form input[name=payment]', 'Monthly'); + * $I->selectOption('//form/select[@name=account]', 'Monthly'); + * ?> + * ``` + * + * Can select multiple options if second argument is array: + * + * ``` php + * selectOption('Which OS do you use?', array('Windows','Linux')); + * ?> + * ``` + * + * @param $select + * @param $option + * @see Codeception\Util\Mink::selectOption() + * @return \Codeception\Maybe + */ + public function selectOption($select, $option) { + $this->scenario->addStep(new \Codeception\Step\Action('selectOption', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Ticks a checkbox. + * For radio buttons use `selectOption` method. + * + * Example: + * + * ``` php + * checkOption('#agree'); + * ?> + * ``` + * + * @param $option + * @see Codeception\Util\Mink::checkOption() + * @return \Codeception\Maybe + */ + public function checkOption($option) { + $this->scenario->addStep(new \Codeception\Step\Action('checkOption', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Unticks a checkbox. + * + * Example: + * + * ``` php + * uncheckOption('#notify'); + * ?> + * ``` + * + * @param $option + * @see Codeception\Util\Mink::uncheckOption() + * @return \Codeception\Maybe + */ + public function uncheckOption($option) { + $this->scenario->addStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri contains a value + * + * ``` php + * seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeInCurrentUrl() + * @return \Codeception\Maybe + */ + public function canSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri contains a value + * + * ``` php + * seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Mink::seeInCurrentUrl() + * @return \Codeception\Maybe + */ + public function seeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri does not contain a value + * + * ``` php + * dontSeeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeInCurrentUrl() + * @return \Codeception\Maybe + */ + public function cantSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri does not contain a value + * + * ``` php + * dontSeeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Mink::dontSeeInCurrentUrl() + * @return \Codeception\Maybe + */ + public function dontSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is equal to value. + * Unlike `seeInCurrentUrl` performs a strict check. + * + * ``` php + * seeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeCurrentUrlEquals() + * @return \Codeception\Maybe + */ + public function canSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is equal to value. + * Unlike `seeInCurrentUrl` performs a strict check. + * + * ``` php + * seeCurrentUrlEquals('/'); * ?> * ``` * - * @param $select - * @param $option - * @see Mink::selectOption() + * @param $uri + * @see Codeception\Util\Mink::seeCurrentUrlEquals() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function selectOption($select, $option) { - $this->scenario->action('selectOption', func_get_args()); + public function seeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -598,52 +1211,54 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Ticks a checkbox. - * For radio buttons use `selectOption` method. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * Example: + * Checks that current url is not equal to value. + * Unlike `dontSeeInCurrentUrl` performs a strict check. * * ``` php * checkOption('#agree'); + * // current url is not root + * $I->dontSeeCurrentUrlEquals('/'); * ?> * ``` * - * @param $option - * @see Mink::checkOption() + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeCurrentUrlEquals() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function checkOption($option) { - $this->scenario->action('checkOption', func_get_args()); + public function cantSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Unticks a checkbox. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * Example: + * Checks that current url is not equal to value. + * Unlike `dontSeeInCurrentUrl` performs a strict check. * * ``` php * uncheckOption('#notify'); + * // current url is not root + * $I->dontSeeCurrentUrlEquals('/'); * ?> * ``` * - * @param $option - * @see Mink::uncheckOption() + * @param $uri + * @see Codeception\Util\Mink::dontSeeCurrentUrlEquals() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function uncheckOption($option) { - $this->scenario->action('uncheckOption', func_get_args()); + public function dontSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -653,50 +1268,52 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Checks that current uri contains a value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is matches a RegEx value * * ``` php * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); + * // to match root url + * $I->seeCurrentUrlMatches('~$/users/(\d+)~'); * ?> * ``` * * @param $uri - * @see Mink::seeInCurrentUrl() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeCurrentUrlMatches() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeInCurrentUrl($uri) { - $this->scenario->assertion('seeInCurrentUrl', func_get_args()); + public function canSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current uri does not contain a value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is matches a RegEx value * * ``` php * dontSeeInCurrentUrl('/users/'); + * // to match root url + * $I->seeCurrentUrlMatches('~$/users/(\d+)~'); * ?> * ``` * * @param $uri - * @see Mink::dontSeeInCurrentUrl() + * @see Codeception\Util\Mink::seeCurrentUrlMatches() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeInCurrentUrl($uri) { - $this->scenario->action('dontSeeInCurrentUrl', func_get_args()); + public function seeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -706,47 +1323,52 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Checks that current url is equal to value. - * Unlike `seeInCurrentUrl` performs a strict check. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url does not match a RegEx value * + * ``` php * seeCurrentUrlEquals('/'); + * $I->dontSeeCurrentUrlMatches('~$/users/(\d+)~'); * ?> + * ``` * * @param $uri - * @see Mink::seeCurrentUrlEquals() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeCurrentUrlMatches() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCurrentUrlEquals($uri) { - $this->scenario->assertion('seeCurrentUrlEquals', func_get_args()); + public function cantSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current url is not equal to value. - * Unlike `dontSeeInCurrentUrl` performs a strict check. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url does not match a RegEx value * + * ``` php * dontSeeCurrentUrlEquals('/'); + * // to match root url + * $I->dontSeeCurrentUrlMatches('~$/users/(\d+)~'); * ?> + * ``` * * @param $uri - * @see Mink::dontSeeCurrentUrlEquals() + * @see Codeception\Util\Mink::dontSeeCurrentUrlMatches() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeCurrentUrlEquals($uri) { - $this->scenario->action('dontSeeCurrentUrlEquals', func_get_args()); + public function dontSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -756,45 +1378,40 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Checks that current url is matches a RegEx value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> + * Checks that cookie is set. * - * @param $uri - * @see Mink::seeCurrentUrlMatches() + * @param $cookie + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCurrentUrlMatches($uri) { - $this->scenario->assertion('seeCurrentUrlMatches', func_get_args()); + public function canSeeCookie($cookie) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current url does not match a RegEx value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> + * Checks that cookie is set. * - * @param $uri - * @see Mink::dontSeeCurrentUrlMatches() + * @param $cookie + * @return mixed + * @see Codeception\Util\Mink::seeCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeCurrentUrlMatches($uri) { - $this->scenario->action('dontSeeCurrentUrlMatches', func_get_args()); + public function seeCookie($cookie) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -804,31 +1421,40 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * @see Mink::seeCookie() + * Checks that cookie doesn't exist + * + * @param $cookie + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCookie($cookie) { - $this->scenario->assertion('seeCookie', func_get_args()); + public function cantSeeCookie($cookie) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that cookie doesn't exist * - * @see Mink::dontSeeCookie() + * @param $cookie + * @return mixed + * @see Codeception\Util\Mink::dontSeeCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeCookie($cookie) { - $this->scenario->action('dontSeeCookie', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -838,14 +1464,20 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Sets a cookie. * - * @see Mink::setCookie() + * @param $cookie + * @param $value + * @return mixed + * @see Codeception\Util\Mink::setCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function setCookie($cookie, $value) { - $this->scenario->action('setCookie', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('setCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -855,14 +1487,19 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * @see Mink::resetCookie() + * Unsets cookie + * + * @param $cookie + * @return mixed + * @see Codeception\Util\Mink::resetCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function resetCookie($cookie) { - $this->scenario->action('resetCookie', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('resetCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -872,14 +1509,19 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * @see Mink::grabCookie() + * Grabs a cookie value. + * + * @param $cookie + * @return mixed + * @see Codeception\Util\Mink::grabCookie() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabCookie($cookie) { - $this->scenario->action('grabCookie', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabCookie', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -889,6 +1531,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Takes a parameters from current URI by RegEx. * If no url provided returns full URI. * @@ -902,13 +1548,11 @@ class WebGuy extends \Codeception\AbstractGuy * @param null $uri * @internal param $url * @return mixed - * @see Mink::grabFromCurrentUrl() + * @see Codeception\Util\Mink::grabFromCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabFromCurrentUrl($uri = null) { - $this->scenario->action('grabFromCurrentUrl', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -918,26 +1562,28 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Attaches file from Codeception data directory to upload field. * * Example: * * ``` php * attachFile('prices.xls'); + * // file is stored in 'tests/_data/prices.xls' + * $I->attachFile('input[@type="file"]', 'prices.xls'); * ?> * ``` * * @param $field * @param $filename - * @see Mink::attachFile() + * @see Codeception\Util\Mink::attachFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function attachFile($field, $filename) { - $this->scenario->action('attachFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('attachFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -947,6 +1593,38 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if option is selected in select field. + * + * ``` php + * seeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeOptionIsSelected() + * @return \Codeception\Maybe + */ + public function canSeeOptionIsSelected($select, $text) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if option is selected in select field. * * ``` php @@ -958,13 +1636,11 @@ class WebGuy extends \Codeception\AbstractGuy * @param $selector * @param $optionText * @return mixed - * @see Mink::seeOptionIsSelected() + * @see Codeception\Util\Mink::seeOptionIsSelected() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeOptionIsSelected($select, $text) { - $this->scenario->assertion('seeOptionIsSelected', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -974,6 +1650,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if option is not selected in select field. * * ``` php @@ -985,43 +1665,39 @@ class WebGuy extends \Codeception\AbstractGuy * @param $selector * @param $optionText * @return mixed - * @see Mink::dontSeeOptionIsSelected() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeOptionIsSelected() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeOptionIsSelected($select, $text) { - $this->scenario->action('dontSeeOptionIsSelected', func_get_args()); + public function cantSeeOptionIsSelected($select, $text) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Assert if the specified checkbox is checked. - * Use css selector or xpath to match. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * Example: + * Checks if option is not selected in select field. * * ``` php * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * + * $I->dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> * ``` * - * @param $checkbox - * @see Mink::seeCheckboxIsChecked() + * @param $selector + * @param $optionText + * @return mixed + * @see Codeception\Util\Mink::dontSeeOptionIsSelected() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCheckboxIsChecked($checkbox) { - $this->scenario->assertion('seeCheckboxIsChecked', func_get_args()); + public function dontSeeOptionIsSelected($select, $text) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1031,35 +1707,44 @@ class WebGuy extends \Codeception\AbstractGuy /** - * Assert if the specified checkbox is unchecked. - * Use css selector or xpath to match. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that an input field or textarea contains value. + * Field is matched either by label or CSS or Xpath * * Example: * * ``` php * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * + * $I->seeInField('Body','Type your comment here'); + * $I->seeInField('form textarea[name=body]','Type your comment here'); + * $I->seeInField('form input[type=hidden]','hidden_value'); + * $I->seeInField('#searchform input','Search'); + * $I->seeInField('//form/*[@name=search]','Search'); + * ?> * ``` * - * @param $checkbox - * @see Mink::dontSeeCheckboxIsChecked() + * @param $field + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeInField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeCheckboxIsChecked($checkbox) { - $this->scenario->action('dontSeeCheckboxIsChecked', func_get_args()); + public function canSeeInField($field, $value) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that an input field or textarea contains value. * Field is matched either by label or CSS or Xpath * @@ -1077,13 +1762,11 @@ class WebGuy extends \Codeception\AbstractGuy * * @param $field * @param $value - * @see Mink::seeInField() + * @see Codeception\Util\Mink::seeInField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeInField($field, $value) { - $this->scenario->assertion('seeInField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1093,6 +1776,43 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that an input field or textarea doesn't contain value. + * Field is matched either by label or CSS or Xpath + * Example: + * + * ``` php + * dontSeeInField('Body','Type your comment here'); + * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); + * $I->dontSeeInField('form input[type=hidden]','hidden_value'); + * $I->dontSeeInField('#searchform input','Search'); + * $I->dontSeeInField('//form/*[@name=search]','Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeInField() + * @return \Codeception\Maybe + */ + public function cantSeeInField($field, $value) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that an input field or textarea doesn't contain value. * Field is matched either by label or CSS or Xpath * Example: @@ -1109,13 +1829,11 @@ class WebGuy extends \Codeception\AbstractGuy * * @param $field * @param $value - * @see Mink::dontSeeInField() + * @see Codeception\Util\Mink::dontSeeInField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeInField($field, $value) { - $this->scenario->action('dontSeeInField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1125,6 +1843,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Finds and returns text contents of element. * Element is searched by CSS selector, XPath or matcher by regex. * @@ -1140,13 +1862,11 @@ class WebGuy extends \Codeception\AbstractGuy * * @param $cssOrXPathOrRegex * @return mixed - * @see Mink::grabTextFrom() + * @see Codeception\Util\Mink::grabTextFrom() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabTextFrom($cssOrXPathOrRegex) { - $this->scenario->action('grabTextFrom', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1156,6 +1876,10 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Finds and returns field and returns it's value. * Searches by field name, then by CSS, then by XPath * @@ -1171,13 +1895,66 @@ class WebGuy extends \Codeception\AbstractGuy * * @param $field * @return mixed - * @see Mink::grabValueFrom() + * @see Codeception\Util\Mink::grabValueFrom() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabValueFrom($field) { - $this->scenario->action('grabValueFrom', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title contains text. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::seeInTitle() + * @return \Codeception\Maybe + */ + public function canSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title contains text. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * @return mixed + * @see Codeception\Util\Mink::seeInTitle() + * @return \Codeception\Maybe + */ + public function seeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1187,14 +1964,40 @@ class WebGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title does not contain text. + * + * @param $title + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Mink::dontSeeInTitle() + * @return \Codeception\Maybe + */ + public function cantSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * @see Mink::grabAttribute() + * Checks that page title does not contain text. + * + * @param $title + * @return mixed + * @see Codeception\Util\Mink::dontSeeInTitle() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function grabAttribute() { - $this->scenario->action('grabAttribute', func_get_args()); + public function dontSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); diff --git a/apps/basic/tests/functional/TestGuy.php b/apps/basic/tests/functional/TestGuy.php index 58baf56..553a44f 100644 --- a/apps/basic/tests/functional/TestGuy.php +++ b/apps/basic/tests/functional/TestGuy.php @@ -18,24 +18,30 @@ use Codeception\Module\Yii2; * @method void expect($prediction) * @method void amGoingTo($argumentation) * @method void am($role) - * @method void lookForwardTo($role) + * @method void lookForwardTo($achieveValue) + * @method void offsetGet($offset) + * @method void offsetSet($offset, $value) + * @method void offsetExists($offset) + * @method void offsetUnset($offset) */ class TestGuy extends \Codeception\AbstractGuy { /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Enters a directory In local filesystem. * Project root directory is used by default * * @param $path - * @see Filesystem::amInPath() + * @see Codeception\Module\Filesystem::amInPath() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amInPath($path) { - $this->scenario->condition('amInPath', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amInPath', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -45,6 +51,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Opens a file and stores it's content. * * Usage: @@ -57,13 +67,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $filename - * @see Filesystem::openFile() + * @see Codeception\Module\Filesystem::openFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function openFile($filename) { - $this->scenario->action('openFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('openFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -73,6 +81,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Deletes a file * * ``` php @@ -82,13 +94,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $filename - * @see Filesystem::deleteFile() + * @see Codeception\Module\Filesystem::deleteFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function deleteFile($filename) { - $this->scenario->action('deleteFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('deleteFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -98,6 +108,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Deletes directory with all subdirectories * * ``` php @@ -107,13 +121,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $dirname - * @see Filesystem::deleteDir() + * @see Codeception\Module\Filesystem::deleteDir() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function deleteDir($dirname) { - $this->scenario->action('deleteDir', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('deleteDir', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -123,6 +135,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Copies directory with all contents * * ``` php @@ -133,13 +149,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $src * @param $dst - * @see Filesystem::copyDir() + * @see Codeception\Module\Filesystem::copyDir() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function copyDir($src, $dst) { - $this->scenario->action('copyDir', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('copyDir', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -149,6 +163,39 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks If opened file has `text` in it. + * + * Usage: + * + * ``` php + * openFile('composer.json'); + * $I->seeInThisFile('codeception/codeception'); + * ?> + * ``` + * + * @param $text + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\Filesystem::seeInThisFile() + * @return \Codeception\Maybe + */ + public function canSeeInThisFile($text) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInThisFile', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks If opened file has `text` in it. * * Usage: @@ -161,13 +208,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $text - * @see Filesystem::seeInThisFile() + * @see Codeception\Module\Filesystem::seeInThisFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeInThisFile($text) { - $this->scenario->assertion('seeInThisFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInThisFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -177,6 +222,40 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks the strict matching of file contents. + * Unlike `seeInThisFile` will fail if file has something more then expected lines. + * Better to use with HEREDOC strings. + * Matching is done after removing "\r" chars from file content. + * + * ``` php + * openFile('process.pid'); + * $I->seeFileContentsEqual('3192'); + * ?> + * ``` + * + * @param $text + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\Filesystem::seeFileContentsEqual() + * @return \Codeception\Maybe + */ + public function canSeeFileContentsEqual($text) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeFileContentsEqual', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks the strict matching of file contents. * Unlike `seeInThisFile` will fail if file has something more then expected lines. * Better to use with HEREDOC strings. @@ -190,13 +269,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $text - * @see Filesystem::seeFileContentsEqual() + * @see Codeception\Module\Filesystem::seeFileContentsEqual() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeFileContentsEqual($text) { - $this->scenario->assertion('seeFileContentsEqual', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeFileContentsEqual', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -206,23 +283,52 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks If opened file doesn't contain `text` in it * * ``` php * openFile('composer.json'); - * $I->seeInThisFile('codeception/codeception'); + * $I->dontSeeInThisFile('codeception/codeception'); + * ?> + * ``` + * + * @param $text + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\Filesystem::dontSeeInThisFile() + * @return \Codeception\Maybe + */ + public function cantSeeInThisFile($text) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInThisFile', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks If opened file doesn't contain `text` in it + * + * ``` php + * openFile('composer.json'); + * $I->dontSeeInThisFile('codeception/codeception'); * ?> * ``` * * @param $text - * @see Filesystem::dontSeeInThisFile() + * @see Codeception\Module\Filesystem::dontSeeInThisFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeInThisFile($text) { - $this->scenario->action('dontSeeInThisFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInThisFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -232,14 +338,16 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Deletes a file - * @see Filesystem::deleteThisFile() + * @see Codeception\Module\Filesystem::deleteThisFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function deleteThisFile() { - $this->scenario->action('deleteThisFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('deleteThisFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -249,6 +357,38 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if file exists in path. + * Opens a file when it's exists + * + * ``` php + * seeFileFound('UserModel.php','app/models'); + * ?> + * ``` + * + * @param $filename + * @param string $path + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Module\Filesystem::seeFileFound() + * @return \Codeception\Maybe + */ + public function canSeeFileFound($filename, $path = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if file exists in path. * Opens a file when it's exists * @@ -260,13 +400,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $filename * @param string $path - * @see Filesystem::seeFileFound() + * @see Codeception\Module\Filesystem::seeFileFound() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeFileFound($filename, $path = null) { - $this->scenario->assertion('seeFileFound', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -276,6 +414,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Erases directory contents * * ``` php @@ -285,13 +427,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $dirname - * @see Filesystem::cleanDir() + * @see Codeception\Module\Filesystem::cleanDir() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function cleanDir($dirname) { - $this->scenario->action('cleanDir', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('cleanDir', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -301,17 +441,19 @@ class TestGuy extends \Codeception\AbstractGuy /** - * Adds HTTP authentication via username/password. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Authenticates user for HTTP_AUTH * * @param $username * @param $password - * @see Framework::amHttpAuthenticated() + * @see Codeception\Util\Framework::amHttpAuthenticated() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amHttpAuthenticated($username, $password) { - $this->scenario->condition('amHttpAuthenticated', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -321,6 +463,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Opens the page. * Requires relative uri as parameter * @@ -336,13 +482,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $page - * @see Framework::amOnPage() + * @see Codeception\Util\Framework::amOnPage() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function amOnPage($page) { - $this->scenario->condition('amOnPage', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -352,6 +496,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Perform a click on link or button. * Link or button are found by their names or CSS selector. * Submits a form if button is a submit type. @@ -380,13 +528,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * @param $link * @param $context - * @see Framework::click() + * @see Codeception\Util\Framework::click() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function click($link, $context = null) { - $this->scenario->action('click', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('click', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -396,6 +542,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Check if current page contains the text specified. * Specify the css selector to match only specific region. * @@ -406,18 +556,48 @@ class TestGuy extends \Codeception\AbstractGuy * $I->see('Logout'); // I can suppose user is logged in * $I->see('Sign Up','h1'); // I can suppose it's a signup page * $I->see('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::see() + * @return \Codeception\Maybe + */ + public function canSee($text, $selector = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Check if current page contains the text specified. + * Specify the css selector to match only specific region. + * + * Examples: * + * ``` php + * see('Logout'); // I can suppose user is logged in + * $I->see('Sign Up','h1'); // I can suppose it's a signup page + * $I->see('Sign Up','//body/h1'); // with XPath + * ?> * ``` * * @param $text * @param null $selector - * @see Framework::see() + * @see Codeception\Util\Framework::see() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function see($text, $selector = null) { - $this->scenario->assertion('see', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('see', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -427,6 +607,42 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Check if current page doesn't contain the text specified. + * Specify the css selector to match only specific region. + * + * Examples: + * + * ```php + * dontSee('Login'); // I can suppose user is already logged in + * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page + * $I->dontSee('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSee() + * @return \Codeception\Maybe + */ + public function cantSee($text, $selector = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Check if current page doesn't contain the text specified. * Specify the css selector to match only specific region. * @@ -437,17 +653,16 @@ class TestGuy extends \Codeception\AbstractGuy * $I->dontSee('Login'); // I can suppose user is already logged in * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page * $I->dontSee('Sign Up','//body/h1'); // with XPath + * ?> * ``` * * @param $text * @param null $selector - * @see Framework::dontSee() + * @see Codeception\Util\Framework::dontSee() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSee($text, $selector = null) { - $this->scenario->action('dontSee', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -457,6 +672,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if there is a link with text specified. * Specify url to match link with exact this url. * @@ -466,18 +685,47 @@ class TestGuy extends \Codeception\AbstractGuy * seeLink('Logout'); // matches Logout * $I->seeLink('Logout','/logout'); // matches Logout + * ?> + * ``` + * + * @param $text + * @param null $url + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeLink() + * @return \Codeception\Maybe + */ + public function canSeeLink($text, $url = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * + * Checks if there is a link with text specified. + * Specify url to match link with exact this url. + * + * Examples: + * + * ``` php + * seeLink('Logout'); // matches Logout + * $I->seeLink('Logout','/logout'); // matches Logout + * ?> * ``` * * @param $text * @param null $url - * @see Framework::seeLink() + * @see Codeception\Util\Framework::seeLink() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeLink($text, $url = null) { - $this->scenario->assertion('seeLink', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -487,6 +735,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if page doesn't contain the link with text specified. * Specify url to narrow the results. * @@ -495,46 +747,46 @@ class TestGuy extends \Codeception\AbstractGuy * ``` php * dontSeeLink('Logout'); // I suppose user is not logged in - * + * ?> * ``` * * @param $text * @param null $url - * @see Framework::dontSeeLink() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeLink() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeLink($text, $url = null) { - $this->scenario->action('dontSeeLink', func_get_args()); + public function cantSeeLink($text, $url = null) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current uri contains a value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if page doesn't contain the link with text specified. + * Specify url to narrow the results. + * + * Examples: * * ``` php * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); + * $I->dontSeeLink('Logout'); // I suppose user is not logged in * ?> * ``` * - * @param $uri - * @see Framework::seeInCurrentUrl() + * @param $text + * @param null $url + * @see Codeception\Util\Framework::dontSeeLink() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeInCurrentUrl($uri) { - $this->scenario->assertion('seeInCurrentUrl', func_get_args()); + public function dontSeeLink($text, $url = null) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -544,47 +796,56 @@ class TestGuy extends \Codeception\AbstractGuy /** - * Checks that current uri does not contain a value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri contains a value * * ``` php * dontSeeInCurrentUrl('/users/'); + * // to match: /home/dashboard + * $I->seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); * ?> * ``` * * @param $uri - * @see Framework::dontSeeInCurrentUrl() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeInCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeInCurrentUrl($uri) { - $this->scenario->action('dontSeeInCurrentUrl', func_get_args()); + public function canSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current url is equal to value. - * Unlike `seeInCurrentUrl` performs a strict check. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri contains a value * + * ``` php * seeCurrentUrlEquals('/'); + * // to match: /home/dashboard + * $I->seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); * ?> + * ``` * * @param $uri - * @see Framework::seeCurrentUrlEquals() + * @see Codeception\Util\Framework::seeInCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCurrentUrlEquals($uri) { - $this->scenario->assertion('seeCurrentUrlEquals', func_get_args()); + public function seeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -594,46 +855,50 @@ class TestGuy extends \Codeception\AbstractGuy /** - * Checks that current url is not equal to value. - * Unlike `dontSeeInCurrentUrl` performs a strict check. + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri does not contain a value * + * ``` php * dontSeeCurrentUrlEquals('/'); + * $I->dontSeeInCurrentUrl('/users/'); * ?> + * ``` * * @param $uri - * @see Framework::dontSeeCurrentUrlEquals() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeInCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeCurrentUrlEquals($uri) { - $this->scenario->action('dontSeeCurrentUrlEquals', func_get_args()); + public function cantSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); } return new Maybe(); } - - /** - * Checks that current url is matches a RegEx value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current uri does not contain a value * + * ``` php * seeCurrentUrlMatches('~$/users/(\d+)~'); + * $I->dontSeeInCurrentUrl('/users/'); * ?> + * ``` * * @param $uri - * @see Framework::seeCurrentUrlMatches() + * @see Codeception\Util\Framework::dontSeeInCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function seeCurrentUrlMatches($uri) { - $this->scenario->assertion('seeCurrentUrlMatches', func_get_args()); + public function dontSeeInCurrentUrl($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -643,21 +908,166 @@ class TestGuy extends \Codeception\AbstractGuy /** - * Checks that current url does not match a RegEx value + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * + * Checks that current url is equal to value. + * Unlike `seeInCurrentUrl` performs a strict check. + * + * ``` php * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); + * $I->seeCurrentUrlEquals('/'); * ?> + * ``` * * @param $uri - * @see Framework::dontSeeCurrentUrlMatches() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeCurrentUrlEquals() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ - public function dontSeeCurrentUrlMatches($uri) { - $this->scenario->action('dontSeeCurrentUrlMatches', func_get_args()); + public function canSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is equal to value. + * Unlike `seeInCurrentUrl` performs a strict check. + * + * ``` php + * seeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Framework::seeCurrentUrlEquals() + * @return \Codeception\Maybe + */ + public function seeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is not equal to value. + * Unlike `dontSeeInCurrentUrl` performs a strict check. + * + * ``` php + * dontSeeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeCurrentUrlEquals() + * @return \Codeception\Maybe + */ + public function cantSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is not equal to value. + * Unlike `dontSeeInCurrentUrl` performs a strict check. + * + * ``` php + * dontSeeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Framework::dontSeeCurrentUrlEquals() + * @return \Codeception\Maybe + */ + public function dontSeeCurrentUrlEquals($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is matches a RegEx value + * + * ``` php + * seeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeCurrentUrlMatches() + * @return \Codeception\Maybe + */ + public function canSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url is matches a RegEx value + * + * ``` php + * seeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Framework::seeCurrentUrlMatches() + * @return \Codeception\Maybe + */ + public function seeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -667,6 +1077,65 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url does not match a RegEx value + * + * ``` php + * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeCurrentUrlMatches() + * @return \Codeception\Maybe + */ + public function cantSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that current url does not match a RegEx value + * + * ``` php + * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * @see Codeception\Util\Framework::dontSeeCurrentUrlMatches() + * @return \Codeception\Maybe + */ + public function dontSeeCurrentUrlMatches($uri) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Takes a parameters from current URI by RegEx. * If no url provided returns full URI. * @@ -680,13 +1149,11 @@ class TestGuy extends \Codeception\AbstractGuy * @param null $uri * @internal param $url * @return mixed - * @see Framework::grabFromCurrentUrl() + * @see Codeception\Util\Framework::grabFromCurrentUrl() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabFromCurrentUrl($uri = null) { - $this->scenario->action('grabFromCurrentUrl', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -696,6 +1163,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Assert if the specified checkbox is checked. * Use css selector or xpath to match. * @@ -706,17 +1177,46 @@ class TestGuy extends \Codeception\AbstractGuy * $I->seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> + * ``` * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function canSeeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is checked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. + * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> * ``` * * @param $checkbox - * @see Framework::seeCheckboxIsChecked() + * @see Codeception\Util\Framework::seeCheckboxIsChecked() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeCheckboxIsChecked($checkbox) { - $this->scenario->assertion('seeCheckboxIsChecked', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -726,6 +1226,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Assert if the specified checkbox is unchecked. * Use css selector or xpath to match. * @@ -735,17 +1239,45 @@ class TestGuy extends \Codeception\AbstractGuy * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> + * ``` * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeCheckboxIsChecked() + * @return \Codeception\Maybe + */ + public function cantSeeCheckboxIsChecked($checkbox) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Assert if the specified checkbox is unchecked. + * Use css selector or xpath to match. + * + * Example: + * + * ``` php + * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> * ``` * * @param $checkbox - * @see Framework::dontSeeCheckboxIsChecked() + * @see Codeception\Util\Framework::dontSeeCheckboxIsChecked() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeCheckboxIsChecked($checkbox) { - $this->scenario->action('dontSeeCheckboxIsChecked', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -755,6 +1287,44 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that an input field or textarea contains value. + * Field is matched either by label or CSS or Xpath + * + * Example: + * + * ``` php + * seeInField('Body','Type your comment here'); + * $I->seeInField('form textarea[name=body]','Type your comment here'); + * $I->seeInField('form input[type=hidden]','hidden_value'); + * $I->seeInField('#searchform input','Search'); + * $I->seeInField('//form/*[@name=search]','Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeInField() + * @return \Codeception\Maybe + */ + public function canSeeInField($field, $value) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that an input field or textarea contains value. * Field is matched either by label or CSS or Xpath * @@ -772,13 +1342,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $field * @param $value - * @see Framework::seeInField() + * @see Codeception\Util\Framework::seeInField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeInField($field, $value) { - $this->scenario->assertion('seeInField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -788,6 +1356,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that an input field or textarea doesn't contain value. * Field is matched either by label or CSS or Xpath * Example: @@ -804,13 +1376,44 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $field * @param $value - * @see Framework::dontSeeInField() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeInField() + * @return \Codeception\Maybe + */ + public function cantSeeInField($field, $value) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that an input field or textarea doesn't contain value. + * Field is matched either by label or CSS or Xpath + * Example: + * + * ``` php + * dontSeeInField('Body','Type your comment here'); + * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); + * $I->dontSeeInField('form input[type=hidden]','hidden_value'); + * $I->dontSeeInField('#searchform input','Search'); + * $I->dontSeeInField('//form/*[@name=search]','Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * @see Codeception\Util\Framework::dontSeeInField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeInField($field, $value) { - $this->scenario->action('dontSeeInField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -820,6 +1423,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Submits a form located on page. * Specify the form by it's css or xpath selector. * Fill the form fields values as array. @@ -832,7 +1439,7 @@ class TestGuy extends \Codeception\AbstractGuy * * ``` php * submitForm('#login', ['login' => 'davert', 'password' => '123456']); + * $I->submitForm('#login', array('login' => 'davert', 'password' => '123456')); * * ``` * @@ -851,20 +1458,18 @@ class TestGuy extends \Codeception\AbstractGuy * * ``` php * submitForm('#userForm', ['user' => ['login' => 'Davert', 'password' => '123456', 'agree' => true]]); + * $I->submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true))); * * ``` * Note, that pricing plan will be set to Paid, as it's selected on page. * * @param $selector * @param $params - * @see Framework::submitForm() + * @see Codeception\Util\Framework::submitForm() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function submitForm($selector, $params) { - $this->scenario->action('submitForm', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('submitForm', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -874,17 +1479,27 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Fills a text field or textarea with value. + * + * Example: + * + * ``` php + * fillField("//input[@type='text']", "Hello World!"); + * ?> + * ``` * * @param $field * @param $value - * @see Framework::fillField() + * @see Codeception\Util\Framework::fillField() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function fillField($field, $value) { - $this->scenario->action('fillField', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('fillField', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -894,6 +1509,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Selects an option in select tag or in radio button group. * * Example: @@ -906,15 +1525,21 @@ class TestGuy extends \Codeception\AbstractGuy * ?> * ``` * + * Can select multiple options if second argument is array: + * + * ``` php + * selectOption('Which OS do you use?', array('Windows','Linux')); + * ?> + * ``` + * * @param $select * @param $option - * @see Framework::selectOption() + * @see Codeception\Util\Framework::selectOption() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function selectOption($select, $option) { - $this->scenario->action('selectOption', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('selectOption', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -924,6 +1549,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Ticks a checkbox. * For radio buttons use `selectOption` method. * @@ -936,13 +1565,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $option - * @see Framework::checkOption() + * @see Codeception\Util\Framework::checkOption() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function checkOption($option) { - $this->scenario->action('checkOption', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('checkOption', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -952,6 +1579,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Unticks a checkbox. * * Example: @@ -963,13 +1594,11 @@ class TestGuy extends \Codeception\AbstractGuy * ``` * * @param $option - * @see Framework::uncheckOption() + * @see Codeception\Util\Framework::uncheckOption() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function uncheckOption($option) { - $this->scenario->action('uncheckOption', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -979,26 +1608,28 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Attaches file from Codeception data directory to upload field. * * Example: * * ``` php * attachFile('prices.xls'); + * // file is stored in 'tests/_data/prices.xls' + * $I->attachFile('input[@type="file"]', 'prices.xls'); * ?> * ``` * * @param $field * @param $filename - * @see Framework::attachFile() + * @see Codeception\Util\Framework::attachFile() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function attachFile($field, $filename) { - $this->scenario->action('attachFile', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('attachFile', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1008,6 +1639,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * If your page triggers an ajax request, you can perform it manually. * This action sends a GET ajax request with specified params. * @@ -1015,13 +1650,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $uri * @param $params - * @see Framework::sendAjaxGetRequest() + * @see Codeception\Util\Framework::sendAjaxGetRequest() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function sendAjaxGetRequest($uri, $params = null) { - $this->scenario->action('sendAjaxGetRequest', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1031,6 +1664,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * If your page triggers an ajax request, you can perform it manually. * This action sends a POST ajax request with specified params. * Additional params can be passed as array. @@ -1042,20 +1679,18 @@ class TestGuy extends \Codeception\AbstractGuy * * ``` php * sendAjaxPostRequest('/updateSettings', ['notifications' => true]; // POST - * $I->sendAjaxGetRequest('/updateSettings', ['notifications' => true]; // GET + * $I->sendAjaxPostRequest('/updateSettings', array('notifications' => true); // POST + * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true); // GET * * ``` * * @param $uri * @param $params - * @see Framework::sendAjaxPostRequest() + * @see Codeception\Util\Framework::sendAjaxPostRequest() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function sendAjaxPostRequest($uri, $params = null) { - $this->scenario->action('sendAjaxPostRequest', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1065,23 +1700,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- * - * @see Framework::formatResponse() - * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! - */ - public function formatResponse($response) { - $this->scenario->action('formatResponse', func_get_args()); - if ($this->scenario->running()) { - $result = $this->scenario->runStep(); - return new Maybe($result); - } - return new Maybe(); - } - - - /** * Finds and returns text contents of element. * Element is searched by CSS selector, XPath or matcher by regex. * @@ -1097,13 +1719,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $cssOrXPathOrRegex * @return mixed - * @see Framework::grabTextFrom() + * @see Codeception\Util\Framework::grabTextFrom() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabTextFrom($cssOrXPathOrRegex) { - $this->scenario->action('grabTextFrom', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1113,6 +1733,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Finds and returns field and returns it's value. * Searches by field name, then by CSS, then by XPath * @@ -1128,13 +1752,11 @@ class TestGuy extends \Codeception\AbstractGuy * * @param $field * @return mixed - * @see Framework::grabValueFrom() + * @see Codeception\Util\Framework::grabValueFrom() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function grabValueFrom($field) { - $this->scenario->action('grabValueFrom', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1144,22 +1766,50 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if element exists on a page, matching it by CSS or XPath * * ``` php * seeElement('.error'); - * $I->seeElement(//form/input[1]); + * $I->seeElement('//form/input[1]'); * ?> * ``` * @param $selector - * @see Framework::seeElement() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeElement() + * @return \Codeception\Maybe + */ + public function canSeeElement($selector) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if element exists on a page, matching it by CSS or XPath + * + * ``` php + * seeElement('.error'); + * $I->seeElement('//form/input[1]'); + * ?> + * ``` + * @param $selector + * @see Codeception\Util\Framework::seeElement() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeElement($selector) { - $this->scenario->assertion('seeElement', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1169,22 +1819,54 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if element does not exist (or is visible) on a page, matching it by CSS or XPath + * + * Example: + * + * ``` php + * dontSeeElement('.error'); + * $I->dontSeeElement('//form/input[1]'); + * ?> + * ``` + * @param $selector + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeElement() + * @return \Codeception\Maybe + */ + public function cantSeeElement($selector) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if element does not exist (or is visible) on a page, matching it by CSS or XPath * + * Example: + * * ``` php * dontSeeElement('.error'); - * $I->dontSeeElement(//form/input[1]); + * $I->dontSeeElement('//form/input[1]'); * ?> * ``` * @param $selector - * @see Framework::dontSeeElement() + * @see Codeception\Util\Framework::dontSeeElement() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeElement($selector) { - $this->scenario->action('dontSeeElement', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1194,6 +1876,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if option is selected in select field. * * ``` php @@ -1205,13 +1891,39 @@ class TestGuy extends \Codeception\AbstractGuy * @param $selector * @param $optionText * @return mixed - * @see Framework::seeOptionIsSelected() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeOptionIsSelected() + * @return \Codeception\Maybe + */ + public function canSeeOptionIsSelected($select, $optionText) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if option is selected in select field. + * + * ``` php + * seeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * @return mixed + * @see Codeception\Util\Framework::seeOptionIsSelected() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeOptionIsSelected($select, $optionText) { - $this->scenario->assertion('seeOptionIsSelected', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1221,6 +1933,10 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks if option is not selected in select field. * * ``` php @@ -1232,13 +1948,39 @@ class TestGuy extends \Codeception\AbstractGuy * @param $selector * @param $optionText * @return mixed - * @see Framework::dontSeeOptionIsSelected() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeOptionIsSelected() + * @return \Codeception\Maybe + */ + public function cantSeeOptionIsSelected($select, $optionText) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks if option is not selected in select field. + * + * ``` php + * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * @return mixed + * @see Codeception\Util\Framework::dontSeeOptionIsSelected() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function dontSeeOptionIsSelected($select, $optionText) { - $this->scenario->action('dontSeeOptionIsSelected', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1248,14 +1990,34 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Asserts that current page has 404 response status code. + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seePageNotFound() + * @return \Codeception\Maybe + */ + public function canSeePageNotFound() { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Asserts that current page has 404 response status code. - * @see Framework::seePageNotFound() + * @see Codeception\Util\Framework::seePageNotFound() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seePageNotFound() { - $this->scenario->assertion('seePageNotFound', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); @@ -1265,17 +2027,138 @@ class TestGuy extends \Codeception\AbstractGuy /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * * Checks that response code is equal to value provided. * * @param $code * @return mixed - * @see Framework::seeResponseCodeIs() + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeResponseCodeIs() + * @return \Codeception\Maybe + */ + public function canSeeResponseCodeIs($code) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that response code is equal to value provided. + * + * @param $code + * @return mixed + * @see Codeception\Util\Framework::seeResponseCodeIs() * @return \Codeception\Maybe - * ! This method is generated. DO NOT EDIT. ! - * ! Documentation taken from corresponding module ! */ public function seeResponseCodeIs($code) { - $this->scenario->assertion('seeResponseCodeIs', func_get_args()); + $this->scenario->addStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title contains text. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::seeInTitle() + * @return \Codeception\Maybe + */ + public function canSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title contains text. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * @return mixed + * @see Codeception\Util\Framework::seeInTitle() + * @return \Codeception\Maybe + */ + public function seeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + + + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title does not contain text. + * + * @param $title + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see Codeception\Util\Framework::dontSeeInTitle() + * @return \Codeception\Maybe + */ + public function cantSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); + if ($this->scenario->running()) { + $result = $this->scenario->runStep(); + return new Maybe($result); + } + return new Maybe(); + } + /** + * This method is generated. + * Documentation taken from corresponding module. + * ---------------------------------------------- + * + * Checks that page title does not contain text. + * + * @param $title + * @return mixed + * @see Codeception\Util\Framework::dontSeeInTitle() + * @return \Codeception\Maybe + */ + public function dontSeeInTitle($title) { + $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); if ($this->scenario->running()) { $result = $this->scenario->runStep(); return new Maybe($result); diff --git a/apps/basic/tests/unit/CodeGuy.php b/apps/basic/tests/unit/CodeGuy.php index adcd618..613c754 100644 --- a/apps/basic/tests/unit/CodeGuy.php +++ b/apps/basic/tests/unit/CodeGuy.php @@ -1,23 +1,26 @@ beginPage(); ?> @@ -29,14 +30,14 @@ app\config\AppAsset::register($this); ], ]); echo Nav::widget([ - 'options' => ['class' => 'navbar-nav pull-right'], + 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['/site/index']], ['label' => 'About', 'url' => ['/site/about']], ['label' => 'Contact', 'url' => ['/site/contact']], Yii::$app->user->isGuest ? ['label' => 'Login', 'url' => ['/site/login']] : - ['label' => 'Logout (' . Yii::$app->user->identity->username .')' , + ['label' => 'Logout (' . Yii::$app->user->identity->username . ')' , 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']], ], @@ -45,9 +46,9 @@ app\config\AppAsset::register($this); ?>
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]); ?> + ]) ?>
diff --git a/apps/basic/web/index-test.php b/apps/basic/web/index-test.php index 1593164..bd61e0b 100644 --- a/apps/basic/web/index-test.php +++ b/apps/basic/web/index-test.php @@ -13,5 +13,12 @@ require_once(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php'); $config = require(__DIR__ . '/../config/web-test.php'); -$application = new yii\web\Application($config); -$application->run(); +if (isset($this)) { + // run in functional tests + $config['class'] = 'yii\web\Application'; + return $config; +} else { + // run in acceptance tests + $application = new yii\web\Application($config); + $application->run(); +} diff --git a/build/controllers/PhpDocController.php b/build/controllers/PhpDocController.php index 760cb05..c7a2fa7 100644 --- a/build/controllers/PhpDocController.php +++ b/build/controllers/PhpDocController.php @@ -278,11 +278,35 @@ class PhpDocController extends Controller . ' See [[get'.ucfirst($propName).'()]] and [[set'.ucfirst($propName).'()]] for details.'; } } elseif (isset($prop['get'])) { - $note = ' This property is read-only.'; -// $docline .= '-read'; + // check if parent class has setter defined + $c = $className; + $parentSetter = false; + while($parent = get_parent_class($c)) { + if (method_exists($parent, 'set' . ucfirst($propName))) { + $parentSetter = true; + break; + } + $c = $parent; + } + if (!$parentSetter) { + $note = ' This property is read-only.'; +// $docline .= '-read'; + } } elseif (isset($prop['set'])) { - $note = ' This property is write-only.'; -// $docline .= '-write'; + // check if parent class has getter defined + $c = $className; + $parentGetter = false; + while($parent = get_parent_class($c)) { + if (method_exists($parent, 'set' . ucfirst($propName))) { + $parentGetter = true; + break; + } + $c = $parent; + } + if (!$parentGetter) { + $note = ' This property is write-only.'; +// $docline .= '-write'; + } } else { continue; } diff --git a/docs/guide/query-builder.md b/docs/guide/query-builder.md index 7625c0b..ac79f1d 100644 --- a/docs/guide/query-builder.md +++ b/docs/guide/query-builder.md @@ -167,8 +167,8 @@ For ordering results `orderBy` and `addOrderBy` could be used: ```php $query->orderBy([ - 'id' => Query::SORT_ASC, - 'name' => Query::SORT_DESC, + 'id' => SORT_ASC, + 'name' => SORT_DESC, ]); ``` diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 2bf080a..e79259c 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -38,7 +38,7 @@ of `Object` should declare its constructor (if needed) in the following way so t it can be properly configured: ```php -class MyClass extends \yii\Object +class MyClass extends \yii\base\Object { public function __construct($param1, $param2, $config = []) { @@ -109,7 +109,7 @@ Yii::$app->trigger($eventName); If you need to handle all instances of a class instead of the object you can attach a handler like the following: ```php -Event::on([ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT], function ($event) { +Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { Yii::trace(get_class($event->sender) . ' is inserted.'); }); ``` diff --git a/docs/guide/view.md b/docs/guide/view.md index 1b366a6..5951a30 100644 --- a/docs/guide/view.md +++ b/docs/guide/view.md @@ -240,7 +240,7 @@ details on how to define asset bundles in [asset manager](assets.md) section of asset bundle, it's very straightforward: ```php -frontend\config\AppAsset::register($this); +frontend\assets\AppAsset::register($this); ``` ### Layout diff --git a/extensions/bootstrap/composer.json b/extensions/bootstrap/composer.json index b8eaacf..e80de80 100644 --- a/extensions/bootstrap/composer.json +++ b/extensions/bootstrap/composer.json @@ -11,7 +11,12 @@ "irc": "irc://irc.freenode.net/yii", "source": "https://github.com/yiisoft/yii2" }, - "minimum-stability": "dev", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], "require": { "yiisoft/yii2": "*", "twbs/bootstrap": "3.0.*" diff --git a/extensions/composer/composer.json b/extensions/composer/composer.json index ff0785c..652ee14 100644 --- a/extensions/composer/composer.json +++ b/extensions/composer/composer.json @@ -17,7 +17,6 @@ "email": "qiang.xue@gmail.com" } ], - "minimum-stability": "dev", "autoload": { "psr-0": { "yii\\composer\\": "" } }, diff --git a/extensions/debug/composer.json b/extensions/debug/composer.json index e1e57b2..f60d1df 100644 --- a/extensions/debug/composer.json +++ b/extensions/debug/composer.json @@ -11,7 +11,12 @@ "irc": "irc://irc.freenode.net/yii", "source": "https://github.com/yiisoft/yii2" }, - "minimum-stability": "dev", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], "require": { "yiisoft/yii2": "*", "yiisoft/yii2-bootstrap": "*" diff --git a/extensions/debug/panels/ConfigPanel.php b/extensions/debug/panels/ConfigPanel.php index 3ed5b06..59cabf3 100644 --- a/extensions/debug/panels/ConfigPanel.php +++ b/extensions/debug/panels/ConfigPanel.php @@ -63,6 +63,7 @@ EOD; ]; return "

Configuration

\n" . $this->renderData('Application Configuration', $app) . "\n" + . $this->renderExtensions() . $this->renderData('PHP Configuration', $php) . "\n" . $this->getPhpInfo(); } @@ -93,6 +94,18 @@ $rows EOD; } + protected function renderExtensions() + { + if (empty($this->data['extensions'])) { + return ''; + } + $data = []; + foreach ($this->data['extensions'] as $extension) { + $data[$extension['name']] = $extension['version']; + } + return $this->renderData('Installed Extensions', $data) . "\n"; + } + public function save() { return [ @@ -110,6 +123,7 @@ EOD; 'apc' => extension_loaded('apc'), 'memcache' => extension_loaded('memcache'), ], + 'extensions' => Yii::$app->extensions, ]; } } diff --git a/extensions/gii/Generator.php b/extensions/gii/Generator.php index 608f685..05c45a7 100644 --- a/extensions/gii/Generator.php +++ b/extensions/gii/Generator.php @@ -178,8 +178,8 @@ abstract class Generator extends Model public function rules() { return [ - ['template', 'required', 'message' => 'A code template must be selected.'], - ['template', 'validateTemplate'], + [['template'], 'required', 'message' => 'A code template must be selected.'], + [['template'], 'validateTemplate'], ]; } @@ -193,7 +193,7 @@ abstract class Generator extends Model $attributes[] = 'template'; $path = $this->getStickyDataFile(); if (is_file($path)) { - $result = @include($path); + $result = json_decode(file_get_contents($path), true); if (is_array($result)) { foreach ($stickyAttributes as $name) { if (isset($result[$name])) { @@ -218,7 +218,7 @@ abstract class Generator extends Model } $path = $this->getStickyDataFile(); @mkdir(dirname($path), 0755, true); - file_put_contents($path, "getRuntimePath() . '/gii-' . Yii::getVersion() . '/' . str_replace('\\', '-', get_class($this)) . '.php'; + return Yii::$app->getRuntimePath() . '/gii-' . Yii::getVersion() . '/' . str_replace('\\', '-', get_class($this)) . '.json'; } /** diff --git a/extensions/gii/composer.json b/extensions/gii/composer.json index fc74a7e..8654621 100644 --- a/extensions/gii/composer.json +++ b/extensions/gii/composer.json @@ -11,7 +11,12 @@ "irc": "irc://irc.freenode.net/yii", "source": "https://github.com/yiisoft/yii2" }, - "minimum-stability": "dev", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], "require": { "yiisoft/yii2": "*", "yiisoft/yii2-bootstrap": "*" diff --git a/extensions/gii/generators/controller/Generator.php b/extensions/gii/generators/controller/Generator.php index f23bcd4..08b29d5 100644 --- a/extensions/gii/generators/controller/Generator.php +++ b/extensions/gii/generators/controller/Generator.php @@ -69,12 +69,12 @@ class Generator extends \yii\gii\Generator public function rules() { return array_merge(parent::rules(), [ - ['controller, actions, baseClass, ns', 'filter', 'filter' => 'trim'], - ['controller, baseClass', 'required'], - ['controller', 'match', 'pattern' => '/^[a-z\\-\\/]*$/', 'message' => 'Only a-z, dashes (-) and slashes (/) are allowed.'], - ['actions', 'match', 'pattern' => '/^[a-z\\-,\\s]*$/', 'message' => 'Only a-z, dashes (-), spaces and commas are allowed.'], - ['baseClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - ['ns', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['controller', 'actions', 'baseClass', 'ns'], 'filter', 'filter' => 'trim'], + [['controller', 'baseClass'], 'required'], + [['controller'], 'match', 'pattern' => '/^[a-z\\-\\/]*$/', 'message' => 'Only a-z, dashes (-) and slashes (/) are allowed.'], + [['actions'], 'match', 'pattern' => '/^[a-z\\-,\\s]*$/', 'message' => 'Only a-z, dashes (-), spaces and commas are allowed.'], + [['baseClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['ns'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], ]); } diff --git a/extensions/gii/generators/crud/Generator.php b/extensions/gii/generators/crud/Generator.php index 3fd5e41..1925de2 100644 --- a/extensions/gii/generators/crud/Generator.php +++ b/extensions/gii/generators/crud/Generator.php @@ -42,17 +42,17 @@ class Generator extends \yii\gii\Generator public function rules() { return array_merge(parent::rules(), [ - ['moduleID, controllerClass, modelClass, searchModelClass, baseControllerClass', 'filter', 'filter' => 'trim'], - ['modelClass, searchModelClass, controllerClass, baseControllerClass, indexWidgetType', 'required'], - ['searchModelClass', 'compare', 'compareAttribute' => 'modelClass', 'operator' => '!==', 'message' => 'Search Model Class must not be equal to Model Class.'], - ['modelClass, controllerClass, baseControllerClass, searchModelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - ['modelClass', 'validateClass', 'params' => ['extends' => ActiveRecord::className()]], - ['baseControllerClass', 'validateClass', 'params' => ['extends' => Controller::className()]], - ['controllerClass', 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'], - ['controllerClass, searchModelClass', 'validateNewClass'], - ['indexWidgetType', 'in', 'range' => ['grid', 'list']], - ['modelClass', 'validateModelClass'], - ['moduleID', 'validateModuleID'], + [['moduleID', 'controllerClass', 'modelClass', 'searchModelClass', 'baseControllerClass'], 'filter', 'filter' => 'trim'], + [['modelClass', 'searchModelClass', 'controllerClass', 'baseControllerClass', 'indexWidgetType'], 'required'], + [['searchModelClass'], 'compare', 'compareAttribute' => 'modelClass', 'operator' => '!==', 'message' => 'Search Model Class must not be equal to Model Class.'], + [['modelClass', 'controllerClass', 'baseControllerClass', 'searchModelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['modelClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]], + [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]], + [['controllerClass'], 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'], + [['controllerClass', 'searchModelClass'], 'validateNewClass'], + [['indexWidgetType'], 'in', 'range' => ['grid', 'list']], + [['modelClass'], 'validateModelClass'], + [['moduleID'], 'validateModuleID'], ]); } @@ -278,7 +278,7 @@ class Generator extends \yii\gii\Generator $rules = []; foreach ($types as $type => $columns) { - $rules[] = "['" . implode(', ', $columns) . "', '$type']"; + $rules[] = "[['" . implode("', '", $columns) . "'], '$type']"; } return $rules; @@ -341,7 +341,9 @@ class Generator extends \yii\gii\Generator public function generateUrlParams() { - $pks = $this->getTableSchema()->primaryKey; + /** @var ActiveRecord $class */ + $class = $this->modelClass; + $pks = $class::primaryKey(); if (count($pks) === 1) { return "'id' => \$model->{$pks[0]}"; } else { @@ -355,7 +357,9 @@ class Generator extends \yii\gii\Generator public function generateActionParams() { - $pks = $this->getTableSchema()->primaryKey; + /** @var ActiveRecord $class */ + $class = $this->modelClass; + $pks = $class::primaryKey(); if (count($pks) === 1) { return '$id'; } else { @@ -366,7 +370,9 @@ class Generator extends \yii\gii\Generator public function generateActionParamComments() { $table = $this->getTableSchema(); - $pks = $table->primaryKey; + /** @var ActiveRecord $class */ + $class = $this->modelClass; + $pks = $class::primaryKey(); if (count($pks) === 1) { return ['@param ' . $table->columns[$pks[0]]->phpType . ' $id']; } else { diff --git a/extensions/gii/generators/crud/templates/controller.php b/extensions/gii/generators/crud/templates/controller.php index 918f840..f975fd1 100644 --- a/extensions/gii/generators/crud/templates/controller.php +++ b/extensions/gii/generators/crud/templates/controller.php @@ -28,7 +28,6 @@ namespace controllerClass, '\\')) ?> use modelClass, '\\') ?>; use searchModelClass, '\\') ?> as ; -use yii\data\ActiveDataProvider; use baseControllerClass, '\\') ?>; use yii\web\HttpException; use yii\web\VerbFilter; diff --git a/extensions/gii/generators/form/Generator.php b/extensions/gii/generators/form/Generator.php index 749f9d8..3bc0be6 100644 --- a/extensions/gii/generators/form/Generator.php +++ b/extensions/gii/generators/form/Generator.php @@ -60,14 +60,14 @@ class Generator extends \yii\gii\Generator public function rules() { return array_merge(parent::rules(), [ - ['modelClass, viewName, scenarioName, viewPath', 'filter', 'filter' => 'trim'], - ['modelClass, viewName, viewPath', 'required'], - ['modelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - ['modelClass', 'validateClass', 'params' => ['extends' => Model::className()]], - ['viewName', 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'], - ['viewPath', 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'], - ['viewPath', 'validateViewPath'], - ['scenarioName', 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], + [['modelClass', 'viewName', 'scenarioName', 'viewPath'], 'filter', 'filter' => 'trim'], + [['modelClass', 'viewName', 'viewPath'], 'required'], + [['modelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['modelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], + [['viewName'], 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'], + [['viewPath'], 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'], + [['viewPath'], 'validateViewPath'], + [['scenarioName'], 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], ]); } diff --git a/extensions/gii/generators/model/Generator.php b/extensions/gii/generators/model/Generator.php index 4f628d7..32ba2e5 100644 --- a/extensions/gii/generators/model/Generator.php +++ b/extensions/gii/generators/model/Generator.php @@ -53,17 +53,17 @@ class Generator extends \yii\gii\Generator public function rules() { return array_merge(parent::rules(), [ - ['db, ns, tableName, modelClass, baseClass', 'filter', 'filter' => 'trim'], - ['db, ns, tableName, baseClass', 'required'], - ['db, modelClass', 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'], - ['ns, baseClass', 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'], - ['tableName', 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'], - ['db', 'validateDb'], - ['ns', 'validateNamespace'], - ['tableName', 'validateTableName'], - ['modelClass', 'validateModelClass', 'skipOnEmpty' => false], - ['baseClass', 'validateClass', 'params' => ['extends' => ActiveRecord::className()]], - ['generateRelations, generateLabelsFromComments', 'boolean'], + [['db', 'ns', 'tableName', 'modelClass', 'baseClass'], 'filter', 'filter' => 'trim'], + [['db', 'ns', 'tableName', 'baseClass'], 'required'], + [['db', 'modelClass'], 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'], + [['ns', 'baseClass'], 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['tableName'], 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'], + [['db'], 'validateDb'], + [['ns'], 'validateNamespace'], + [['tableName'], 'validateTableName'], + [['modelClass'], 'validateModelClass', 'skipOnEmpty' => false], + [['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]], + [['generateRelations', 'generateLabelsFromComments'], 'boolean'], ]); } @@ -104,7 +104,7 @@ class Generator extends \yii\gii\Generator 'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.', 'generateRelations' => 'This indicates whether the generator should generate relations based on foreign key constraints it detects in the database. Note that if your database contains too many tables, - you may want to uncheck this option to accelerate the code generation proc ess.', + you may want to uncheck this option to accelerate the code generation process.', 'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels by using the comments of the corresponding DB columns.', ]; @@ -237,10 +237,10 @@ class Generator extends \yii\gii\Generator $rules = []; foreach ($types as $type => $columns) { - $rules[] = "['" . implode(', ', $columns) . "', '$type']"; + $rules[] = "[['" . implode("', '", $columns) . "'], '$type']"; } foreach ($lengths as $length => $columns) { - $rules[] = "['" . implode(', ', $columns) . "', 'string', 'max' => $length]"; + $rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]"; } return $rules; diff --git a/extensions/gii/generators/module/Generator.php b/extensions/gii/generators/module/Generator.php index fcb385d..5946e07 100644 --- a/extensions/gii/generators/module/Generator.php +++ b/extensions/gii/generators/module/Generator.php @@ -45,11 +45,11 @@ class Generator extends \yii\gii\Generator public function rules() { return array_merge(parent::rules(), [ - ['moduleID, moduleClass', 'filter', 'filter' => 'trim'], - ['moduleID, moduleClass', 'required'], - ['moduleID', 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], - ['moduleClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - ['moduleClass', 'validateModuleClass'], + [['moduleID', 'moduleClass'], 'filter', 'filter' => 'trim'], + [['moduleID', 'moduleClass'], 'required'], + [['moduleID'], 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], + [['moduleClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], + [['moduleClass'], 'validateModuleClass'], ]); } @@ -139,7 +139,7 @@ EOD; */ public function validateModuleClass() { - if (strpos($this->moduleClass, '\\') === false || Yii::getAlias('@' . str_replace('\\', '/', $this->moduleClass)) === false) { + if (strpos($this->moduleClass, '\\') === false || Yii::getAlias('@' . str_replace('\\', '/', $this->moduleClass), false) === false) { $this->addError('moduleClass', 'Module class must be properly namespaced.'); } if (substr($this->moduleClass, -1, 1) == '\\') { diff --git a/extensions/gii/views/default/index.php b/extensions/gii/views/default/index.php index f6d6855..2e48816 100644 --- a/extensions/gii/views/default/index.php +++ b/extensions/gii/views/default/index.php @@ -2,10 +2,10 @@ use yii\helpers\Html; /** - * @var $this \yii\web\View - * @var $content string - * @var yii\gii\Generator[] $generators - * @var yii\gii\Generator $activeGenerator + * @var \yii\web\View $this + * @var \yii\gii\Generator[] $generators + * @var \yii\gii\Generator $activeGenerator + * @var string $content */ $generators = Yii::$app->controller->module->generators; $activeGenerator = Yii::$app->controller->generator; diff --git a/extensions/gii/views/default/view/files.php b/extensions/gii/views/default/view/files.php index 3da2d97..d8d5f0f 100644 --- a/extensions/gii/views/default/view/files.php +++ b/extensions/gii/views/default/view/files.php @@ -4,8 +4,8 @@ use yii\helpers\Html; use yii\gii\CodeFile; /** - * @var $this \yii\web\View - * @var $generator \yii\gii\Generator + * @var \yii\web\View $this + * @var \yii\gii\Generator $generator * @var CodeFile[] $files * @var array $answers */ diff --git a/extensions/gii/views/layouts/generator.php b/extensions/gii/views/layouts/generator.php index c03f09a..245cd29 100644 --- a/extensions/gii/views/layouts/generator.php +++ b/extensions/gii/views/layouts/generator.php @@ -2,10 +2,10 @@ use yii\helpers\Html; /** - * @var $this \yii\web\View - * @var $content string - * @var yii\gii\Generator[] $generators - * @var yii\gii\Generator $activeGenerator + * @var \yii\web\View $this + * @var \yii\gii\Generator[] $generators + * @var \yii\gii\Generator $activeGenerator + * @var string $content */ $generators = Yii::$app->controller->module->generators; $activeGenerator = Yii::$app->controller->generator; diff --git a/extensions/gii/views/layouts/main.php b/extensions/gii/views/layouts/main.php index 69afeb2..983475b 100644 --- a/extensions/gii/views/layouts/main.php +++ b/extensions/gii/views/layouts/main.php @@ -4,8 +4,8 @@ use yii\bootstrap\Nav; use yii\helpers\Html; /** - * @var $this \yii\web\View - * @var $content string + * @var \yii\web\View $this + * @var string $content */ $asset = yii\gii\GiiAsset::register($this); ?> @@ -26,7 +26,7 @@ NavBar::begin([ 'options' => ['class' => 'navbar-inverse navbar-fixed-top'], ]); echo Nav::widget([ - 'options' => ['class' => 'nav navbar-nav pull-right'], + 'options' => ['class' => 'nav navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['default/index']], ['label' => 'Help', 'url' => 'http://www.yiiframework.com/doc/guide/topics.gii'], diff --git a/extensions/jui/composer.json b/extensions/jui/composer.json index 0888ab1..ff54422 100644 --- a/extensions/jui/composer.json +++ b/extensions/jui/composer.json @@ -11,7 +11,12 @@ "irc": "irc://irc.freenode.net/yii", "source": "https://github.com/yiisoft/yii2" }, - "minimum-stability": "dev", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], "require": { "yiisoft/yii2": "*" }, diff --git a/extensions/smarty/composer.json b/extensions/smarty/composer.json index 566187a..88b75a3 100644 --- a/extensions/smarty/composer.json +++ b/extensions/smarty/composer.json @@ -17,10 +17,9 @@ "email": "sam@rmcreative.ru" } ], - "minimum-stability": "dev", "require": { "yiisoft/yii2": "*", - "smarty/smarty": ">=v3.1.13" + "smarty/smarty": "*" }, "autoload": { "psr-0": { "yii\\smarty\\": "" } diff --git a/extensions/swiftmailer/Mailer.php b/extensions/swiftmailer/Mailer.php index 58f0f23..3418d8d 100644 --- a/extensions/swiftmailer/Mailer.php +++ b/extensions/swiftmailer/Mailer.php @@ -104,13 +104,13 @@ class Mailer extends BaseMailer /** * @inheritdoc */ - public function send($message) + protected function sendMessage($message) { $address = $message->getTo(); if (is_array($address)) { - $address = implode(', ', $address); + $address = implode(', ', array_keys($address)); } - Yii::trace('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); + Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); return $this->getSwiftMailer()->send($message->getSwiftMessage()) > 0; } @@ -145,7 +145,7 @@ class Mailer extends BaseMailer $transport->$name = $value; } else { $setter = 'set' . $name; - if (method_exists($transport, $setter)) { + if (method_exists($transport, $setter) || method_exists($transport, '__call')) { $transport->$setter($value); } else { throw new InvalidConfigException('Setting unknown property: ' . get_class($transport) . '::' . $name); diff --git a/extensions/swiftmailer/Message.php b/extensions/swiftmailer/Message.php index 067b50e..b0ebd63 100644 --- a/extensions/swiftmailer/Message.php +++ b/extensions/swiftmailer/Message.php @@ -44,7 +44,7 @@ class Message extends BaseMessage */ public function getCharset() { - $this->getSwiftMessage()->getCharset(); + return $this->getSwiftMessage()->getCharset(); } /** @@ -61,7 +61,7 @@ class Message extends BaseMessage */ public function getFrom() { - $this->getSwiftMessage()->getFrom(); + return $this->getSwiftMessage()->getFrom(); } /** @@ -78,7 +78,7 @@ class Message extends BaseMessage */ public function getReplyTo() { - $this->getSwiftMessage()->getReplyTo(); + return $this->getSwiftMessage()->getReplyTo(); } /** @@ -95,7 +95,7 @@ class Message extends BaseMessage */ public function getTo() { - $this->getSwiftMessage()->getTo(); + return $this->getSwiftMessage()->getTo(); } /** @@ -112,7 +112,7 @@ class Message extends BaseMessage */ public function getCc() { - $this->getSwiftMessage()->getCc(); + return $this->getSwiftMessage()->getCc(); } /** @@ -129,7 +129,7 @@ class Message extends BaseMessage */ public function getBcc() { - $this->getSwiftMessage()->getBcc(); + return $this->getSwiftMessage()->getBcc(); } /** @@ -146,7 +146,7 @@ class Message extends BaseMessage */ public function getSubject() { - $this->getSwiftMessage()->getSubject(); + return $this->getSwiftMessage()->getSubject(); } /** @@ -192,7 +192,7 @@ class Message extends BaseMessage $partFound = false; foreach ($parts as $key => $part) { if (!($part instanceof \Swift_Mime_Attachment)) { - /* @var $part \Swift_Mime_MimePart */ + /* @var \Swift_Mime_MimePart $part */ if ($part->getContentType() == $contentType) { unset($parts[$key]); $partFound = true; diff --git a/extensions/swiftmailer/composer.json b/extensions/swiftmailer/composer.json index e995b2f..5a47397 100644 --- a/extensions/swiftmailer/composer.json +++ b/extensions/swiftmailer/composer.json @@ -17,10 +17,9 @@ "email": "klimov.paul@gmail.com" } ], - "minimum-stability": "dev", "require": { "yiisoft/yii2": "*", - "swiftmailer/swiftmailer": "@stable" + "swiftmailer/swiftmailer": "*" }, "autoload": { "psr-0": { "yii\\swiftmailer\\": "" } diff --git a/extensions/twig/composer.json b/extensions/twig/composer.json index c57c65d..8fe6431 100644 --- a/extensions/twig/composer.json +++ b/extensions/twig/composer.json @@ -17,10 +17,9 @@ "email": "sam@rmcreative.ru" } ], - "minimum-stability": "dev", "require": { "yiisoft/yii2": "*", - "twig/twig": "1.13.*" + "twig/twig": "*" }, "autoload": { "psr-0": { "yii\\twig\\": "" } diff --git a/framework/composer.json b/framework/composer.json index 9e6e3c4..637471c 100644 --- a/framework/composer.json +++ b/framework/composer.json @@ -65,17 +65,15 @@ }, "require": { "php": ">=5.4.0", - "yiisoft/yii2-composer": "*", - "yiisoft/jquery": "1.10.*", "ext-mbstring": "*", "lib-pcre": "*", - "phpspec/php-diff": "dev-master", - "ezyang/htmlpurifier": "4.5.*" + "yiisoft/yii2-composer": "*", + "yiisoft/jquery": "1.10.*", + "phpspec/php-diff": ">=1.0.2", + "ezyang/htmlpurifier": "4.5.*", + "michelf/php-markdown": "1.3.*" }, "autoload": { "psr-0": { "yii\\": "/" } - }, - "suggest": { - "michelf/php-markdown": "Required by Markdown." } } diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index 011a9c7..357a1e7 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -63,8 +63,7 @@ class BaseYii * The array keys are the class names (without leading backslashes), and the array values * are the corresponding class file paths (or path aliases). This property mainly affects * how [[autoload()]] works. - * @see import - * @see autoload + * @see autoload() */ public static $classMap = []; /** @@ -73,8 +72,8 @@ class BaseYii public static $app; /** * @var array registered path aliases - * @see getAlias - * @see setAlias + * @see getAlias() + * @see setAlias() */ public static $aliases = ['@yii' => __DIR__]; /** @@ -95,7 +94,7 @@ class BaseYii * ] * ~~~ * - * @see createObject + * @see createObject() */ public static $objectConfig = []; @@ -136,7 +135,7 @@ class BaseYii * If this is false and an invalid alias is given, false will be returned by this method. * @return string|boolean the path corresponding to the alias, false if the root alias is not previously registered. * @throws InvalidParamException if the alias is invalid while $throwException is true. - * @see setAlias + * @see setAlias() */ public static function getAlias($alias, $throwException = true) { @@ -219,7 +218,7 @@ class BaseYii * actual path first by calling [[getAlias()]]. * * @throws InvalidParamException if $path is an invalid alias. - * @see getAlias + * @see getAlias() */ public static function setAlias($alias, $path) { @@ -368,7 +367,7 @@ class BaseYii } if (($n = func_num_args()) > 1) { - /** @var $reflection \ReflectionClass */ + /** @var \ReflectionClass $reflection */ if (isset($reflections[$class])) { $reflection = $reflections[$class]; } else { @@ -450,7 +449,7 @@ class BaseYii * ~~~ * @param string $token token for the code block * @param string $category the category of this log message - * @see endProfile + * @see endProfile() */ public static function beginProfile($token, $category = 'application') { @@ -462,7 +461,7 @@ class BaseYii * This has to be matched with a previous call to [[beginProfile]] with the same category name. * @param string $token token for the code block * @param string $category the category of this log message - * @see beginProfile + * @see beginProfile() */ public static function endProfile($token, $category = 'application') { diff --git a/framework/yii/base/ActionFilter.php b/framework/yii/base/ActionFilter.php index 60be177..648211c 100644 --- a/framework/yii/base/ActionFilter.php +++ b/framework/yii/base/ActionFilter.php @@ -8,6 +8,11 @@ namespace yii\base; /** + * ActionFilter provides a base implementation for action filters that can be added to a controller + * to handle the `beforeAction` event. + * + * Check implementation of [[AccessControl]], [[PageCache]] and [[HttpCache]] as examples on how to use it. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index 8826d5a..b729158 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -15,6 +15,7 @@ use yii\web\HttpException; * 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 string $basePath The root directory of the application. * @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. @@ -258,9 +259,10 @@ abstract class Application extends Module } /** - * Sets the root directory of the applicaition and the @app alias. + * Sets the root directory of the application and the @app alias. * This method can only be invoked at the beginning of the constructor. * @param string $path the root directory of the application. + * @property string the root directory of the application. * @throws InvalidParamException if the directory does not exist. */ public function setBasePath($path) @@ -425,7 +427,7 @@ abstract class Application extends Module /** * Returns the view object. - * @return View the view object that is used to render various view files. + * @return View|\yii\web\View the view object that is used to render various view files. */ public function getView() { @@ -614,10 +616,8 @@ abstract class Application extends Module { $category = get_class($exception); if ($exception instanceof HttpException) { - /** @var $exception HttpException */ $category .= '\\' . $exception->statusCode; } elseif ($exception instanceof \ErrorException) { - /** @var $exception \ErrorException */ $category .= '\\' . $exception->getSeverity(); } Yii::error((string)$exception, $category); diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php index b67a09f..2ef4ead 100644 --- a/framework/yii/base/Component.php +++ b/framework/yii/base/Component.php @@ -10,6 +10,8 @@ namespace yii\base; use Yii; /** + * Component is the base class that implements the *property*, *event* and *behavior* features. + * * @include @yii/base/Component.md * * @property Behavior[] $behaviors List of behaviors attached to this component. This property is read-only. @@ -41,7 +43,7 @@ class Component extends Object * @return mixed the property value or the value of a behavior's property * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is write-only. - * @see __set + * @see __set() */ public function __get($name) { @@ -80,7 +82,7 @@ class Component extends Object * @param mixed $value the property value * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is read-only. - * @see __get + * @see __get() */ public function __set($name, $value) { @@ -225,8 +227,8 @@ class Component extends Object * @param boolean $checkVars whether to treat member variables as properties * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component * @return boolean whether the property is defined - * @see canGetProperty - * @see canSetProperty + * @see canGetProperty() + * @see canSetProperty() */ public function hasProperty($name, $checkVars = true, $checkBehaviors = true) { @@ -246,7 +248,7 @@ class Component extends Object * @param boolean $checkVars whether to treat member variables as properties * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component * @return boolean whether the property can be read - * @see canSetProperty + * @see canSetProperty() */ public function canGetProperty($name, $checkVars = true, $checkBehaviors = true) { @@ -276,7 +278,7 @@ class Component extends Object * @param boolean $checkVars whether to treat member variables as properties * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component * @return boolean whether the property can be written - * @see canGetProperty + * @see canGetProperty() */ public function canSetProperty($name, $checkVars = true, $checkBehaviors = true) { @@ -492,7 +494,7 @@ class Component extends Object * - an object configuration array that will be passed to [[Yii::createObject()]] to create the behavior object. * * @return Behavior the behavior object - * @see detachBehavior + * @see detachBehavior() */ public function attachBehavior($name, $behavior) { @@ -505,7 +507,7 @@ class Component extends Object * Each behavior is indexed by its name and should be a [[Behavior]] object, * a string specifying the behavior class, or an configuration array for creating the behavior. * @param array $behaviors list of behaviors to be attached to the component - * @see attachBehavior + * @see attachBehavior() */ public function attachBehaviors($behaviors) { diff --git a/framework/yii/base/Controller.php b/framework/yii/base/Controller.php index d2f491c..c8f2d48 100644 --- a/framework/yii/base/Controller.php +++ b/framework/yii/base/Controller.php @@ -111,7 +111,7 @@ class Controller extends Component implements ViewContextInterface * @param array $params the parameters (name-value pairs) to be passed to the action. * @return mixed the result of the action * @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully. - * @see createAction + * @see createAction() */ public function runAction($id, $params = []) { @@ -149,8 +149,7 @@ class Controller extends Component implements ViewContextInterface * @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'. * @param array $params the parameters to be passed to the action. * @return mixed the result of the action - * @see runAction - * @see forward + * @see runAction() */ public function run($route, $params = []) { diff --git a/framework/yii/base/ErrorHandler.php b/framework/yii/base/ErrorHandler.php index ead9646..c96ca5e 100644 --- a/framework/yii/base/ErrorHandler.php +++ b/framework/yii/base/ErrorHandler.php @@ -16,6 +16,9 @@ use yii\web\HttpException; * ErrorHandler displays these errors using appropriate views based on the * nature of the errors and the mode the application runs at. * + * ErrorHandler is configured as an application component in [[yii\base\Application]] by default. + * You can access that instance via `Yii::$app->errorHandler`. + * * @author Qiang Xue * @author Timur Ruziev * @since 2.0 diff --git a/framework/yii/base/Formatter.php b/framework/yii/base/Formatter.php index 18faaff..30df3c3 100644 --- a/framework/yii/base/Formatter.php +++ b/framework/yii/base/Formatter.php @@ -19,6 +19,9 @@ use yii\helpers\Html; * The behavior of some of them may be configured via the properties of Formatter. For example, * by configuring [[dateFormat]], one may control how [[asDate()]] formats the value into a date string. * + * Formatter is configured as an application component in [[yii\base\Application]] by default. + * You can access that instance via `Yii::$app->formatter`. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php index 99c1df9..b366a9f 100644 --- a/framework/yii/base/Model.php +++ b/framework/yii/base/Model.php @@ -46,7 +46,8 @@ use yii\validators\Validator; * @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. + * @property ArrayObject|\yii\validators\Validator[] $validators All the validators declared in the model. + * This property is read-only. * * @author Qiang Xue * @since 2.0 @@ -91,19 +92,19 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * * ~~~ * [ - * 'attribute list', + * ['attribute1', 'attribute2'], * 'validator type', - * 'on' => 'scenario name', + * 'on' => ['scenario1', 'scenario2'], * ...other parameters... * ] * ~~~ * * where * - * - attribute list: required, specifies the attributes (separated by commas) to be validated; + * - attribute list: required, specifies the attributes array to be validated, for single attribute you can pass string; * - validator type: required, specifies the validator to be used. It can be the name of a model * class method, the name of a built-in validator, or a validator class name (or its path alias). - * - on: optional, specifies the [[scenario|scenarios]] (separated by commas) when the validation + * - on: optional, specifies the [[scenario|scenarios]] array when the validation * rule can be applied. If this option is not set, the rule will apply to all scenarios. * - additional name-value pairs can be specified to initialize the corresponding validator properties. * Please refer to individual validator class API for possible properties. @@ -128,7 +129,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * ~~~ * [ * // built-in "required" validator - * ['username', 'required'], + * [['username', 'password'], 'required'], * // built-in "string" validator customized with "min" and "max" properties * ['username', 'string', 'min' => 3, 'max' => 12], * // built-in "compare" validator that is used in "register" scenario only @@ -144,7 +145,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * merge the parent rules with child rules using functions such as `array_merge()`. * * @return array validation rules - * @see scenarios + * @see scenarios() */ public function rules() { @@ -255,7 +256,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * merge the parent labels with child labels using functions such as `array_merge()`. * * @return array attribute labels (name => label) - * @see generateAttributeLabel + * @see generateAttributeLabel() */ public function attributeLabels() { @@ -349,7 +350,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * $model->validators[] = $newValidator; * ~~~ * - * @return ArrayObject all the validators declared in the model. + * @return ArrayObject|\yii\validators\Validator[] all the validators declared in the model. */ public function getValidators() { @@ -369,7 +370,6 @@ class Model extends Component implements IteratorAggregate, ArrayAccess { $validators = []; $scenario = $this->getScenario(); - /** @var $validator Validator */ foreach ($this->getValidators() as $validator) { if ($validator->isActive($scenario) && ($attribute === null || in_array($attribute, $validator->attributes, true))) { $validators[] = $validator; @@ -391,7 +391,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess if ($rule instanceof Validator) { $validators->append($rule); } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type - $validator = Validator::createValidator($rule[1], $this, $rule[0], array_slice($rule, 2)); + $validator = Validator::createValidator($rule[1], $this, (array) $rule[0], array_slice($rule, 2)); $validators->append($validator); } else { throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.'); @@ -444,8 +444,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * Returns the text label for the specified attribute. * @param string $attribute the attribute name * @return string the attribute label - * @see generateAttributeLabel - * @see attributeLabels + * @see generateAttributeLabel() + * @see attributeLabels() */ public function getAttributeLabel($attribute) { @@ -483,8 +483,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * ] * ~~~ * - * @see getFirstErrors - * @see getFirstError + * @see getFirstErrors() + * @see getFirstError() */ public function getErrors($attribute = null) { @@ -498,8 +498,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess /** * 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. - * @see getErrors - * @see getFirstError + * @see getErrors() + * @see getFirstError() */ public function getFirstErrors() { @@ -520,8 +520,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * Returns the first error of the specified attribute. * @param string $attribute attribute name. * @return string the error message. Null is returned if no error. - * @see getErrors - * @see getFirstErrors + * @see getErrors() + * @see getFirstErrors() */ public function getFirstError($attribute) { diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index b3e28f6..1e5302c 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -578,7 +578,7 @@ abstract class Module extends Component { $parts = $this->createController($route); if (is_array($parts)) { - /** @var $controller Controller */ + /** @var Controller $controller */ list($controller, $actionID) = $parts; $oldController = Yii::$app->controller; Yii::$app->controller = $controller; diff --git a/framework/yii/base/Object.php b/framework/yii/base/Object.php index f0bd92b..06fca50 100644 --- a/framework/yii/base/Object.php +++ b/framework/yii/base/Object.php @@ -10,7 +10,10 @@ namespace yii\base; use Yii; /** + * Object is the base class that implements the *property* feature. + * * @include @yii/base/Object.md + * * @author Qiang Xue * @since 2.0 */ @@ -64,7 +67,7 @@ class Object implements Arrayable * @return mixed the property value * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is write-only - * @see __set + * @see __set() */ public function __get($name) { @@ -87,7 +90,7 @@ class Object implements Arrayable * @param mixed $value the property value * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is read-only - * @see __get + * @see __get() */ public function __set($name, $value) { @@ -168,8 +171,8 @@ class Object implements Arrayable * @param string $name the property name * @param boolean $checkVars whether to treat member variables as properties * @return boolean whether the property is defined - * @see canGetProperty - * @see canSetProperty + * @see canGetProperty() + * @see canSetProperty() */ public function hasProperty($name, $checkVars = true) { @@ -187,7 +190,7 @@ class Object implements Arrayable * @param string $name the property name * @param boolean $checkVars whether to treat member variables as properties * @return boolean whether the property can be read - * @see canSetProperty + * @see canSetProperty() */ public function canGetProperty($name, $checkVars = true) { @@ -205,7 +208,7 @@ class Object implements Arrayable * @param string $name the property name * @param boolean $checkVars whether to treat member variables as properties * @return boolean whether the property can be written - * @see canGetProperty + * @see canGetProperty() */ public function canSetProperty($name, $checkVars = true) { diff --git a/framework/yii/base/Request.php b/framework/yii/base/Request.php index 0d660d6..cd3ffdc 100644 --- a/framework/yii/base/Request.php +++ b/framework/yii/base/Request.php @@ -8,6 +8,7 @@ namespace yii\base; /** + * Request represents a request that is handled by an [[Application]]. * * @property boolean $isConsoleRequest The value indicating whether the current request is made via console. * @property string $scriptFile Entry script file path (processed w/ realpath()). diff --git a/framework/yii/base/Response.php b/framework/yii/base/Response.php index 467de9e..1403b69 100644 --- a/framework/yii/base/Response.php +++ b/framework/yii/base/Response.php @@ -8,6 +8,8 @@ namespace yii\base; /** + * Response represents the response of an [[Application]] to a [[Request]]. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php index c22b3c0..61d9373 100644 --- a/framework/yii/base/View.php +++ b/framework/yii/base/View.php @@ -123,7 +123,7 @@ class View extends Component * existing [[context]] will be used. * @return string the rendering result * @throws InvalidParamException if the view cannot be resolved or the view file does not exist. - * @see renderFile + * @see renderFile() */ public function render($view, $params = [], $context = null) { @@ -410,7 +410,7 @@ class View extends Component { $properties['id'] = $id; $properties['view'] = $this; - /** @var $cache FragmentCache */ + /** @var FragmentCache $cache */ $cache = FragmentCache::begin($properties); if ($cache->getCachedContent() !== false) { $this->endCache(); diff --git a/framework/yii/base/ViewEvent.php b/framework/yii/base/ViewEvent.php index b5734f4..d02e180 100644 --- a/framework/yii/base/ViewEvent.php +++ b/framework/yii/base/ViewEvent.php @@ -8,6 +8,8 @@ namespace yii\base; /** + * ViewEvent represents events triggered by the [[View]] component. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/caching/ChainedDependency.php b/framework/yii/caching/ChainedDependency.php index 20cb632..f8bfee3 100644 --- a/framework/yii/caching/ChainedDependency.php +++ b/framework/yii/caching/ChainedDependency.php @@ -23,7 +23,7 @@ class ChainedDependency extends Dependency * @var Dependency[] list of dependencies that this dependency is composed of. * Each array element must be a dependency object. */ - public $dependencies; + public $dependencies = []; /** * @var boolean whether this dependency is depending on every dependency in [[dependencies]]. * Defaults to true, meaning if any of the dependencies has changed, this dependency is considered changed. @@ -33,18 +33,6 @@ class ChainedDependency extends Dependency public $dependOnAll = true; /** - * Constructor. - * @param Dependency[] $dependencies list of dependencies that this dependency is composed of. - * Each array element should be a dependency object. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($dependencies = [], $config = []) - { - $this->dependencies = $dependencies; - parent::__construct($config); - } - - /** * Evaluates the dependency by generating and saving the data related with dependency. * @param Cache $cache the cache component that is currently evaluating this dependency */ diff --git a/framework/yii/caching/DbDependency.php b/framework/yii/caching/DbDependency.php index e8e1e68..ac6f2e7 100644 --- a/framework/yii/caching/DbDependency.php +++ b/framework/yii/caching/DbDependency.php @@ -34,20 +34,7 @@ class DbDependency extends Dependency /** * @var array the parameters (name => value) to be bound to the SQL statement specified by [[sql]]. */ - public $params; - - /** - * Constructor. - * @param string $sql the SQL query whose result is used to determine if the dependency has been changed. - * @param array $params the parameters (name => value) to be bound to the SQL statement specified by [[sql]]. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($sql, $params = [], $config = []) - { - $this->sql = $sql; - $this->params = $params; - parent::__construct($config); - } + public $params = []; /** * Generates the data needed to determine if dependency has been changed. @@ -62,6 +49,9 @@ class DbDependency extends Dependency if (!$db instanceof Connection) { throw new InvalidConfigException("DbDependency::db must be the application component ID of a DB connection."); } + if ($this->sql === null) { + throw new InvalidConfigException("DbDependency::sql must be set."); + } if ($db->enableQueryCache) { // temporarily disable and re-enable query caching diff --git a/framework/yii/caching/ExpressionDependency.php b/framework/yii/caching/ExpressionDependency.php index 36250d2..f6642b4 100644 --- a/framework/yii/caching/ExpressionDependency.php +++ b/framework/yii/caching/ExpressionDependency.php @@ -27,7 +27,7 @@ class ExpressionDependency extends Dependency * A PHP expression can be any PHP code that evaluates to a value. To learn more about what an expression is, * please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php). */ - public $expression; + public $expression = 'true'; /** * @var mixed custom parameters associated with this dependency. You may get the value * of this property in [[expression]] using `$this->params`. @@ -35,19 +35,6 @@ class ExpressionDependency extends Dependency public $params; /** - * Constructor. - * @param string $expression the PHP expression whose result is used to determine the dependency. - * @param mixed $params the custom parameters associated with this dependency - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($expression = 'true', $params = null, $config = []) - { - $this->expression = $expression; - $this->params = $params; - parent::__construct($config); - } - - /** * Generates the data needed to determine if dependency has been changed. * This method returns the result of the PHP expression. * @param Cache $cache the cache component that is currently evaluating this dependency diff --git a/framework/yii/caching/FileDependency.php b/framework/yii/caching/FileDependency.php index fa8b147..11afde3 100644 --- a/framework/yii/caching/FileDependency.php +++ b/framework/yii/caching/FileDependency.php @@ -6,6 +6,7 @@ */ namespace yii\caching; +use yii\base\InvalidConfigException; /** * FileDependency represents a dependency based on a file's last modification time. @@ -25,24 +26,17 @@ class FileDependency extends Dependency public $fileName; /** - * Constructor. - * @param string $fileName name of the file whose change is to be checked. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($fileName = null, $config = []) - { - $this->fileName = $fileName; - parent::__construct($config); - } - - /** * Generates the data needed to determine if dependency has been changed. * This method returns the file's last modification time. * @param Cache $cache the cache component that is currently evaluating this dependency * @return mixed the data needed to determine if dependency has been changed. + * @throws InvalidConfigException if [[fileName]] is not set */ protected function generateDependencyData($cache) { + if ($this->fileName === null) { + throw new InvalidConfigException('FileDependency::fileName must be set'); + } return @filemtime($this->fileName); } } diff --git a/framework/yii/caching/GroupDependency.php b/framework/yii/caching/GroupDependency.php index 48673f6..1cf7869 100644 --- a/framework/yii/caching/GroupDependency.php +++ b/framework/yii/caching/GroupDependency.php @@ -6,6 +6,7 @@ */ namespace yii\caching; +use yii\base\InvalidConfigException; /** * GroupDependency marks a cached data item with a group name. @@ -19,29 +20,22 @@ namespace yii\caching; class GroupDependency extends Dependency { /** - * @var string the group name + * @var string the group name. This property must be set. */ public $group; /** - * Constructor. - * @param string $group the group name - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($group, $config = []) - { - $this->group = $group; - parent::__construct($config); - } - - /** * Generates the data needed to determine if dependency has been changed. * This method does nothing in this class. * @param Cache $cache the cache component that is currently evaluating this dependency * @return mixed the data needed to determine if dependency has been changed. + * @throws InvalidConfigException if [[group]] is not set. */ protected function generateDependencyData($cache) { + if ($this->group === null) { + throw new InvalidConfigException('GroupDependency::group must be set'); + } $version = $cache->get([__CLASS__, $this->group]); if ($version === false) { $version = $this->invalidate($cache, $this->group); @@ -53,9 +47,13 @@ class GroupDependency extends Dependency * Performs the actual dependency checking. * @param Cache $cache the cache component that is currently evaluating this dependency * @return boolean whether the dependency is changed or not. + * @throws InvalidConfigException if [[group]] is not set. */ public function getHasChanged($cache) { + if ($this->group === null) { + throw new InvalidConfigException('GroupDependency::group must be set'); + } $version = $cache->get([__CLASS__, $this->group]); return $version === false || $version !== $this->data; } diff --git a/framework/yii/caching/MemCache.php b/framework/yii/caching/MemCache.php index fc7efb4..6f7a760 100644 --- a/framework/yii/caching/MemCache.php +++ b/framework/yii/caching/MemCache.php @@ -31,7 +31,7 @@ use yii\base\InvalidConfigException; * [ * 'components' => [ * 'cache' => [ - * 'class' => 'MemCache', + * 'class' => 'yii\caching\MemCache', * 'servers' => [ * [ * 'host' => 'server1', diff --git a/framework/yii/captcha/CaptchaAsset.php b/framework/yii/captcha/CaptchaAsset.php index adece3c..4fc722f 100644 --- a/framework/yii/captcha/CaptchaAsset.php +++ b/framework/yii/captcha/CaptchaAsset.php @@ -10,6 +10,8 @@ namespace yii\captcha; use yii\web\AssetBundle; /** + * This asset bundle provides the javascript files needed for the [[Captcha]] widget. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/console/Request.php b/framework/yii/console/Request.php index d99c321..d4d3af0 100644 --- a/framework/yii/console/Request.php +++ b/framework/yii/console/Request.php @@ -8,6 +8,10 @@ namespace yii\console; /** + * The console Request represents the environment information for a console application. + * + * It is a wrapper for the PHP `$_SERVER` variable which holds information about the + * currently running PHP script and the command line arguments given to it. * * @property array $params The command line arguments. It does not include the entry script name. * diff --git a/framework/yii/console/Response.php b/framework/yii/console/Response.php index 9c23e83..f6e6dd0 100644 --- a/framework/yii/console/Response.php +++ b/framework/yii/console/Response.php @@ -8,6 +8,8 @@ namespace yii\console; /** + * The console Response represents the result of a console application by holding the [[exitCode]]. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/console/controllers/CacheController.php b/framework/yii/console/controllers/CacheController.php index 1822b73..43932d1 100644 --- a/framework/yii/console/controllers/CacheController.php +++ b/framework/yii/console/controllers/CacheController.php @@ -52,7 +52,7 @@ class CacheController extends Controller */ public function actionFlush($component = 'cache') { - /** @var $cache Cache */ + /** @var Cache $cache */ $cache = Yii::$app->getComponent($component); if (!$cache || !$cache instanceof Cache) { throw new Exception('Application component "'.$component.'" is not defined or not a cache.'); diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php index ca7696f..89a7cf6 100644 --- a/framework/yii/data/ActiveDataProvider.php +++ b/framework/yii/data/ActiveDataProvider.php @@ -8,11 +8,11 @@ namespace yii\data; use Yii; +use yii\db\ActiveQueryInterface; use yii\base\InvalidConfigException; use yii\base\Model; -use yii\db\Query; -use yii\db\ActiveQuery; use yii\db\Connection; +use yii\db\QueryInterface; /** * ActiveDataProvider implements a data provider based on [[Query]] and [[ActiveQuery]]. @@ -54,7 +54,7 @@ use yii\db\Connection; class ActiveDataProvider extends BaseDataProvider { /** - * @var Query the query that is used to fetch data models and [[totalCount]] + * @var QueryInterface the query that is used to fetch data models and [[totalCount]] * if it is not explicitly set. */ public $query; @@ -97,8 +97,8 @@ class ActiveDataProvider extends BaseDataProvider */ protected function prepareModels() { - if (!$this->query instanceof Query) { - throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); + if (!$this->query instanceof QueryInterface) { + throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); } if (($pagination = $this->getPagination()) !== false) { $pagination->totalCount = $this->getTotalCount(); @@ -125,7 +125,7 @@ class ActiveDataProvider extends BaseDataProvider } } return $keys; - } elseif ($this->query instanceof ActiveQuery) { + } elseif ($this->query instanceof ActiveQueryInterface) { /** @var \yii\db\ActiveRecord $class */ $class = $this->query->modelClass; $pks = $class::primaryKey(); @@ -154,11 +154,11 @@ class ActiveDataProvider extends BaseDataProvider */ protected function prepareTotalCount() { - if (!$this->query instanceof Query) { - throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); + if (!$this->query instanceof QueryInterface) { + throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); } $query = clone $this->query; - return (int) $query->limit(-1)->offset(-1)->count('*', $this->db); + return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db); } /** @@ -167,7 +167,7 @@ class ActiveDataProvider extends BaseDataProvider public function setSort($value) { parent::setSort($value); - if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) { + if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQueryInterface) { /** @var Model $model */ $model = new $this->query->modelClass; foreach ($model->attributes() as $attribute) { diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php index 99846db..4d21fbe 100644 --- a/framework/yii/db/ActiveQuery.php +++ b/framework/yii/db/ActiveQuery.php @@ -11,8 +11,7 @@ namespace yii\db; /** * ActiveQuery represents a DB query associated with an Active Record class. * - * ActiveQuery instances are usually created by [[ActiveRecord::find()]], [[ActiveRecord::findBySql()]] - * and [[ActiveRecord::count()]]. + * ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]]. * * ActiveQuery mainly provides the following methods to retrieve the query results: * @@ -42,23 +41,13 @@ namespace yii\db; * ~~~ * * @author Qiang Xue + * @author Carsten Brandt * @since 2.0 */ -class ActiveQuery extends Query +class ActiveQuery extends Query implements ActiveQueryInterface { - /** - * @var string the name of the ActiveRecord class. - */ - public $modelClass; - /** - * @var array list of relations that this query should be performed with - */ - public $with; - /** - * @var boolean whether to return each record as an array. If false (default), an object - * of [[modelClass]] will be created to represent each record. - */ - public $asArray; + use ActiveQueryTrait; + /** * @var string the SQL statement to be executed for retrieving AR records. * This is set by [[ActiveRecord::findBySql()]]. @@ -67,25 +56,6 @@ class ActiveQuery extends Query /** - * PHP magic method. - * This method allows calling static method defined in [[modelClass]] via this query object. - * It is mainly implemented for supporting the feature of scope. - * @param string $name the method name to be called - * @param array $params the parameters passed to the method - * @return mixed the method return result - */ - public function __call($name, $params) - { - if (method_exists($this->modelClass, $name)) { - array_unshift($params, $this); - call_user_func_array([$this->modelClass, $name], $params); - return $this; - } else { - return parent::__call($name, $params); - } - } - - /** * Executes query and returns all results as an array. * @param Connection $db the DB connection used to create the DB command. * If null, the DB connection returned by [[modelClass]] will be used. @@ -122,7 +92,7 @@ class ActiveQuery extends Query if ($this->asArray) { $model = $row; } else { - /** @var $class ActiveRecord */ + /** @var ActiveRecord $class */ $class = $this->modelClass; $model = $class::create($row); } @@ -145,7 +115,7 @@ class ActiveQuery extends Query */ public function createCommand($db = null) { - /** @var $modelClass ActiveRecord */ + /** @var ActiveRecord $modelClass */ $modelClass = $this->modelClass; if ($db === null) { $db = $modelClass::getDb(); @@ -164,165 +134,4 @@ class ActiveQuery extends Query } return $db->createCommand($this->sql, $params); } - - /** - * Sets the [[asArray]] property. - * @param boolean $value whether to return the query results in terms of arrays instead of Active Records. - * @return static the query object itself - */ - public function asArray($value = true) - { - $this->asArray = $value; - return $this; - } - - /** - * Specifies the relations with which this query should be performed. - * - * The parameters to this method can be either one or multiple strings, or a single array - * of relation names and the optional callbacks to customize the relations. - * - * A relation name can refer to a relation defined in [[modelClass]] - * or a sub-relation that stands for a relation of a related record. - * For example, `orders.address` means the `address` relation defined - * in the model class corresponding to the `orders` relation. - * - * The followings are some usage examples: - * - * ~~~ - * // find customers together with their orders and country - * Customer::find()->with('orders', 'country')->all(); - * // find customers together with their orders and the orders' shipping address - * Customer::find()->with('orders.address')->all(); - * // find customers together with their country and orders of status 1 - * Customer::find()->with([ - * 'orders' => function($query) { - * $query->andWhere('status = 1'); - * }, - * 'country', - * ])->all(); - * ~~~ - * - * @return static the query object itself - */ - public function with() - { - $this->with = func_get_args(); - if (isset($this->with[0]) && is_array($this->with[0])) { - // the parameter is given as an array - $this->with = $this->with[0]; - } - return $this; - } - - /** - * Sets the [[indexBy]] property. - * @param string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row or model data. The signature of the callable should be: - * - * ~~~ - * // $model is an AR instance when `asArray` is false, - * // or an array of column values when `asArray` is true. - * function ($model) - * { - * // return the index value corresponding to $model - * } - * ~~~ - * - * @return static the query object itself - */ - public function indexBy($column) - { - return parent::indexBy($column); - } - - private function createModels($rows) - { - $models = []; - if ($this->asArray) { - if ($this->indexBy === null) { - return $rows; - } - foreach ($rows as $row) { - if (is_string($this->indexBy)) { - $key = $row[$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - $models[$key] = $row; - } - } else { - /** @var $class ActiveRecord */ - $class = $this->modelClass; - if ($this->indexBy === null) { - foreach ($rows as $row) { - $models[] = $class::create($row); - } - } else { - foreach ($rows as $row) { - $model = $class::create($row); - if (is_string($this->indexBy)) { - $key = $model->{$this->indexBy}; - } else { - $key = call_user_func($this->indexBy, $model); - } - $models[$key] = $model; - } - } - } - return $models; - } - - private function populateRelations(&$models, $with) - { - $primaryModel = new $this->modelClass; - $relations = $this->normalizeRelations($primaryModel, $with); - foreach ($relations as $name => $relation) { - if ($relation->asArray === null) { - // inherit asArray from primary query - $relation->asArray = $this->asArray; - } - $relation->findWith($name, $models); - } - } - - /** - * @param ActiveRecord $model - * @param array $with - * @return ActiveRelation[] - */ - private function normalizeRelations($model, $with) - { - $relations = []; - foreach ($with as $name => $callback) { - if (is_integer($name)) { - $name = $callback; - $callback = null; - } - if (($pos = strpos($name, '.')) !== false) { - // with sub-relations - $childName = substr($name, $pos + 1); - $name = substr($name, 0, $pos); - } else { - $childName = null; - } - - $t = strtolower($name); - if (!isset($relations[$t])) { - $relation = $model->getRelation($name); - $relation->primaryModel = null; - $relations[$t] = $relation; - } else { - $relation = $relations[$t]; - } - - if (isset($childName)) { - $relation->with[$childName] = $callback; - } elseif ($callback !== null) { - call_user_func($callback, $relation); - } - } - return $relations; - } } diff --git a/framework/yii/db/ActiveQueryInterface.php b/framework/yii/db/ActiveQueryInterface.php new file mode 100644 index 0000000..a2e132f --- /dev/null +++ b/framework/yii/db/ActiveQueryInterface.php @@ -0,0 +1,77 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +interface ActiveQueryInterface extends QueryInterface +{ + /** + * Sets the [[asArray]] property. + * @param boolean $value whether to return the query results in terms of arrays instead of Active Records. + * @return static the query object itself + */ + public function asArray($value = true); + + /** + * Sets the [[indexBy]] property. + * @param string|callable $column the name of the column by which the query results should be indexed by. + * This can also be a callable (e.g. anonymous function) that returns the index value based on the given + * row or model data. The signature of the callable should be: + * + * ~~~ + * // $model is an AR instance when `asArray` is false, + * // or an array of column values when `asArray` is true. + * function ($model) + * { + * // return the index value corresponding to $model + * } + * ~~~ + * + * @return static the query object itself + */ + public function indexBy($column); + + /** + * Specifies the relations with which this query should be performed. + * + * The parameters to this method can be either one or multiple strings, or a single array + * of relation names and the optional callbacks to customize the relations. + * + * A relation name can refer to a relation defined in [[modelClass]] + * or a sub-relation that stands for a relation of a related record. + * For example, `orders.address` means the `address` relation defined + * in the model class corresponding to the `orders` relation. + * + * The followings are some usage examples: + * + * ~~~ + * // find customers together with their orders and country + * Customer::find()->with('orders', 'country')->all(); + * // find customers together with their orders and the orders' shipping address + * Customer::find()->with('orders.address')->all(); + * // find customers together with their country and orders of status 1 + * Customer::find()->with([ + * 'orders' => function($query) { + * $query->andWhere('status = 1'); + * }, + * 'country', + * ])->all(); + * ~~~ + * + * @return static the query object itself + */ + public function with(); +} diff --git a/framework/yii/db/ActiveQueryTrait.php b/framework/yii/db/ActiveQueryTrait.php new file mode 100644 index 0000000..51135d8 --- /dev/null +++ b/framework/yii/db/ActiveQueryTrait.php @@ -0,0 +1,199 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +trait ActiveQueryTrait +{ + /** + * @var string the name of the ActiveRecord class. + */ + public $modelClass; + /** + * @var array list of relations that this query should be performed with + */ + public $with; + /** + * @var boolean whether to return each record as an array. If false (default), an object + * of [[modelClass]] will be created to represent each record. + */ + public $asArray; + + + /** + * PHP magic method. + * This method allows calling static method defined in [[modelClass]] via this query object. + * It is mainly implemented for supporting the feature of scope. + * @param string $name the method name to be called + * @param array $params the parameters passed to the method + * @return mixed the method return result + */ + public function __call($name, $params) + { + if (method_exists($this->modelClass, $name)) { + array_unshift($params, $this); + call_user_func_array([$this->modelClass, $name], $params); + return $this; + } else { + return parent::__call($name, $params); + } + } + + /** + * Sets the [[asArray]] property. + * @param boolean $value whether to return the query results in terms of arrays instead of Active Records. + * @return static the query object itself + */ + public function asArray($value = true) + { + $this->asArray = $value; + return $this; + } + + /** + * Specifies the relations with which this query should be performed. + * + * The parameters to this method can be either one or multiple strings, or a single array + * of relation names and the optional callbacks to customize the relations. + * + * A relation name can refer to a relation defined in [[modelClass]] + * or a sub-relation that stands for a relation of a related record. + * For example, `orders.address` means the `address` relation defined + * in the model class corresponding to the `orders` relation. + * + * The followings are some usage examples: + * + * ~~~ + * // find customers together with their orders and country + * Customer::find()->with('orders', 'country')->all(); + * // find customers together with their orders and the orders' shipping address + * Customer::find()->with('orders.address')->all(); + * // find customers together with their country and orders of status 1 + * Customer::find()->with([ + * 'orders' => function($query) { + * $query->andWhere('status = 1'); + * }, + * 'country', + * ])->all(); + * ~~~ + * + * @return static the query object itself + */ + public function with() + { + $this->with = func_get_args(); + if (isset($this->with[0]) && is_array($this->with[0])) { + // the parameter is given as an array + $this->with = $this->with[0]; + } + return $this; + } + + /** + * Converts found rows into model instances + * @param array $rows + * @return array|ActiveRecord[] + */ + private function createModels($rows) + { + $models = []; + if ($this->asArray) { + if ($this->indexBy === null) { + return $rows; + } + foreach ($rows as $row) { + if (is_string($this->indexBy)) { + $key = $row[$this->indexBy]; + } else { + $key = call_user_func($this->indexBy, $row); + } + $models[$key] = $row; + } + } else { + /** @var ActiveRecord $class */ + $class = $this->modelClass; + if ($this->indexBy === null) { + foreach ($rows as $row) { + $models[] = $class::create($row); + } + } else { + foreach ($rows as $row) { + $model = $class::create($row); + if (is_string($this->indexBy)) { + $key = $model->{$this->indexBy}; + } else { + $key = call_user_func($this->indexBy, $model); + } + $models[$key] = $model; + } + } + } + return $models; + } + + /** + * @param ActiveRecord[] $models + * @param array $with + */ + private function populateRelations(&$models, $with) + { + $primaryModel = new $this->modelClass; + $relations = $this->normalizeRelations($primaryModel, $with); + foreach ($relations as $name => $relation) { + if ($relation->asArray === null) { + // inherit asArray from primary query + $relation->asArray = $this->asArray; + } + $relation->findWith($name, $models); + } + } + + /** + * @param ActiveRecord $model + * @param array $with + * @return ActiveRelationInterface[] + */ + private function normalizeRelations($model, $with) + { + $relations = []; + foreach ($with as $name => $callback) { + if (is_integer($name)) { + $name = $callback; + $callback = null; + } + if (($pos = strpos($name, '.')) !== false) { + // with sub-relations + $childName = substr($name, $pos + 1); + $name = substr($name, 0, $pos); + } else { + $childName = null; + } + + if (!isset($relations[$name])) { + $relation = $model->getRelation($name); + $relation->primaryModel = null; + $relations[$name] = $relation; + } else { + $relation = $relations[$name]; + } + + if (isset($childName)) { + $relation->with[$childName] = $callback; + } elseif ($callback !== null) { + call_user_func($callback, $relation); + } + } + return $relations; + } +} diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php index 830bf40..9edc824 100644 --- a/framework/yii/db/ActiveRecord.php +++ b/framework/yii/db/ActiveRecord.php @@ -29,11 +29,14 @@ use yii\helpers\Inflector; * @property mixed $oldPrimaryKey The old 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. + * @property array $populatedRelations An array of relation data indexed by relation names. 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 + * @author Carsten Brandt * @since 2.0 */ class ActiveRecord extends Model @@ -250,7 +253,7 @@ class ActiveRecord extends Model /** * Creates an [[ActiveQuery]] instance. - * This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query. + * This method is called by [[find()]], [[findBySql()]] to start a SELECT query. * You may override this method to return a customized query (e.g. `CustomerQuery` specified * written for querying `Customer` purpose.) * @return ActiveQuery the newly created [[ActiveQuery]] instance. @@ -370,7 +373,7 @@ class ActiveRecord extends Model * This method is overridden so that attributes and related objects can be accessed like properties. * @param string $name property name * @return mixed property value - * @see getAttribute + * @see getAttribute() */ public function __get($name) { @@ -383,7 +386,7 @@ class ActiveRecord extends Model return $this->_related[$name]; } $value = parent::__get($name); - if ($value instanceof ActiveRelation) { + if ($value instanceof ActiveRelationInterface) { return $this->_related[$name] = $value->multiple ? $value->all() : $value->one(); } else { return $value; @@ -472,7 +475,7 @@ class ActiveRecord extends Model */ public function hasOne($class, $link) { - return new ActiveRelation([ + return $this->createActiveRelation([ 'modelClass' => $class, 'primaryModel' => $this, 'link' => $link, @@ -510,7 +513,7 @@ class ActiveRecord extends Model */ public function hasMany($class, $link) { - return new ActiveRelation([ + return $this->createActiveRelation([ 'modelClass' => $class, 'primaryModel' => $this, 'link' => $link, @@ -519,6 +522,18 @@ class ActiveRecord extends Model } /** + * Creates an [[ActiveRelation]] instance. + * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. + * You may override this method to return a customized relation. + * @param array $config the configuration passed to the ActiveRelation class. + * @return ActiveRelation the newly created [[ActiveRelation]] instance. + */ + protected function createActiveRelation($config = []) + { + return new ActiveRelation($config); + } + + /** * Populates the named relation with the related records. * Note that this method does not check if the relation exists or not. * @param string $name the relation name (case-sensitive) @@ -574,7 +589,7 @@ class ActiveRecord extends Model * null will be returned. * @param string $name the attribute name * @return mixed the attribute value. Null if the attribute is not set or does not exist. - * @see hasAttribute + * @see hasAttribute() */ public function getAttribute($name) { @@ -586,7 +601,7 @@ class ActiveRecord extends Model * @param string $name the attribute name * @param mixed $value the attribute value. * @throws InvalidParamException if the named attribute does not exist. - * @see hasAttribute + * @see hasAttribute() */ public function setAttribute($name, $value) { @@ -623,7 +638,7 @@ class ActiveRecord extends Model * @param string $name the attribute name * @return mixed the old attribute value. Null if the attribute is not loaded before * or does not exist. - * @see hasAttribute + * @see hasAttribute() */ public function getOldAttribute($name) { @@ -635,7 +650,7 @@ class ActiveRecord extends Model * @param string $name the attribute name * @param mixed $value the old attribute value. * @throws InvalidParamException if the named attribute does not exist. - * @see hasAttribute + * @see hasAttribute() */ public function setOldAttribute($name, $value) { @@ -1028,7 +1043,7 @@ 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 + * @see getIsNewRecord() */ public function setIsNewRecord($value) { @@ -1281,7 +1296,7 @@ class ActiveRecord extends Model $getter = 'get' . $name; try { $relation = $this->$getter(); - if ($relation instanceof ActiveRelation) { + if ($relation instanceof ActiveRelationInterface) { return $relation; } else { return null; @@ -1319,9 +1334,9 @@ class ActiveRecord extends Model throw new InvalidCallException('Unable to link models: both models must NOT be newly created.'); } if (is_array($relation->via)) { - /** @var $viaRelation ActiveRelation */ + /** @var ActiveRelation $viaRelation */ list($viaName, $viaRelation) = $relation->via; - /** @var $viaClass ActiveRecord */ + /** @var ActiveRecord $viaClass */ $viaClass = $viaRelation->modelClass; $viaTable = $viaClass::tableName(); // unset $viaName so that it can be reloaded to reflect the change @@ -1394,9 +1409,9 @@ class ActiveRecord extends Model if ($relation->via !== null) { if (is_array($relation->via)) { - /** @var $viaRelation ActiveRelation */ + /** @var ActiveRelation $viaRelation */ list($viaName, $viaRelation) = $relation->via; - /** @var $viaClass ActiveRecord */ + /** @var ActiveRecord $viaClass */ $viaClass = $viaRelation->modelClass; $viaTable = $viaClass::tableName(); unset($this->_related[$viaName]); @@ -1442,7 +1457,7 @@ class ActiveRecord extends Model if (!$relation->multiple) { unset($this->_related[$name]); } elseif (isset($this->_related[$name])) { - /** @var $b ActiveRecord */ + /** @var ActiveRecord $b */ foreach ($this->_related[$name] as $a => $b) { if ($model->getPrimaryKey() == $b->getPrimaryKey()) { unset($this->_related[$name][$a]); diff --git a/framework/yii/db/ActiveRelation.php b/framework/yii/db/ActiveRelation.php index 1a7541a..ea9b87a 100644 --- a/framework/yii/db/ActiveRelation.php +++ b/framework/yii/db/ActiveRelation.php @@ -8,8 +8,6 @@ namespace yii\db; -use yii\base\InvalidConfigException; - /** * ActiveRelation represents a relation between two Active Record classes. * @@ -22,61 +20,16 @@ use yii\base\InvalidConfigException; * * If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method. * + * @property array|ActiveRelation $via the query associated with the pivot table. Please call [[via()]] + * or [[viaTable()]] to set this property instead of directly setting it. + * * @author Qiang Xue + * @author Carsten Brandt * @since 2.0 */ -class ActiveRelation extends ActiveQuery +class ActiveRelation extends ActiveQuery implements ActiveRelationInterface { - /** - * @var boolean whether this relation should populate all query results into AR instances. - * If false, only the first row of the results will be retrieved. - */ - public $multiple; - /** - * @var ActiveRecord the primary model that this relation is associated with. - * This is used only in lazy loading with dynamic query options. - */ - public $primaryModel; - /** - * @var array the columns of the primary and foreign tables that establish the relation. - * The array keys must be columns of the table for this relation, and the array values - * must be the corresponding columns from the primary table. - * Do not prefix or quote the column names as they will be done automatically by Yii. - */ - public $link; - /** - * @var array|ActiveRelation the query associated with the pivot table. Please call [[via()]] - * or [[viaTable()]] to set this property instead of directly setting it. - */ - 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. - * @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. - * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. - * Its signature should be `function($query)`, where `$query` is the query to be customized. - * @return static the relation object itself. - */ - public function via($relationName, $callable = null) - { - $relation = $this->primaryModel->getRelation($relationName); - $this->via = [$relationName, $relation]; - if ($callable !== null) { - call_user_func($callable, $relation); - } - return $this; - } + use ActiveRelationTrait; /** * Specifies the pivot table. @@ -120,7 +73,7 @@ class ActiveRelation extends ActiveQuery $this->filterByModels($viaModels); } elseif (is_array($this->via)) { // via relation - /** @var $viaQuery ActiveRelation */ + /** @var ActiveRelation $viaQuery */ list($viaName, $viaQuery) = $this->via; if ($viaQuery->multiple) { $viaModels = $viaQuery->all(); @@ -137,179 +90,4 @@ class ActiveRelation extends ActiveQuery } return parent::createCommand($db); } - - /** - * Finds the related records and populates them into the primary models. - * This method is internally used by [[ActiveQuery]]. Do not call it directly. - * @param string $name the relation name - * @param array $primaryModels primary models - * @return array the related models - * @throws InvalidConfigException - */ - public function findWith($name, &$primaryModels) - { - if (!is_array($this->link)) { - throw new InvalidConfigException('Invalid link: it must be an array of key-value pairs.'); - } - - if ($this->via instanceof self) { - // via pivot table - /** @var $viaQuery ActiveRelation */ - $viaQuery = $this->via; - $viaModels = $viaQuery->findPivotRows($primaryModels); - $this->filterByModels($viaModels); - } elseif (is_array($this->via)) { - // via relation - /** @var $viaQuery ActiveRelation */ - list($viaName, $viaQuery) = $this->via; - $viaQuery->primaryModel = null; - $viaModels = $viaQuery->findWith($viaName, $primaryModels); - $this->filterByModels($viaModels); - } else { - $this->filterByModels($primaryModels); - } - - if (count($primaryModels) === 1 && !$this->multiple) { - $model = $this->one(); - foreach ($primaryModels as $i => $primaryModel) { - if ($primaryModel instanceof ActiveRecord) { - $primaryModel->populateRelation($name, $model); - } else { - $primaryModels[$i][$name] = $model; - } - } - return [$model]; - } else { - $models = $this->all(); - if (isset($viaModels, $viaQuery)) { - $buckets = $this->buildBuckets($models, $this->link, $viaModels, $viaQuery->link); - } else { - $buckets = $this->buildBuckets($models, $this->link); - } - - $link = array_values(isset($viaQuery) ? $viaQuery->link : $this->link); - foreach ($primaryModels as $i => $primaryModel) { - $key = $this->getModelKey($primaryModel, $link); - $value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null); - if ($primaryModel instanceof ActiveRecord) { - $primaryModel->populateRelation($name, $value); - } else { - $primaryModels[$i][$name] = $value; - } - } - return $models; - } - } - - /** - * @param array $models - * @param array $link - * @param array $viaModels - * @param array $viaLink - * @return array - */ - private function buildBuckets($models, $link, $viaModels = null, $viaLink = null) - { - $buckets = []; - $linkKeys = array_keys($link); - foreach ($models as $i => $model) { - $key = $this->getModelKey($model, $linkKeys); - if ($this->indexBy !== null) { - $buckets[$key][$i] = $model; - } else { - $buckets[$key][] = $model; - } - } - - if ($viaModels !== null) { - $viaBuckets = []; - $viaLinkKeys = array_keys($viaLink); - $linkValues = array_values($link); - foreach ($viaModels as $viaModel) { - $key1 = $this->getModelKey($viaModel, $viaLinkKeys); - $key2 = $this->getModelKey($viaModel, $linkValues); - if (isset($buckets[$key2])) { - foreach ($buckets[$key2] as $i => $bucket) { - if ($this->indexBy !== null) { - $viaBuckets[$key1][$i] = $bucket; - } else { - $viaBuckets[$key1][] = $bucket; - } - } - } - } - $buckets = $viaBuckets; - } - - if (!$this->multiple) { - foreach ($buckets as $i => $bucket) { - $buckets[$i] = reset($bucket); - } - } - return $buckets; - } - - /** - * @param ActiveRecord|array $model - * @param array $attributes - * @return string - */ - private function getModelKey($model, $attributes) - { - if (count($attributes) > 1) { - $key = []; - foreach ($attributes as $attribute) { - $key[] = $model[$attribute]; - } - return serialize($key); - } else { - $attribute = reset($attributes); - return $model[$attribute]; - } - } - - /** - * @param array $models - */ - private function filterByModels($models) - { - $attributes = array_keys($this->link); - $values = []; - if (count($attributes) === 1) { - // single key - $attribute = reset($this->link); - foreach ($models as $model) { - if (($value = $model[$attribute]) !== null) { - $values[] = $value; - } - } - } else { - // composite keys - foreach ($models as $model) { - $v = []; - foreach ($this->link as $attribute => $link) { - $v[$attribute] = $model[$link]; - } - $values[] = $v; - } - } - $this->andWhere(['in', $attributes, array_unique($values, SORT_REGULAR)]); - } - - /** - * @param ActiveRecord[] $primaryModels - * @return array - */ - private function findPivotRows($primaryModels) - { - if (empty($primaryModels)) { - return []; - } - $this->filterByModels($primaryModels); - /** @var $primaryModel ActiveRecord */ - $primaryModel = reset($primaryModels); - $db = $primaryModel->getDb(); - list ($sql, $params) = $db->getQueryBuilder()->build($this); - return $db->createCommand($sql, $params)->queryAll(); - } } diff --git a/framework/yii/db/ActiveRelationInterface.php b/framework/yii/db/ActiveRelationInterface.php new file mode 100644 index 0000000..84e0648 --- /dev/null +++ b/framework/yii/db/ActiveRelationInterface.php @@ -0,0 +1,29 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +interface ActiveRelationInterface extends ActiveQueryInterface +{ + /** + * Specifies the relation associated with the pivot table. + * @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. + * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. + * Its signature should be `function($query)`, where `$query` is the query to be customized. + * @return static the relation object itself. + */ + public function via($relationName, $callable = null); +} diff --git a/framework/yii/db/ActiveRelationTrait.php b/framework/yii/db/ActiveRelationTrait.php new file mode 100644 index 0000000..27963d0 --- /dev/null +++ b/framework/yii/db/ActiveRelationTrait.php @@ -0,0 +1,246 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +trait ActiveRelationTrait +{ + /** + * @var boolean whether this relation should populate all query results into AR instances. + * If false, only the first row of the results will be retrieved. + */ + public $multiple; + /** + * @var ActiveRecord the primary model that this relation is associated with. + * This is used only in lazy loading with dynamic query options. + */ + public $primaryModel; + /** + * @var array the columns of the primary and foreign tables that establish the relation. + * The array keys must be columns of the table for this relation, and the array values + * must be the corresponding columns from the primary table. + * Do not prefix or quote the column names as this will be done automatically by Yii. + */ + public $link; + /** + * @var array the query associated with the pivot table. Please call [[via()]] + * to set this property instead of directly setting it. + */ + public $via; + + /** + * Clones internal objects. + */ + public function __clone() + { + // make a clone of "via" object so that the same query object can be reused multiple times + if (is_object($this->via)) { + $this->via = clone $this->via; + } elseif (is_array($this->via)) { + $this->via = [$this->via[0], clone $this->via[1]]; + } + } + + /** + * Specifies the relation associated with the pivot table. + * @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. + * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. + * Its signature should be `function($query)`, where `$query` is the query to be customized. + * @return static the relation object itself. + */ + public function via($relationName, $callable = null) + { + $relation = $this->primaryModel->getRelation($relationName); + $this->via = [$relationName, $relation]; + if ($callable !== null) { + call_user_func($callable, $relation); + } + return $this; + } + + /** + * Finds the related records and populates them into the primary models. + * This method is internally used by [[ActiveQuery]]. Do not call it directly. + * @param string $name the relation name + * @param array $primaryModels primary models + * @return array the related models + * @throws InvalidConfigException + */ + public function findWith($name, &$primaryModels) + { + if (!is_array($this->link)) { + throw new InvalidConfigException('Invalid link: it must be an array of key-value pairs.'); + } + + if ($this->via instanceof self) { + // via pivot table + /** @var ActiveRelationTrait $viaQuery */ + $viaQuery = $this->via; + $viaModels = $viaQuery->findPivotRows($primaryModels); + $this->filterByModels($viaModels); + } elseif (is_array($this->via)) { + // via relation + /** @var ActiveRelationTrait $viaQuery */ + list($viaName, $viaQuery) = $this->via; + $viaQuery->primaryModel = null; + $viaModels = $viaQuery->findWith($viaName, $primaryModels); + $this->filterByModels($viaModels); + } else { + $this->filterByModels($primaryModels); + } + + if (count($primaryModels) === 1 && !$this->multiple) { + $model = $this->one(); + foreach ($primaryModels as $i => $primaryModel) { + if ($primaryModel instanceof ActiveRecord) { + $primaryModel->populateRelation($name, $model); + } else { + $primaryModels[$i][$name] = $model; + } + } + return [$model]; + } else { + $models = $this->all(); + if (isset($viaModels, $viaQuery)) { + $buckets = $this->buildBuckets($models, $this->link, $viaModels, $viaQuery->link); + } else { + $buckets = $this->buildBuckets($models, $this->link); + } + + $link = array_values(isset($viaQuery) ? $viaQuery->link : $this->link); + foreach ($primaryModels as $i => $primaryModel) { + $key = $this->getModelKey($primaryModel, $link); + $value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null); + if ($primaryModel instanceof ActiveRecord) { + $primaryModel->populateRelation($name, $value); + } else { + $primaryModels[$i][$name] = $value; + } + } + return $models; + } + } + + /** + * @param array $models + * @param array $link + * @param array $viaModels + * @param array $viaLink + * @return array + */ + private function buildBuckets($models, $link, $viaModels = null, $viaLink = null) + { + $buckets = []; + $linkKeys = array_keys($link); + foreach ($models as $i => $model) { + $key = $this->getModelKey($model, $linkKeys); + if ($this->indexBy !== null) { + $buckets[$key][$i] = $model; + } else { + $buckets[$key][] = $model; + } + } + + if ($viaModels !== null) { + $viaBuckets = []; + $viaLinkKeys = array_keys($viaLink); + $linkValues = array_values($link); + foreach ($viaModels as $viaModel) { + $key1 = $this->getModelKey($viaModel, $viaLinkKeys); + $key2 = $this->getModelKey($viaModel, $linkValues); + if (isset($buckets[$key2])) { + foreach ($buckets[$key2] as $i => $bucket) { + if ($this->indexBy !== null) { + $viaBuckets[$key1][$i] = $bucket; + } else { + $viaBuckets[$key1][] = $bucket; + } + } + } + } + $buckets = $viaBuckets; + } + + if (!$this->multiple) { + foreach ($buckets as $i => $bucket) { + $buckets[$i] = reset($bucket); + } + } + return $buckets; + } + + /** + * @param ActiveRecord|array $model + * @param array $attributes + * @return string + */ + private function getModelKey($model, $attributes) + { + if (count($attributes) > 1) { + $key = []; + foreach ($attributes as $attribute) { + $key[] = $model[$attribute]; + } + return serialize($key); + } else { + $attribute = reset($attributes); + return $model[$attribute]; + } + } + + /** + * @param array $models + */ + private function filterByModels($models) + { + $attributes = array_keys($this->link); + $values = []; + if (count($attributes) === 1) { + // single key + $attribute = reset($this->link); + foreach ($models as $model) { + if (($value = $model[$attribute]) !== null) { + $values[] = $value; + } + } + } else { + // composite keys + foreach ($models as $model) { + $v = []; + foreach ($this->link as $attribute => $link) { + $v[$attribute] = $model[$link]; + } + $values[] = $v; + } + } + $this->andWhere(['in', $attributes, array_unique($values, SORT_REGULAR)]); + } + + /** + * @param ActiveRecord[] $primaryModels + * @return array + */ + private function findPivotRows($primaryModels) + { + if (empty($primaryModels)) { + return []; + } + $this->filterByModels($primaryModels); + /** @var ActiveRecord $primaryModel */ + $primaryModel = reset($primaryModels); + return $this->asArray()->all($primaryModel->getDb()); + } +} diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php index 671558a..6ed0d9c 100644 --- a/framework/yii/db/Command.php +++ b/framework/yii/db/Command.php @@ -260,7 +260,7 @@ class Command extends \yii\base\Component $rawSql = $this->getRawSql(); - Yii::trace($rawSql, __METHOD__); + Yii::info($rawSql, __METHOD__); if ($sql == '') { return 0; @@ -364,9 +364,9 @@ class Command extends \yii\base\Component $db = $this->db; $rawSql = $this->getRawSql(); - Yii::trace($rawSql, __METHOD__); + Yii::info($rawSql, __METHOD__); - /** @var $cache \yii\caching\Cache */ + /** @var \yii\caching\Cache $cache */ if ($db->enableQueryCache && $method !== '') { $cache = is_string($db->queryCache) ? Yii::$app->getComponent($db->queryCache) : $db->queryCache; } diff --git a/framework/yii/db/Query.php b/framework/yii/db/Query.php index 0839849..50ed105 100644 --- a/framework/yii/db/Query.php +++ b/framework/yii/db/Query.php @@ -33,20 +33,12 @@ use yii\base\Component; * ~~~ * * @author Qiang Xue + * @author Carsten Brandt * @since 2.0 */ -class Query extends Component +class Query extends Component implements QueryInterface { - /** - * Sort ascending - * @see orderBy - */ - const SORT_ASC = false; - /** - * Sort descending - * @see orderBy - */ - const SORT_DESC = true; + use QueryTrait; /** * @var array the columns being selected. For example, `['id', 'name']`. @@ -71,28 +63,6 @@ class Query extends Component */ public $from; /** - * @var string|array query condition. This refers to the WHERE clause in a SQL statement. - * For example, `age > 31 AND team = 1`. - * @see where() - */ - public $where; - /** - * @var integer maximum number of records to be returned. If not set or less than 0, it means no limit. - */ - public $limit; - /** - * @var integer zero-based offset from where the records are to be returned. If not set or - * less than 0, it means starting from the beginning. - */ - public $offset; - /** - * @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement. - * The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which - * can be either [[Query::SORT_ASC]] or [[Query::SORT_DESC]]. The array may also contain [[Expression]] objects. - * If that is the case, the expressions will be converted into strings without any change. - */ - public $orderBy; - /** * @var array how to group the query results. For example, `['company', 'department']`. * This is used to construct the GROUP BY clause in a SQL statement. */ @@ -130,12 +100,6 @@ class Query extends Component * For example, `[':name' => 'Dan', ':age' => 31]`. */ public $params; - /** - * @var string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row data. For more details, see [[indexBy()]]. This property is only used by [[all()]]. - */ - public $indexBy; /** @@ -154,27 +118,6 @@ class Query extends Component } /** - * Sets the [[indexBy]] property. - * @param string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row data. The signature of the callable should be: - * - * ~~~ - * function ($row) - * { - * // return the index value corresponding to $row - * } - * ~~~ - * - * @return static the query object itself - */ - public function indexBy($column) - { - $this->indexBy = $column; - return $this; - } - - /** * Executes the query and returns all results as an array. * @param Connection $db the database connection used to generate the SQL statement. * If this parameter is not given, the `db` application component will be used. @@ -239,7 +182,7 @@ class Query extends Component * @param string $q the COUNT expression. Defaults to '*'. * Make sure you properly quote column names in the expression. * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. + * If this parameter is not given (or null), the `db` application component will be used. * @return integer number of records */ public function count($q = '*', $db = null) @@ -653,83 +596,6 @@ class Query extends Component } /** - * Sets the ORDER BY part of the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see addOrderBy() - */ - public function orderBy($columns) - { - $this->orderBy = $this->normalizeOrderBy($columns); - return $this; - } - - /** - * Adds additional ORDER BY columns to the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see orderBy() - */ - public function addOrderBy($columns) - { - $columns = $this->normalizeOrderBy($columns); - if ($this->orderBy === null) { - $this->orderBy = $columns; - } else { - $this->orderBy = array_merge($this->orderBy, $columns); - } - return $this; - } - - protected function normalizeOrderBy($columns) - { - if (is_array($columns)) { - return $columns; - } else { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - $result = []; - foreach ($columns as $column) { - if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { - $result[$matches[1]] = strcasecmp($matches[2], 'desc') ? self::SORT_ASC : self::SORT_DESC; - } else { - $result[$column] = self::SORT_ASC; - } - } - return $result; - } - } - - /** - * Sets the LIMIT part of the query. - * @param integer $limit the limit. Use null or negative value to disable limit. - * @return static the query object itself - */ - public function limit($limit) - { - $this->limit = $limit; - return $this; - } - - /** - * Sets the OFFSET part of the query. - * @param integer $offset the offset. Use null or negative value to disable offset. - * @return static the query object itself - */ - public function offset($offset) - { - $this->offset = $offset; - return $this; - } - - /** * Appends a SQL statement using UNION operator. * @param string|Query $sql the SQL statement to be appended using UNION * @return static the query object itself diff --git a/framework/yii/db/QueryBuilder.php b/framework/yii/db/QueryBuilder.php index 09948c8..0a547ae 100644 --- a/framework/yii/db/QueryBuilder.php +++ b/framework/yii/db/QueryBuilder.php @@ -683,7 +683,7 @@ class QueryBuilder extends \yii\base\Object if (is_object($direction)) { $orders[] = (string)$direction; } else { - $orders[] = $this->db->quoteColumnName($name) . ($direction === Query::SORT_DESC ? ' DESC' : ''); + $orders[] = $this->db->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : ''); } } diff --git a/framework/yii/db/QueryInterface.php b/framework/yii/db/QueryInterface.php new file mode 100644 index 0000000..f3cc312 --- /dev/null +++ b/framework/yii/db/QueryInterface.php @@ -0,0 +1,206 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +interface QueryInterface +{ + /** + * Executes the query and returns all results as an array. + * @param Connection $db the database connection used to execute the query. + * If this parameter is not given, the `db` application component will be used. + * @return array the query results. If the query results in nothing, an empty array will be returned. + */ + public function all($db = null); + + /** + * Executes the query and returns a single row of result. + * @param Connection $db the database connection used to execute the query. + * If this parameter is not given, the `db` application component will be used. + * @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query + * results in nothing. + */ + public function one($db = null); + + /** + * Returns the number of records. + * @param string $q the COUNT expression. Defaults to '*'. + * @param Connection $db the database connection used to execute the query. + * If this parameter is not given, the `db` application component will be used. + * @return integer number of records + */ + public function count($q = '*', $db = null); + + /** + * Returns a value indicating whether the query result contains any row of data. + * @param Connection $db the database connection used to execute the query. + * If this parameter is not given, the `db` application component will be used. + * @return boolean whether the query result contains any row of data. + */ + public function exists($db = null); + + /** + * Sets the [[indexBy]] property. + * @param string|callable $column the name of the column by which the query results should be indexed by. + * This can also be a callable (e.g. anonymous function) that returns the index value based on the given + * row data. The signature of the callable should be: + * + * ~~~ + * function ($row) + * { + * // return the index value corresponding to $row + * } + * ~~~ + * + * @return static the query object itself + */ + public function indexBy($column); + + /** + * Sets the WHERE part of the query. + * + * The method requires a $condition parameter. + * + * The $condition parameter should be an array in one of the following two formats: + * + * - hash format: `['column1' => value1, 'column2' => value2, ...]` + * - operator format: `[operator, operand1, operand2, ...]` + * + * A condition in hash format represents the following SQL expression in general: + * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, + * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used + * in the generated expression. Below are some examples: + * + * - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`. + * - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`. + * - `['status' => null] generates `status IS NULL`. + * + * A condition in operator format generates the SQL expression according to the specified operator, which + * can be one of the followings: + * + * - `and`: the operands should be concatenated together using `AND`. For example, + * `['and', 'id=1', 'id=2']` will generate `id=1 AND id=2`. If an operand is an array, + * it will be converted into a string using the rules described here. For example, + * `['and', 'type=1', ['or', 'id=1', 'id=2']]` will generate `type=1 AND (id=1 OR id=2)`. + * The method will NOT do any quoting or escaping. + * + * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. + * + * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the + * starting and ending values of the range that the column is in. + * For example, `['between', 'id', 1, 10]` will generate `id BETWEEN 1 AND 10`. + * + * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` + * in the generated condition. + * + * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing + * the range of the values that the column or DB expression should be in. For example, + * `['in', 'id', [1, 2, 3]]` will generate `id IN (1, 2, 3)`. + * The method will properly quote the column name and escape values in the range. + * + * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. + * + * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing + * the values that the column or DB expression should be like. + * For example, `['like', 'name', '%tester%']` will generate `name LIKE '%tester%'`. + * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated + * using `AND`. For example, `['like', 'name', ['%test%', '%sample%']]` will generate + * `name LIKE '%test%' AND name LIKE '%sample%'`. + * The method will properly quote the column name and escape values in the range. + * + * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` + * predicates when operand 2 is an array. + * + * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` + * in the generated condition. + * + * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate + * the `NOT LIKE` predicates. + * + * @param array $condition the conditions that should be put in the WHERE part. + * @return static the query object itself + * @see andWhere() + * @see orWhere() + */ + public function where($condition); + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new WHERE condition. Please refer to [[where()]] + * on how to specify this parameter. + * @return static the query object itself + * @see where() + * @see orWhere() + */ + public function andWhere($condition); + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new WHERE condition. Please refer to [[where()]] + * on how to specify this parameter. + * @return static the query object itself + * @see where() + * @see andWhere() + */ + public function orWhere($condition); + + /** + * Sets the ORDER BY part of the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array + * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). + * The method will automatically quote the column names unless a column contains some parenthesis + * (which means the column contains a DB expression). + * @return static the query object itself + * @see addOrderBy() + */ + public function orderBy($columns); + + /** + * Adds additional ORDER BY columns to the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array + * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). + * The method will automatically quote the column names unless a column contains some parenthesis + * (which means the column contains a DB expression). + * @return static the query object itself + * @see orderBy() + */ + public function addOrderBy($columns); + + /** + * Sets the LIMIT part of the query. + * @param integer $limit the limit. Use null or negative value to disable limit. + * @return static the query object itself + */ + public function limit($limit); + + /** + * Sets the OFFSET part of the query. + * @param integer $offset the offset. Use null or negative value to disable offset. + * @return static the query object itself + */ + public function offset($offset); +} \ No newline at end of file diff --git a/framework/yii/db/QueryTrait.php b/framework/yii/db/QueryTrait.php new file mode 100644 index 0000000..a963869 --- /dev/null +++ b/framework/yii/db/QueryTrait.php @@ -0,0 +1,208 @@ + + * @author Carsten Brandt + * @since 2.0 + */ +trait QueryTrait +{ + /** + * @var string|array query condition. This refers to the WHERE clause in a SQL statement. + * For example, `age > 31 AND team = 1`. + * @see where() + */ + public $where; + /** + * @var integer maximum number of records to be returned. If not set or less than 0, it means no limit. + */ + public $limit; + /** + * @var integer zero-based offset from where the records are to be returned. If not set or + * less than 0, it means starting from the beginning. + */ + public $offset; + /** + * @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement. + * The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which + * can be either [SORT_ASC](http://php.net/manual/en/array.constants.php#constant.sort-asc) + * or [SORT_DESC](http://php.net/manual/en/array.constants.php#constant.sort-desc). + * The array may also contain [[Expression]] objects. If that is the case, the expressions + * will be converted into strings without any change. + */ + public $orderBy; + /** + * @var string|callable $column the name of the column by which the query results should be indexed by. + * This can also be a callable (e.g. anonymous function) that returns the index value based on the given + * row data. For more details, see [[indexBy()]]. This property is only used by [[all()]]. + */ + public $indexBy; + + /** + * Sets the [[indexBy]] property. + * @param string|callable $column the name of the column by which the query results should be indexed by. + * This can also be a callable (e.g. anonymous function) that returns the index value based on the given + * row data. The signature of the callable should be: + * + * ~~~ + * function ($row) + * { + * // return the index value corresponding to $row + * } + * ~~~ + * + * @return static the query object itself + */ + public function indexBy($column) + { + $this->indexBy = $column; + return $this; + } + + /** + * Sets the WHERE part of the query. + * + * See [[QueryInterface::where()]] for detailed documentation. + * + * @param array $condition the conditions that should be put in the WHERE part. + * @return static the query object itself + * @see andWhere() + * @see orWhere() + */ + public function where($condition) + { + $this->where = $condition; + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new WHERE condition. Please refer to [[where()]] + * on how to specify this parameter. + * @return static the query object itself + * @see where() + * @see orWhere() + */ + public function andWhere($condition) + { + if ($this->where === null) { + $this->where = $condition; + } else { + $this->where = ['and', $this->where, $condition]; + } + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new WHERE condition. Please refer to [[where()]] + * on how to specify this parameter. + * @return static the query object itself + * @see where() + * @see andWhere() + */ + public function orWhere($condition) + { + if ($this->where === null) { + $this->where = $condition; + } else { + $this->where = ['or', $this->where, $condition]; + } + return $this; + } + + /** + * Sets the ORDER BY part of the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array + * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). + * The method will automatically quote the column names unless a column contains some parenthesis + * (which means the column contains a DB expression). + * @return static the query object itself + * @see addOrderBy() + */ + public function orderBy($columns) + { + $this->orderBy = $this->normalizeOrderBy($columns); + return $this; + } + + /** + * Adds additional ORDER BY columns to the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array + * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). + * The method will automatically quote the column names unless a column contains some parenthesis + * (which means the column contains a DB expression). + * @return static the query object itself + * @see orderBy() + */ + public function addOrderBy($columns) + { + $columns = $this->normalizeOrderBy($columns); + if ($this->orderBy === null) { + $this->orderBy = $columns; + } else { + $this->orderBy = array_merge($this->orderBy, $columns); + } + return $this; + } + + protected function normalizeOrderBy($columns) + { + if (is_array($columns)) { + return $columns; + } else { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + $result = []; + foreach ($columns as $column) { + if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { + $result[$matches[1]] = strcasecmp($matches[2], 'desc') ? SORT_ASC : SORT_DESC; + } else { + $result[$column] = SORT_ASC; + } + } + return $result; + } + } + + /** + * Sets the LIMIT part of the query. + * @param integer $limit the limit. Use null or negative value to disable limit. + * @return static the query object itself + */ + public function limit($limit) + { + $this->limit = $limit; + return $this; + } + + /** + * Sets the OFFSET part of the query. + * @param integer $offset the offset. Use null or negative value to disable offset. + * @return static the query object itself + */ + public function offset($offset) + { + $this->offset = $offset; + return $this; + } +} \ No newline at end of file diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php index 2b3a187..f2ae94c 100644 --- a/framework/yii/db/Schema.php +++ b/framework/yii/db/Schema.php @@ -92,14 +92,16 @@ abstract class Schema extends Object $realName = $this->getRawTableName($name); if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) { - /** @var $cache Cache */ + /** @var Cache $cache */ $cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache; if ($cache instanceof Cache) { $key = $this->getCacheKey($name); if ($refresh || ($table = $cache->get($key)) === false) { $table = $this->loadTableSchema($realName); if ($table !== null) { - $cache->set($key, $table, $db->schemaCacheDuration, new GroupDependency($this->getCacheGroup())); + $cache->set($key, $table, $db->schemaCacheDuration, new GroupDependency([ + 'group' => $this->getCacheGroup(), + ])); } } return $this->_tables[$name] = $table; @@ -213,7 +215,7 @@ abstract class Schema extends Object */ public function refresh() { - /** @var $cache Cache */ + /** @var Cache $cache */ $cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache; if ($this->db->enableSchemaCache && $cache instanceof Cache) { GroupDependency::invalidate($cache, $this->getCacheGroup()); @@ -289,7 +291,7 @@ abstract class Schema extends Object * then this method will do nothing. * @param string $name table name * @return string the properly quoted table name - * @see quoteSimpleTableName + * @see quoteSimpleTableName() */ public function quoteTableName($name) { @@ -314,7 +316,7 @@ abstract class Schema extends Object * then this method will do nothing. * @param string $name column name * @return string the properly quoted column name - * @see quoteSimpleColumnName + * @see quoteSimpleColumnName() */ public function quoteColumnName($name) { diff --git a/framework/yii/grid/ActionColumn.php b/framework/yii/grid/ActionColumn.php index 794198e..2ee1db2 100644 --- a/framework/yii/grid/ActionColumn.php +++ b/framework/yii/grid/ActionColumn.php @@ -12,6 +12,8 @@ use Closure; use yii\helpers\Html; /** + * ActionColumn is a column for the [[GridView]] widget that displays buttons for viewing and manipulating the items. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php index e8a25a7..bd6eacb 100644 --- a/framework/yii/grid/DataColumn.php +++ b/framework/yii/grid/DataColumn.php @@ -15,6 +15,10 @@ use yii\helpers\Html; use yii\helpers\Inflector; /** + * DataColumn is the default column type for the [[GridView]] widget. + * + * It is used to show data columns and allows sorting them. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php index 2981c82..de99a18 100644 --- a/framework/yii/grid/GridView.php +++ b/framework/yii/grid/GridView.php @@ -16,6 +16,10 @@ use yii\helpers\Json; use yii\widgets\BaseListView; /** + * The GridView widget is used to display data in a grid. + * + * It provides features like sorting, paging and also filtering the data. + * * @author Qiang Xue * @since 2.0 */ @@ -89,10 +93,9 @@ class GridView extends BaseListView */ public $showFooter = false; /** - * @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data. - * If false, the grid view will still be displayed (without body content though). + * @var boolean whether to show the grid view if [[dataProvider]] returns no data. */ - public $empty = false; + public $showOnEmpty = true; /** * @var array|Formatter the formatter used to format model attribute values into displayable texts. * This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]] @@ -342,7 +345,13 @@ class GridView extends BaseListView } } } - return "\n" . implode("\n", $rows) . "\n"; + + if (empty($rows)) { + $colspan = count($this->columns); + return "\n" . $this->renderEmpty() . "\n"; + } else { + return "\n" . implode("\n", $rows) . "\n"; + } } /** diff --git a/framework/yii/grid/GridViewAsset.php b/framework/yii/grid/GridViewAsset.php index ae49070..a67999d 100644 --- a/framework/yii/grid/GridViewAsset.php +++ b/framework/yii/grid/GridViewAsset.php @@ -10,6 +10,7 @@ namespace yii\grid; use yii\web\AssetBundle; /** + * This asset bundle provides the javascript files for the [[GridView]] widget. * * @author Qiang Xue * @since 2.0 diff --git a/framework/yii/helpers/BaseHtml.php b/framework/yii/helpers/BaseHtml.php index 9f3df0e..71ad9ea 100644 --- a/framework/yii/helpers/BaseHtml.php +++ b/framework/yii/helpers/BaseHtml.php @@ -86,7 +86,7 @@ class BaseHtml * @param boolean $doubleEncode whether to encode HTML entities in `$content`. If false, * HTML entities in `$content` will not be further encoded. * @return string the encoded content - * @see decode + * @see decode() * @see http://www.php.net/manual/en/function.htmlspecialchars.php */ public static function encode($content, $doubleEncode = true) @@ -99,7 +99,7 @@ class BaseHtml * This is the opposite of [[encode()]]. * @param string $content the content to be decoded * @return string the decoded content - * @see encode + * @see encode() * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php */ public static function decode($content) @@ -116,8 +116,8 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated HTML tag - * @see beginTag - * @see endTag + * @see beginTag() + * @see endTag() */ public static function tag($name, $content = '', $options = []) { @@ -132,8 +132,8 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated start tag - * @see endTag - * @see tag + * @see endTag() + * @see tag() */ public static function beginTag($name, $options = []) { @@ -144,8 +144,8 @@ class BaseHtml * Generates an end tag. * @param string $name the tag name * @return string the generated end tag - * @see beginTag - * @see tag + * @see beginTag() + * @see tag() */ public static function endTag($name) { @@ -187,7 +187,7 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated link tag - * @see url + * @see url() */ public static function cssFile($url, $options = []) { @@ -203,7 +203,7 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated script tag - * @see url + * @see url() */ public static function jsFile($url, $options = []) { @@ -222,7 +222,7 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated form start tag. - * @see endForm + * @see endForm() */ public static function beginForm($action = '', $method = 'post', $options = []) { @@ -271,7 +271,7 @@ class BaseHtml /** * Generates a form end tag. * @return string the generated tag - * @see beginForm + * @see beginForm() */ public static function endForm() { @@ -290,7 +290,7 @@ class BaseHtml * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. * If a value is null, the corresponding attribute will not be rendered. * @return string the generated hyperlink - * @see url + * @see url() */ public static function a($text, $url = null, $options = []) { diff --git a/framework/yii/helpers/BaseInflector.php b/framework/yii/helpers/BaseInflector.php index 8d5fe28..deb8239 100644 --- a/framework/yii/helpers/BaseInflector.php +++ b/framework/yii/helpers/BaseInflector.php @@ -328,7 +328,7 @@ class BaseInflector * Converts a word like "send_email" to "SendEmail". It * will remove non alphanumeric character from the word, so * "who's online" will be converted to "WhoSOnline" - * @see variablize + * @see variablize() * @param string $word the word to CamelCase * @return string */ diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php index 6b7f1cf..8e86654 100644 --- a/framework/yii/helpers/BaseSecurity.php +++ b/framework/yii/helpers/BaseSecurity.php @@ -175,7 +175,7 @@ class BaseSecurity /** * Returns a secret key associated with the specified name. * If the secret key does not exist, a random key will be generated - * and saved in the file "keys.php" under the application's runtime directory + * and saved in the file "keys.data" under the application's runtime directory * so that the same secret key can be returned in future requests. * @param string $name the name that is associated with the secret key * @param integer $length the length of the key that should be generated if not exists @@ -184,16 +184,16 @@ class BaseSecurity public static function getSecretKey($name, $length = 32) { static $keys; - $keyFile = Yii::$app->getRuntimePath() . '/keys.php'; + $keyFile = Yii::$app->getRuntimePath() . '/keys.json'; if ($keys === null) { $keys = []; if (is_file($keyFile)) { - $keys = require($keyFile); + $keys = json_decode(file_get_contents($keyFile), true); } } if (!isset($keys[$name])) { $keys[$name] = static::generateRandomKey($length); - file_put_contents($keyFile, " [ + * 'class' => 'yii\i18n\Formatter', + * ] + * ``` + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index fe0b533..5575621 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -14,6 +14,9 @@ use yii\base\InvalidConfigException; /** * I18N provides features related with internationalization (I18N) and localization (L10N). * + * I18N is configured as an application component in [[yii\base\Application]] by default. + * You can access that instance via `Yii::$app->i18n`. + * * @property MessageFormatter $messageFormatter The message formatter to be used to format message via ICU * message format. Note that the type of this property differs in getter and setter. See * [[getMessageFormatter()]] and [[setMessageFormatter()]] for details. diff --git a/framework/yii/log/Target.php b/framework/yii/log/Target.php index cd1256a..c9d5d97 100644 --- a/framework/yii/log/Target.php +++ b/framework/yii/log/Target.php @@ -112,7 +112,7 @@ abstract class Target extends Component { $context = []; if ($this->logUser && ($user = Yii::$app->getComponent('user', false)) !== null) { - /** @var $user \yii\web\User */ + /** @var \yii\web\User $user */ $context[] = 'User: ' . $user->getId(); } diff --git a/framework/yii/mail/BaseMailer.php b/framework/yii/mail/BaseMailer.php index 2b6918a..90565c9 100644 --- a/framework/yii/mail/BaseMailer.php +++ b/framework/yii/mail/BaseMailer.php @@ -16,11 +16,12 @@ use yii\web\View; /** * BaseMailer serves as a base class that implements the basic functions required by [[MailerInterface]]. * - * Concrete child classes should may focus on implementing the [[send()]] method. + * Concrete child classes should may focus on implementing the [[sendMessage()]] method. * * @see BaseMessage * - * @property View|array $view view instance or its array configuration. + * @property View $view View instance. Note that the type of this property differs in getter and setter. See + * [[getView()]] and [[setView()]] for details. * * @author Paul Klimov * @since 2.0 @@ -28,10 +29,6 @@ use yii\web\View; abstract class BaseMailer extends Component implements MailerInterface, ViewContextInterface { /** - * @var \yii\base\View|array view instance or its array configuration. - */ - private $_view = []; - /** * @var string directory containing view files for this email messages. * This can be specified as an absolute path or path alias. */ @@ -70,6 +67,33 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont * @var string the default class name of the new message instances created by [[createMessage()]] */ public $messageClass = 'yii\mail\BaseMessage'; + /** + * @var boolean whether to save email messages as files under [[fileTransportPath]] instead of sending them + * to the actual recipients. This is usually used during development for debugging purpose. + * @see fileTransportPath + */ + public $useFileTransport = false; + /** + * @var string the directory where the email messages are saved when [[useFileTransport]] is true. + */ + public $fileTransportPath = '@runtime/mail'; + /** + * @var callback a PHP callback that will be called by [[send()]] when [[useFileTransport]] is true. + * The callback should return a file name which will be used to save the email message. + * If not set, the file name will be generated based on the current timestamp. + * + * The signature of the callback is: + * + * ~~~ + * function ($mailer, $message) + * ~~~ + */ + public $fileTransportCallback; + + /** + * @var \yii\base\View|array view instance or its array configuration. + */ + private $_view = []; /** * @param array|View $view view instance or its array configuration that will be used to @@ -172,6 +196,30 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont } /** + * Sends the given email message. + * This method will log a message about the email being sent. + * If [[useFileTransport]] is true, it will save the email as a file under [[fileTransportPath]]. + * Otherwise, it will call [[sendMessage()]] to send the email to its recipient(s). + * Child classes should implement [[sendMessage()]] with the actual email sending logic. + * @param MessageInterface $message email message instance to be sent + * @return boolean whether the message has been sent successfully + */ + public function send($message) + { + $address = $message->getTo(); + if (is_array($address)) { + $address = implode(', ', array_keys($address)); + } + Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); + + if ($this->useFileTransport) { + return $this->saveMessage($message); + } else { + return $this->sendMessage($message); + } + } + + /** * Sends multiple messages at once. * * The default implementation simply calls [[send()]] multiple times. @@ -211,6 +259,35 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont } /** + * Sends the specified message. + * This method should be implemented by child classes with the actual email sending logic. + * @param MessageInterface $message the message to be sent + * @return boolean whether the message is sent successfully + */ + abstract protected function sendMessage($message); + + /** + * Saves the message as a file under [[fileTransportPath]]. + * @param MessageInterface $message + * @return boolean whether the message is saved successfully + */ + protected function saveMessage($message) + { + $path = Yii::getAlias($this->fileTransportPath); + if (!is_dir(($path))) { + mkdir($path, 0777, true); + } + if ($this->fileTransportCallback !== null) { + $file = $path . '/' . call_user_func($this->fileTransportCallback, $this, $message); + } else { + $time = microtime(true); + $file = $path . '/' . date('Ymd-His-', $time) . sprintf('%04d', (int)(($time - (int)$time) * 10000)) . '-' . sprintf('%04d', mt_rand(0, 10000)) . '.eml'; + } + file_put_contents($file, $message->toString()); + return true; + } + + /** * Finds the view file corresponding to the specified relative view name. * This method will return the view file by prefixing the view name with [[viewPath]]. * @param string $view a relative view name. The name does NOT start with a slash. diff --git a/framework/yii/mail/BaseMessage.php b/framework/yii/mail/BaseMessage.php index 04b7200..01b671c 100644 --- a/framework/yii/mail/BaseMessage.php +++ b/framework/yii/mail/BaseMessage.php @@ -18,7 +18,7 @@ use Yii; * * @see BaseMailer * - * @property BaseMailer $mailer mailer component instance. This property is read-only. + * @property MailerInterface $mailer The mailer component. This property is read-only. * * @author Paul Klimov * @since 2.0 diff --git a/framework/yii/rbac/PhpManager.php b/framework/yii/rbac/PhpManager.php index a91d9bd..57ede09 100644 --- a/framework/yii/rbac/PhpManager.php +++ b/framework/yii/rbac/PhpManager.php @@ -36,8 +36,8 @@ class PhpManager extends Manager * If not set, it will be using 'protected/data/rbac.php' as the data file. * Make sure this file is writable by the Web server process if the authorization * needs to be changed. - * @see loadFromFile - * @see saveToFile + * @see loadFromFile() + * @see saveToFile() */ public $authFile; @@ -74,7 +74,7 @@ class PhpManager extends Manager if (!isset($this->_items[$itemName])) { return false; } - /** @var $item Item */ + /** @var Item $item */ $item = $this->_items[$itemName]; Yii::trace('Checking permission: ' . $item->getName(), __METHOD__); if (!isset($params['userId'])) { @@ -85,7 +85,7 @@ class PhpManager extends Manager return true; } if (isset($this->_assignments[$userId][$itemName])) { - /** @var $assignment Assignment */ + /** @var Assignment $assignment */ $assignment = $this->_assignments[$userId][$itemName]; if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) { return true; @@ -113,9 +113,9 @@ class PhpManager extends Manager if (!isset($this->_items[$childName], $this->_items[$itemName])) { throw new Exception("Either '$itemName' or '$childName' does not exist."); } - /** @var $child Item */ + /** @var Item $child */ $child = $this->_items[$childName]; - /** @var $item Item */ + /** @var Item $item */ $item = $this->_items[$itemName]; $this->checkItemChildType($item->type, $child->type); if ($this->detectLoop($itemName, $childName)) { @@ -270,14 +270,14 @@ class PhpManager extends Manager $items = []; if ($userId === null) { foreach ($this->_items as $name => $item) { - /** @var $item Item */ + /** @var Item $item */ if ($item->type == $type) { $items[$name] = $item; } } } elseif (isset($this->_assignments[$userId])) { foreach ($this->_assignments[$userId] as $assignment) { - /** @var $assignment Assignment */ + /** @var Assignment $assignment */ $name = $assignment->itemName; if (isset($this->_items[$name]) && ($type === null || $this->_items[$name]->type == $type)) { $items[$name] = $this->_items[$name]; @@ -400,7 +400,7 @@ class PhpManager extends Manager { $items = []; foreach ($this->_items as $name => $item) { - /** @var $item Item */ + /** @var Item $item */ $items[$name] = [ 'type' => $item->type, 'description' => $item->description, @@ -409,7 +409,7 @@ class PhpManager extends Manager ]; if (isset($this->_children[$name])) { foreach ($this->_children[$name] as $child) { - /** @var $child Item */ + /** @var Item $child */ $items[$name]['children'][] = $child->getName(); } } @@ -417,7 +417,7 @@ class PhpManager extends Manager foreach ($this->_assignments as $userId => $assignments) { foreach ($assignments as $name => $assignment) { - /** @var $assignment Assignment */ + /** @var Assignment $assignment */ if (isset($items[$name])) { $items[$name]['assignments'][$userId] = [ 'bizRule' => $assignment->bizRule, @@ -505,7 +505,7 @@ class PhpManager extends Manager return false; } foreach ($this->_children[$childName] as $child) { - /** @var $child Item */ + /** @var Item $child */ if ($this->detectLoop($itemName, $child->getName())) { return true; } @@ -517,7 +517,7 @@ class PhpManager extends Manager * Loads the authorization data from a PHP script file. * @param string $file the file path. * @return array the authorization data - * @see saveToFile + * @see saveToFile() */ protected function loadFromFile($file) { @@ -532,7 +532,7 @@ class PhpManager extends Manager * Saves the authorization data to a PHP script file. * @param array $data the authorization data * @param string $file the file path. - * @see loadFromFile + * @see loadFromFile() */ protected function saveToFile($data, $file) { diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php index f70f414..34b556e 100644 --- a/framework/yii/requirements/requirements.php +++ b/framework/yii/requirements/requirements.php @@ -3,7 +3,7 @@ * These are the Yii core requirements for the [[YiiRequirementChecker]] instance. * These requirements are mandatory for any Yii application. * - * @var $this YiiRequirementChecker + * @var YiiRequirementChecker $this */ return array( array( diff --git a/framework/yii/requirements/views/console/index.php b/framework/yii/requirements/views/console/index.php index 6935107..1d87fe9 100644 --- a/framework/yii/requirements/views/console/index.php +++ b/framework/yii/requirements/views/console/index.php @@ -1,7 +1,7 @@ diff --git a/framework/yii/validators/ExistValidator.php b/framework/yii/validators/ExistValidator.php index 2746b06..ba3f332 100644 --- a/framework/yii/validators/ExistValidator.php +++ b/framework/yii/validators/ExistValidator.php @@ -65,7 +65,7 @@ class ExistValidator extends Validator return; } - /** @var $className \yii\db\ActiveRecord */ + /** @var \yii\db\ActiveRecord $className */ $className = $this->className === null ? get_class($object) : $this->className; $attributeName = $this->attributeName === null ? $attribute : $this->attributeName; $query = $className::find(); @@ -92,7 +92,7 @@ class ExistValidator extends Validator if ($this->attributeName === null) { throw new InvalidConfigException('The "attributeName" property must be set.'); } - /** @var $className \yii\db\ActiveRecord */ + /** @var \yii\db\ActiveRecord $className */ $className = $this->className; $query = $className::find(); $query->where([$this->attributeName => $value]); diff --git a/framework/yii/validators/InlineValidator.php b/framework/yii/validators/InlineValidator.php index dabdb4a..febf8dc 100644 --- a/framework/yii/validators/InlineValidator.php +++ b/framework/yii/validators/InlineValidator.php @@ -26,8 +26,11 @@ class InlineValidator extends Validator { /** * @var string|\Closure an anonymous function or the name of a model class method that will be - * called to perform the actual validation. Note that if you use anonymous function, you cannot - * use `$this` in it unless you are using PHP 5.4 or above. + * called to perform the actual validation. The signature of the method should be like the following: + * + * ~~~ + * function foo($attribute, $params) + * ~~~ */ public $method; /** @@ -39,7 +42,7 @@ class InlineValidator extends Validator * The signature of the method should be like the following: * * ~~~ - * function foo($attribute) + * function foo($attribute, $params) * { * return "javascript"; * } @@ -93,7 +96,7 @@ class InlineValidator extends Validator if (is_string($method)) { $method = [$object, $method]; } - return call_user_func($method, $attribute); + return call_user_func($method, $attribute, $this->params); } else { return null; } diff --git a/framework/yii/validators/PunycodeAsset.php b/framework/yii/validators/PunycodeAsset.php index 08439bf..c0c1e2b 100644 --- a/framework/yii/validators/PunycodeAsset.php +++ b/framework/yii/validators/PunycodeAsset.php @@ -9,6 +9,8 @@ namespace yii\validators; use yii\web\AssetBundle; /** + * This asset bundle provides the javascript files needed for the [[EmailValidator]]s client validation. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php index 334d057..7006cc4 100644 --- a/framework/yii/validators/UniqueValidator.php +++ b/framework/yii/validators/UniqueValidator.php @@ -60,7 +60,7 @@ class UniqueValidator extends Validator return; } - /** @var $className \yii\db\ActiveRecord */ + /** @var \yii\db\ActiveRecord $className */ $className = $this->className === null ? get_class($object) : $this->className; $attributeName = $this->attributeName === null ? $attribute : $this->attributeName; diff --git a/framework/yii/validators/ValidationAsset.php b/framework/yii/validators/ValidationAsset.php index 8ff1b2d..14d7ad0 100644 --- a/framework/yii/validators/ValidationAsset.php +++ b/framework/yii/validators/ValidationAsset.php @@ -9,6 +9,8 @@ namespace yii\validators; use yii\web\AssetBundle; /** + * This asset bundle provides the javascript files for client validation. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php index 012f392..2cd611b 100644 --- a/framework/yii/validators/Validator.php +++ b/framework/yii/validators/Validator.php @@ -76,7 +76,8 @@ abstract class Validator extends Component ]; /** - * @var array list of attributes to be validated. + * @var array|string attributes to be validated by this validator. For multiple attributes, + * please specify them as an array; for single attribute, you may use either a string or an array. */ public $attributes = []; /** @@ -88,11 +89,13 @@ abstract class Validator extends Component */ public $message; /** - * @var array list of scenarios that the validator can be applied to. + * @var array|string scenarios that the validator can be applied to. For multiple scenarios, + * please specify them as an array; for single scenario, you may use either a string or an array. */ public $on = []; /** - * @var array list of scenarios that the validator should not be applied to. + * @var array|string scenarios that the validator should not be applied to. For multiple scenarios, + * please specify them as an array; for single scenario, you may use either a string or an array. */ public $except = []; /** @@ -133,19 +136,8 @@ abstract class Validator extends Component */ public static function createValidator($type, $object, $attributes, $params = []) { - if (!is_array($attributes)) { - $attributes = preg_split('/[\s,]+/', $attributes, -1, PREG_SPLIT_NO_EMPTY); - } $params['attributes'] = $attributes; - if (isset($params['on']) && !is_array($params['on'])) { - $params['on'] = preg_split('/[\s,]+/', $params['on'], -1, PREG_SPLIT_NO_EMPTY); - } - - if (isset($params['except']) && !is_array($params['except'])) { - $params['except'] = preg_split('/[\s,]+/', $params['except'], -1, PREG_SPLIT_NO_EMPTY); - } - if (method_exists($object, $type)) { // method-based validator $params['class'] = __NAMESPACE__ . '\InlineValidator'; @@ -167,6 +159,17 @@ abstract class Validator extends Component } /** + * @inheritdoc + */ + public function init() + { + parent::init(); + $this->attributes = (array)$this->attributes; + $this->on = (array)$this->on; + $this->except = (array)$this->except; + } + + /** * Validates the specified object. * @param \yii\base\Model $object the data object being validated * @param array|null $attributes the list of attributes to be validated. diff --git a/framework/yii/web/AccessControl.php b/framework/yii/web/AccessControl.php index d11f59c..549f087 100644 --- a/framework/yii/web/AccessControl.php +++ b/framework/yii/web/AccessControl.php @@ -102,7 +102,7 @@ class AccessControl extends ActionFilter { $user = Yii::$app->getUser(); $request = Yii::$app->getRequest(); - /** @var $rule AccessRule */ + /** @var AccessRule $rule */ foreach ($this->rules as $rule) { if ($allow = $rule->allows($action, $user, $request)) { return true; diff --git a/framework/yii/web/AssetConverter.php b/framework/yii/web/AssetConverter.php index ba64aa9..a93b915 100644 --- a/framework/yii/web/AssetConverter.php +++ b/framework/yii/web/AssetConverter.php @@ -14,6 +14,8 @@ use yii\base\Exception; /** * AssetConverter supports conversion of several popular script formats into JS or CSS scripts. * + * It is used by [[AssetManager]] to convert files after they have been published. + * * @author Qiang Xue * @since 2.0 */ @@ -63,6 +65,8 @@ class AssetConverter extends Component implements AssetConverterInterface * @param string $asset the name of the asset file * @param string $result the name of the file to be generated by the converter command * @return bool true on success, false on failure. Failures will be logged. + * @throws \yii\base\Exception when the command fails and YII_DEBUG is true. + * In production mode the error will be logged. */ protected function runCommand($command, $basePath, $asset, $result) { diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php index 49374f0..b562cf6 100644 --- a/framework/yii/web/AssetManager.php +++ b/framework/yii/web/AssetManager.php @@ -16,6 +16,22 @@ use yii\helpers\FileHelper; /** * AssetManager manages asset bundles and asset publishing. * + * AssetManager is configured as an application component in [[yii\web\Application]] by default. + * You can access that instance via `Yii::$app->assetManager`. + * + * You can modify its configuration by adding an array to your application config under `components` + * as it is shown in the following example: + * + * ~~~ + * 'assetManager' => [ + * 'bundles' => [ + * // you can override AssetBundle configs here + * ], + * //'linkAssets' => true, + * // ... + * ] + * ~~~ + * * @property AssetConverterInterface $converter The asset converter. Note that the type of this property * differs in getter and setter. See [[getConverter()]] and [[setConverter()]] for details. * diff --git a/framework/yii/web/CacheSession.php b/framework/yii/web/CacheSession.php index 84033b7..7b4a98d 100644 --- a/framework/yii/web/CacheSession.php +++ b/framework/yii/web/CacheSession.php @@ -19,7 +19,17 @@ use yii\base\InvalidConfigException; * * Beware, by definition cache storage are volatile, which means the data stored on them * may be swapped out and get lost. Therefore, you must make sure the cache used by this component - * is NOT volatile. If you want to use database as storage medium, use [[DbSession]] is a better choice. + * is NOT volatile. If you want to use database as storage medium, [[DbSession]] is a better choice. + * + * The following example shows how you can configure the application to use CacheSession: + * Add the following to your application config under `components`: + * + * ~~~ + * 'session' => [ + * 'class' => 'yii\web\CacheSession', + * // 'cache' => 'mycache', + * ] + * ~~~ * * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. * diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php index 6927893..3b08b7e 100644 --- a/framework/yii/web/Controller.php +++ b/framework/yii/web/Controller.php @@ -14,6 +14,9 @@ use yii\helpers\Html; /** * Controller is the base class of web controllers. * + * @property string $canonicalUrl The canonical URL of the currently requested page. This property is + * read-only. + * * @author Qiang Xue * @since 2.0 */ @@ -38,7 +41,7 @@ class Controller extends \yii\base\Controller * @param \yii\base\Action $action the action to be bound with parameters * @param array $params the parameters to be bound to the action * @return array the valid parameters that the action can run with. - * @throws HttpException if there are missing parameters. + * @throws HttpException if there are missing or invalid parameters. */ public function bindActionParams($action, $params) { @@ -54,7 +57,15 @@ class Controller extends \yii\base\Controller foreach ($method->getParameters() as $param) { $name = $param->getName(); if (array_key_exists($name, $params)) { - $args[] = $actionParams[$name] = $params[$name]; + if ($param->isArray()) { + $args[] = $actionParams[$name] = is_array($params[$name]) ? $params[$name] : [$params[$name]]; + } elseif (!is_array($params[$name])) { + $args[] = $actionParams[$name] = $params[$name]; + } else { + throw new HttpException(400, Yii::t('yii', 'Invalid data received for parameter "{param}".', [ + 'param' => $name, + ])); + } unset($params[$name]); } elseif ($param->isDefaultValueAvailable()) { $args[] = $actionParams[$name] = $param->getDefaultValue(); @@ -128,7 +139,7 @@ class Controller extends \yii\base\Controller * $this->registerLinkTag(['rel' => 'canonical', 'href' => Yii::$app->controller->canonicalUrl]); * ~~~ * - * @return string + * @return string the canonical URL of the currently requested page */ public function getCanonicalUrl() { @@ -139,6 +150,13 @@ class Controller extends \yii\base\Controller * Redirects the browser to the specified URL. * This method is a shortcut to [[Response::redirect()]]. * + * You can use it in an action by returning the [[Response]] directly: + * + * ```php + * // stop executing this action and redirect to login page + * return $this->redirect(['login']); + * ``` + * * @param string|array $url the URL to be redirected to. This can be in one of the following formats: * * - a string representing a URL (e.g. "http://example.com") @@ -161,6 +179,14 @@ class Controller extends \yii\base\Controller /** * Redirects the browser to the home page. + * + * You can use this method in an action by returning the [[Response]] directly: + * + * ```php + * // stop executing this action and redirect to home page + * return $this->goHome(); + * ``` + * * @return Response the current response object */ public function goHome() @@ -170,6 +196,14 @@ class Controller extends \yii\base\Controller /** * Redirects the browser to the last visited page. + * + * You can use this method in an action by returning the [[Response]] directly: + * + * ```php + * // stop executing this action and redirect to last visited page + * return $this->goBack(); + * ``` + * * @param string|array $defaultUrl the default return URL in case it was not set previously. * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to. * Please refer to [[User::setReturnUrl()]] on accepted format of the URL. @@ -184,6 +218,14 @@ class Controller extends \yii\base\Controller /** * Refreshes the current page. * This method is a shortcut to [[Response::refresh()]]. + * + * You can use it in an action by returning the [[Response]] directly: + * + * ```php + * // stop executing this action and refresh the current page + * return $this->refresh(); + * ``` + * * @param string $anchor the anchor that should be appended to the redirection URL. * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it. * @return Response the response object itself diff --git a/framework/yii/web/DbSession.php b/framework/yii/web/DbSession.php index 410439b..d5d1742 100644 --- a/framework/yii/web/DbSession.php +++ b/framework/yii/web/DbSession.php @@ -19,6 +19,7 @@ use yii\base\InvalidConfigException; * must be pre-created. The table name can be changed by setting [[sessionTable]]. * * The following example shows how you can configure the application to use DbSession: + * Add the following to your application config under `components`: * * ~~~ * 'session' => [ diff --git a/framework/yii/web/HttpCache.php b/framework/yii/web/HttpCache.php index d2f3923..134df71 100644 --- a/framework/yii/web/HttpCache.php +++ b/framework/yii/web/HttpCache.php @@ -12,7 +12,32 @@ use yii\base\ActionFilter; use yii\base\Action; /** - * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers + * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers. + * + * It is an action filter that can be added to a controller and handles the `beforeAction` event. + * + * To use AccessControl, declare it in the `behaviors()` method of your controller class. + * In the following example the filter will be applied to the `list`-action and + * the Last-Modified header will contain the date of the last update to the user table in the database. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'httpCache' => [ + * 'class' => \yii\web\HttpCache::className(), + * 'only' => ['list'], + * 'lastModified' => function ($action, $params) { + * $q = new Query(); + * return strtotime($q->from('users')->max('updated_timestamp')); + * }, + * // 'etagSeed' => function ($action, $params) { + * // return // generate etag seed here + * // } + * ], + * ]; + * } + * ~~~ * * @author Da:Sourcerer * @author Qiang Xue diff --git a/framework/yii/web/HttpException.php b/framework/yii/web/HttpException.php index 2e677d5..2398437 100644 --- a/framework/yii/web/HttpException.php +++ b/framework/yii/web/HttpException.php @@ -16,6 +16,14 @@ use yii\base\UserException; * keeps a standard HTTP status code (e.g. 404, 500). Error handlers may use this status code * to decide how to format the error page. * + * Throwing an HttpException like in the following example will result in the 404 page to be displayed. + * + * ```php + * if ($item === null) { // item does not exist + * throw new \yii\web\HttpException(404, 'The requested Item could not be found.'); + * } + * ``` + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/web/PageCache.php b/framework/yii/web/PageCache.php index 2a3187b..4c8cc50 100644 --- a/framework/yii/web/PageCache.php +++ b/framework/yii/web/PageCache.php @@ -15,6 +15,35 @@ use yii\caching\Dependency; /** * The PageCache provides functionality for whole page caching * + * It is an action filter that can be added to a controller and handles the `beforeAction` event. + * + * To use PageCache, declare it in the `behaviors()` method of your controller class. + * In the following example the filter will be applied to the `list`-action and + * cache the whole page for maximum 60 seconds or until the count of entries in the post table changes. + * It also stores different versions of the page depended on the route ([[varyByRoute]] is true by default), + * the application language and user id. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'pageCache' => [ + * 'class' => \yii\web\PageCache::className(), + * 'only' => ['list'], + * 'duration' => 60, + * 'dependecy' => [ + * 'class' => 'yii\caching\DbDependency', + * 'sql' => 'SELECT COUNT(*) FROM post', + * ], + * 'variations' => [ + * Yii::$app->language, + * Yii::$app->user->id + * ] + * ], + * ]; + * } + * ~~~ + * * @author Qiang Xue * @since 2.0 */ @@ -60,6 +89,7 @@ class PageCache extends ActionFilter * [ * Yii::$app->language, * ] + * ~~~ */ public $variations; /** diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index a6a92fa..2071afa 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -18,6 +18,9 @@ use yii\helpers\Security; * Also it provides an interface to retrieve request parameters from $_POST, $_GET, $_COOKIES and REST * parameters sent via other HTTP methods like PUT or DELETE. * + * Request is configured as an application component in [[yii\web\Application]] by default. + * You can access that instance via `Yii::$app->request`. + * * @property string $absoluteUrl The currently requested absolute URL. This property is read-only. * @property string $acceptTypes User browser accept types, null if not present. This property is read-only. * @property array $acceptedContentTypes The content types ordered by the preference level. The first element @@ -31,6 +34,8 @@ use yii\helpers\Security; * @property string $csrfToken The random token for CSRF validation. This property is read-only. * @property string $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned * if no such header is sent. This property is read-only. + * @property array $delete The DELETE request parameter values. This property is read-only. + * @property array $get The GET request parameter values. This property is read-only. * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. * `http://www.yiiframework.com`). * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only. @@ -47,11 +52,14 @@ use yii\helpers\Security; * read-only. * @property string $method Request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. The value returned is * turned into upper case. This property is read-only. + * @property array $patch The PATCH request parameter values. This property is read-only. * @property string $pathInfo Part of the request URL that is after the entry script and before the question * mark. Note, the returned path info is already URL-decoded. * @property integer $port Port number for insecure requests. + * @property array $post The POST request parameter values. This property is read-only. * @property string $preferredLanguage The language that the application should use. Null is returned if both * [[getAcceptedLanguages()]] and `$languages` are empty. This property is read-only. + * @property array $put The PUT request parameter values. This property is read-only. * @property string $queryString Part of the request URL that is after the question mark. This property is * read-only. * @property string $rawBody The request body. This property is read-only. @@ -111,8 +119,8 @@ class Request extends \yii\base\Request /** * @var string|boolean the name of the POST parameter that is used to indicate if a request is a PUT, PATCH or DELETE * request tunneled through POST. Default to '_method'. - * @see getMethod - * @see getRestParams + * @see getMethod() + * @see getRestParams() */ public $restVar = '_method'; @@ -237,7 +245,7 @@ class Request extends \yii\base\Request /** * Returns the request parameters for the RESTful request. * @return array the RESTful request parameters - * @see getMethod + * @see getMethod() */ public function getRestParams() { @@ -293,7 +301,7 @@ class Request extends \yii\base\Request * @param string $name the GET parameter name. If not specified, whole $_GET is returned. * @param mixed $defaultValue the default parameter value if the GET parameter does not exist. * @return mixed the GET parameter value - * @see getPost + * @see getPost() */ public function get($name = null, $defaultValue = null) { @@ -304,12 +312,22 @@ class Request extends \yii\base\Request } /** + * Returns the GET request parameter values. + * @return array the GET request parameter values + */ + public function getGet() + { + return $_GET; + } + + /** * Returns the named POST parameter value. * If the POST parameter does not exist, the second parameter to this method will be returned. * @param string $name the POST parameter name. If not specified, whole $_POST is returned. * @param mixed $defaultValue the default parameter value if the POST parameter does not exist. + * @property array the POST request parameter values * @return mixed the POST parameter value - * @see getParam + * @see get() */ public function getPost($name = null, $defaultValue = null) { @@ -323,6 +341,7 @@ class Request extends \yii\base\Request * Returns the named DELETE parameter value. * @param string $name the DELETE parameter name. If not specified, an array of DELETE parameters is returned. * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist. + * @property array the DELETE request parameter values * @return mixed the DELETE parameter value */ public function getDelete($name = null, $defaultValue = null) @@ -337,6 +356,7 @@ class Request extends \yii\base\Request * Returns the named PUT parameter value. * @param string $name the PUT parameter name. If not specified, an array of PUT parameters is returned. * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist. + * @property array the PUT request parameter values * @return mixed the PUT parameter value */ public function getPut($name = null, $defaultValue = null) @@ -351,6 +371,7 @@ class Request extends \yii\base\Request * Returns the named PATCH parameter value. * @param string $name the PATCH parameter name. If not specified, an array of PATCH parameters is returned. * @param mixed $defaultValue the default parameter value if the PATCH parameter does not exist. + * @property array the PATCH request parameter values * @return mixed the PATCH parameter value */ public function getPatch($name = null, $defaultValue = null) @@ -369,7 +390,7 @@ class Request extends \yii\base\Request * By default this is determined based on the user request information. * You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property. * @return string schema and hostname part (with port number if needed) of the request URL (e.g. `http://www.yiiframework.com`) - * @see setHostInfo + * @see setHostInfo() */ public function getHostInfo() { @@ -408,7 +429,7 @@ class Request extends \yii\base\Request * This is similar to [[scriptUrl]] except that it does not include the script file name, * and the ending slashes are removed. * @return string the relative URL for the application - * @see setScriptUrl + * @see setScriptUrl() */ public function getBaseUrl() { @@ -725,7 +746,7 @@ class Request extends \yii\base\Request * Defaults to 80, or the port specified by the server if the current * request is insecure. * @return integer port number for insecure requests. - * @see setPort + * @see setPort() */ public function getPort() { @@ -756,7 +777,7 @@ class Request extends \yii\base\Request * Defaults to 443, or the port specified by the server if the current * request is secure. * @return integer port number for secure requests. - * @see setSecurePort + * @see setSecurePort() */ public function getSecurePort() { diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php index ea1f0d9..8934fa1 100644 --- a/framework/yii/web/Response.php +++ b/framework/yii/web/Response.php @@ -22,6 +22,20 @@ use yii\helpers\StringHelper; * It holds the [[headers]], [[cookies]] and [[content]] that is to be sent to the client. * It also controls the HTTP [[statusCode|status code]]. * + * Response is configured as an application component in [[yii\web\Application]] by default. + * You can access that instance via `Yii::$app->response`. + * + * You can modify its configuration by adding an array to your application config under `components` + * as it is shown in the following example: + * + * ~~~ + * 'response' => [ + * 'format' => yii\web\Response::FORMAT_JSON, + * 'charset' => 'UTF-8', + * // ... + * ] + * ~~~ + * * @property CookieCollection $cookies The cookie collection. This property is read-only. * @property HeaderCollection $headers The header collection. This property is read-only. * @property boolean $isClientError Whether this response indicates a client error. This property is diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php index b03c74b..9fba49a 100644 --- a/framework/yii/web/Session.php +++ b/framework/yii/web/Session.php @@ -15,7 +15,7 @@ use yii\base\InvalidParamException; * Session provides session data management and the related configurations. * * Session is a Web application component that can be accessed via `Yii::$app->session`. - + * * To start the session, call [[open()]]; To complete and send out session data, call [[close()]]; * To destroy the session, call [[destroy()]]. * @@ -80,11 +80,12 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co * @var string the name of the session variable that stores the flash message data. */ public $flashVar = '__flash'; - /** - * @var array parameter-value pairs to override default session cookie parameters + * @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function + * Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httpOnly' + * @see http://www.php.net/manual/en/function.session-set-cookie-params.php */ - public $cookieParams = ['httpOnly' => true]; + private $_cookieParams = ['httpOnly' => true]; /** * Initializes the application component. @@ -135,7 +136,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ); } - $this->setCookieParams($this->cookieParams); + $this->setCookieParamsInternal(); @session_start(); @@ -263,26 +264,36 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co $params['httpOnly'] = $params['httponly']; unset($params['httponly']); } - return $params; + return array_merge($params, $this->_cookieParams); } /** * Sets the session cookie parameters. - * The effect of this method only lasts for the duration of the script. - * Call this method before the session starts. + * The cookie parameters passed to this method will be merged with the result + * of `session_get_cookie_params()`. * @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httpOnly`. * @throws InvalidParamException if the parameters are incomplete. * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php */ - public function setCookieParams($value) + public function setCookieParams(array $value) + { + $this->_cookieParams = $value; + } + + /** + * Sets the session cookie parameters. + * This method is called by [[open()]] when it is about to open the session. + * @throws InvalidParamException if the parameters are incomplete. + * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php + */ + private function setCookieParamsInternal() { $data = $this->getCookieParams(); extract($data); - extract($value); if (isset($lifetime, $path, $domain, $secure, $httpOnly)) { session_set_cookie_params($lifetime, $path, $domain, $secure, $httpOnly); } else { - throw new InvalidParamException('Please make sure these parameters are provided: lifetime, path, domain, secure and httpOnly.'); + throw new InvalidParamException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httpOnly.'); } } diff --git a/framework/yii/web/UploadedFile.php b/framework/yii/web/UploadedFile.php index 3cb6813..1de4d46 100644 --- a/framework/yii/web/UploadedFile.php +++ b/framework/yii/web/UploadedFile.php @@ -74,7 +74,7 @@ class UploadedFile extends Object * For example, '[1]file' for tabular file uploading; and 'file[1]' for an element in a file array. * @return UploadedFile the instance of the uploaded file. * Null is returned if no file is uploaded for the specified model attribute. - * @see getInstanceByName + * @see getInstanceByName() */ public static function getInstance($model, $attribute) { diff --git a/framework/yii/web/UrlManager.php b/framework/yii/web/UrlManager.php index c5f4c28..540e8d5 100644 --- a/framework/yii/web/UrlManager.php +++ b/framework/yii/web/UrlManager.php @@ -14,6 +14,22 @@ use yii\caching\Cache; /** * UrlManager handles HTTP request parsing and creation of URLs based on a set of rules. * + * UrlManager is configured as an application component in [[yii\base\Application]] by default. + * You can access that instance via `Yii::$app->urlManager`. + * + * You can modify its configuration by adding an array to your application config under `components` + * as it is shown in the following example: + * + * ~~~ + * 'urlManager' => [ + * 'enablePrettyUrl' => true, + * 'rules' => [ + * // your rules go here + * ], + * // ... + * ] + * ~~~ + * * @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend URLs it creates. * @property string $hostInfo The host info (e.g. "http://www.example.com") that is used by * [[createAbsoluteUrl()]] to prepend URLs it creates. @@ -169,7 +185,7 @@ class UrlManager extends Component { if ($this->enablePrettyUrl) { $pathInfo = $request->getPathInfo(); - /** @var $rule UrlRule */ + /** @var UrlRule $rule */ foreach ($this->rules as $rule) { if (($result = $rule->parseRequest($this, $request)) !== false) { Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__); @@ -224,7 +240,7 @@ class UrlManager extends Component $baseUrl = $this->getBaseUrl(); if ($this->enablePrettyUrl) { - /** @var $rule UrlRule */ + /** @var UrlRule $rule */ foreach ($this->rules as $rule) { if (($url = $rule->createUrl($this, $route, $params)) !== false) { if ($rule->host !== null) { @@ -251,7 +267,7 @@ class UrlManager extends Component if (!empty($params)) { $url .= '&' . http_build_query($params); } - return $url; + return $url . $anchor; } } @@ -282,7 +298,7 @@ class UrlManager extends Component public function getBaseUrl() { if ($this->_baseUrl === null) { - /** @var $request \yii\web\Request */ + /** @var \yii\web\Request $request */ $request = Yii::$app->getRequest(); $this->_baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $request->getScriptUrl() : $request->getBaseUrl(); } diff --git a/framework/yii/web/UrlRule.php b/framework/yii/web/UrlRule.php index 6ebc615..af227cd 100644 --- a/framework/yii/web/UrlRule.php +++ b/framework/yii/web/UrlRule.php @@ -11,7 +11,17 @@ use yii\base\Object; use yii\base\InvalidConfigException; /** - * UrlRule represents a rule used for parsing and generating URLs. + * UrlRule represents a rule used by [[UrlManager]] for parsing and generating URLs. + * + * To define your own URL parsing and creation logic you can extend from this class + * and add it to [[UrlManager::rules]] like this: + * + * ~~~ + * 'rules' => [ + * ['class' => 'MyUrlRule', 'pattern' => '...', 'route' => 'site/index', ...], + * // ... + * ] + * ~~~ * * @author Qiang Xue * @since 2.0 diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php index eca2ed6..682d78e 100644 --- a/framework/yii/web/User.php +++ b/framework/yii/web/User.php @@ -20,6 +20,21 @@ use yii\base\InvalidConfigException; * User works with a class implementing the [[IdentityInterface]]. This class implements * the actual user authentication logic and is often backed by a user database table. * + * User is configured as an application component in [[yii\web\Application]] by default. + * You can access that instance via `Yii::$app->user`. + * + * You can modify its configuration by adding an array to your application config under `components` + * as it is shown in the following example: + * + * ~~~ + * 'user' => [ + * 'identityClass' => 'app\models\User', // User must implement the IdentityInterface + * 'enableAutoLogin' => true, + * // 'loginUrl' => ['user/login'], + * // ... + * ] + * ~~~ + * * @property string|integer $id The unique identifier for the user. If null, it means the user is a guest. * This property is read-only. * @property IdentityInterface $identity The identity object associated with the currently logged user. Null @@ -129,8 +144,8 @@ class User extends Component * Returns the identity object associated with the currently logged user. * @return IdentityInterface the identity object associated with the currently logged user. * Null is returned if the user is not logged in (not authenticated). - * @see login - * @see logout + * @see login() + * @see logout() */ public function getIdentity() { @@ -139,7 +154,7 @@ class User extends Component if ($id === null) { $this->_identity = null; } else { - /** @var $class IdentityInterface */ + /** @var IdentityInterface $class */ $class = $this->identityClass; $this->_identity = $class::findIdentity($id); } @@ -180,6 +195,9 @@ class User extends Component { if ($this->beforeLogin($identity, false)) { $this->switchIdentity($identity, $duration); + $id = $identity->getId(); + $ip = Yii::$app->getRequest()->getUserIP(); + Yii::info("User '$id' logged in from $ip.", __METHOD__); $this->afterLogin($identity, false); } return !$this->getIsGuest(); @@ -199,12 +217,14 @@ class User extends Component $data = json_decode($value, true); if (count($data) === 3 && isset($data[0], $data[1], $data[2])) { list ($id, $authKey, $duration) = $data; - /** @var $class IdentityInterface */ + /** @var IdentityInterface $class */ $class = $this->identityClass; $identity = $class::findIdentity($id); if ($identity !== null && $identity->validateAuthKey($authKey)) { if ($this->beforeLogin($identity, true)) { $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0); + $ip = Yii::$app->getRequest()->getUserIP(); + Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__); $this->afterLogin($identity, true); } } elseif ($identity !== null) { @@ -225,6 +245,9 @@ class User extends Component $identity = $this->getIdentity(); if ($identity !== null && $this->beforeLogout($identity)) { $this->switchIdentity(null); + $id = $identity->getId(); + $ip = Yii::$app->getRequest()->getUserIP(); + Yii::info("User '$id' logged out from $ip.", __METHOD__); if ($destroySession) { Yii::$app->getSession()->destroy(); } @@ -258,7 +281,7 @@ class User extends Component * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to. * Please refer to [[setReturnUrl()]] on accepted format of the URL. * @return string the URL that the user should be redirected to after login. - * @see loginRequired + * @see loginRequired() */ public function getReturnUrl($defaultUrl = null) { @@ -405,7 +428,7 @@ class User extends Component * information in the cookie. * @param IdentityInterface $identity * @param integer $duration number of seconds that the user can remain in logged-in status. - * @see loginByCookie + * @see loginByCookie() */ protected function sendIdentityCookie($identity, $duration) { diff --git a/framework/yii/web/View.php b/framework/yii/web/View.php index ab78fc5..db0c500 100644 --- a/framework/yii/web/View.php +++ b/framework/yii/web/View.php @@ -22,6 +22,22 @@ use yii\base\InvalidConfigException; * * View provides a set of methods (e.g. [[render()]]) for rendering purpose. * + * View is configured as an application component in [[yii\base\Application]] by default. + * You can access that instance via `Yii::$app->view`. + * + * You can modify its configuration by adding an array to your application config under `components` + * as it is shown in the following example: + * + * ~~~ + * 'view' => [ + * 'theme' => 'app\themes\MyTheme', + * 'renderers' => [ + * // you may add Smarty or Twig renderer here + * ] + * // ... + * ] + * ~~~ + * * @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application * component. * @@ -72,7 +88,7 @@ class View extends \yii\base\View /** * @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values * are the registered [[AssetBundle]] objects. - * @see registerAssetBundle + * @see registerAssetBundle() */ public $assetBundles = []; /** @@ -81,32 +97,32 @@ class View extends \yii\base\View public $title; /** * @var array the registered meta tags. - * @see registerMetaTag + * @see registerMetaTag() */ public $metaTags; /** * @var array the registered link tags. - * @see registerLinkTag + * @see registerLinkTag() */ public $linkTags; /** * @var array the registered CSS code blocks. - * @see registerCss + * @see registerCss() */ public $css; /** * @var array the registered CSS files. - * @see registerCssFile + * @see registerCssFile() */ public $cssFiles; /** * @var array the registered JS code blocks - * @see registerJs + * @see registerJs() */ public $js; /** * @var array the registered JS files. - * @see registerJsFile + * @see registerJsFile() */ public $jsFiles; diff --git a/framework/yii/web/XmlResponseFormatter.php b/framework/yii/web/XmlResponseFormatter.php index 05c2762..292424a 100644 --- a/framework/yii/web/XmlResponseFormatter.php +++ b/framework/yii/web/XmlResponseFormatter.php @@ -17,6 +17,8 @@ use yii\helpers\StringHelper; /** * XmlResponseFormatter formats the given data into an XML response content. * + * It is used by [[Response]] to format response data. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/web/YiiAsset.php b/framework/yii/web/YiiAsset.php index e49082d..d38b711 100644 --- a/framework/yii/web/YiiAsset.php +++ b/framework/yii/web/YiiAsset.php @@ -8,6 +8,8 @@ namespace yii\web; /** + * This asset bundle provides the base javascript files for the Yii Framework. + * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/yii/widgets/ActiveForm.php b/framework/yii/widgets/ActiveForm.php index c018011..b218a2e 100644 --- a/framework/yii/widgets/ActiveForm.php +++ b/framework/yii/widgets/ActiveForm.php @@ -220,7 +220,7 @@ class ActiveForm extends Widget $lines = []; foreach ($models as $model) { - /** @var $model Model */ + /** @var Model $model */ foreach ($model->getFirstErrors() as $error) { $lines[] = Html::encode($error); } diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php index 310201a..4c4e5a4 100644 --- a/framework/yii/widgets/BaseListView.php +++ b/framework/yii/widgets/BaseListView.php @@ -53,10 +53,13 @@ abstract class BaseListView extends Widget */ public $summary; /** - * @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data. - * If false, the list view will still be displayed (without body content though). + * @var boolean whether to show the list view if [[dataProvider]] returns no data. */ - public $empty; + public $showOnEmpty = false; + /** + * @var string the HTML content to be displayed when [[dataProvider]] does not have any data. + */ + public $emptyText; /** * @var string the layout that determines how different sections of the list view should be organized. * The following tokens will be replaced with the corresponding section contents: @@ -83,6 +86,9 @@ abstract class BaseListView extends Widget if ($this->dataProvider === null) { throw new InvalidConfigException('The "dataProvider" property must be set.'); } + if ($this->emptyText === null) { + $this->emptyText = Yii::t('yii', 'No results found.'); + } $this->dataProvider->prepare(); } @@ -91,13 +97,13 @@ abstract class BaseListView extends Widget */ public function run() { - if ($this->dataProvider->getCount() > 0 || $this->empty === false) { + if ($this->dataProvider->getCount() > 0 || $this->showOnEmpty) { $content = preg_replace_callback("/{\\w+}/", function ($matches) { $content = $this->renderSection($matches[0]); return $content === false ? $matches[0] : $content; }, $this->layout); } else { - $content = '
' . ($this->empty === null ? Yii::t('yii', 'No results found.') : $this->empty) . '
'; + $content = $this->renderEmpty(); } $tag = ArrayHelper::remove($this->options, 'tag', 'div'); echo Html::tag($tag, $content, $this->options); @@ -126,11 +132,24 @@ abstract class BaseListView extends Widget } /** + * Renders the HTML content indicating that the list view has no data. + * @return string the rendering result + * @see emptyText + */ + public function renderEmpty() + { + return '
' . ($this->emptyText === null ? Yii::t('yii', 'No results found.') : $this->emptyText) . '
'; + } + + /** * Renders the summary text. */ public function renderSummary() { $count = $this->dataProvider->getCount(); + if ($count <= 0) { + return ''; + } if (($pagination = $this->dataProvider->getPagination()) !== false) { $totalCount = $this->dataProvider->getTotalCount(); $begin = $pagination->getPage() * $pagination->pageSize + 1; diff --git a/framework/yii/widgets/Menu.php b/framework/yii/widgets/Menu.php index 7ea7717..d5ff8ef 100644 --- a/framework/yii/widgets/Menu.php +++ b/framework/yii/widgets/Menu.php @@ -104,7 +104,7 @@ class Menu extends Widget /** * @var boolean whether to automatically activate items according to whether their route setting * matches the currently requested route. - * @see isItemActive + * @see isItemActive() */ public $activateItems = true; /** @@ -137,14 +137,14 @@ class Menu extends Widget * @var string the route used to determine if a menu item is active or not. * If not set, it will use the route of the current request. * @see params - * @see isItemActive + * @see isItemActive() */ public $route; /** * @var array the parameters used to determine if a menu item is active or not. * If not set, it will use `$_GET`. * @see route - * @see isItemActive + * @see isItemActive() */ public $params; diff --git a/tests/unit/data/base/Singer.php b/tests/unit/data/base/Singer.php index 5c0f0fe..547cee8 100644 --- a/tests/unit/data/base/Singer.php +++ b/tests/unit/data/base/Singer.php @@ -14,9 +14,9 @@ class Singer extends Model public function rules() { return [ - ['lastName', 'default', 'value' => 'Lennon'], - ['lastName', 'required'], - ['underscore_style', 'yii\captcha\CaptchaValidator'], + [['lastName'], 'default', 'value' => 'Lennon'], + [['lastName'], 'required'], + [['underscore_style'], 'yii\captcha\CaptchaValidator'], ]; } } diff --git a/tests/unit/data/validators/models/FakedValidationModel.php b/tests/unit/data/validators/models/FakedValidationModel.php index 6e9c8b1..e4de44b 100644 --- a/tests/unit/data/validators/models/FakedValidationModel.php +++ b/tests/unit/data/validators/models/FakedValidationModel.php @@ -28,7 +28,7 @@ class FakedValidationModel extends Model public function rules() { return [ - ['val_attr_a, val_attr_b', 'required', 'on' => 'reqTest'], + [['val_attr_a', 'val_attr_b'], 'required', 'on' => 'reqTest'], ['val_attr_c', 'integer'], ]; } @@ -60,4 +60,4 @@ class FakedValidationModel extends Model { return $attr; } -} \ No newline at end of file +} diff --git a/tests/unit/data/views/layout.php b/tests/unit/data/views/layout.php index ed7dc27..97a0888 100644 --- a/tests/unit/data/views/layout.php +++ b/tests/unit/data/views/layout.php @@ -1,7 +1,7 @@ beginPage(); ?> @@ -19,4 +19,4 @@ endBody(); ?> -endPage(); ?> \ No newline at end of file +endPage(); ?> diff --git a/tests/unit/data/views/rawlayout.php b/tests/unit/data/views/rawlayout.php index 68cea54..aaa489f 100644 --- a/tests/unit/data/views/rawlayout.php +++ b/tests/unit/data/views/rawlayout.php @@ -1,5 +1,5 @@ beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?> \ No newline at end of file +?>beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?> diff --git a/tests/unit/extensions/swiftmailer/MailerTest.php b/tests/unit/extensions/swiftmailer/MailerTest.php index 306e128..24602b2 100644 --- a/tests/unit/extensions/swiftmailer/MailerTest.php +++ b/tests/unit/extensions/swiftmailer/MailerTest.php @@ -53,6 +53,8 @@ class MailerTest extends VendorTestCase $transportConfig = [ 'class' => 'Swift_SmtpTransport', 'host' => 'localhost', + 'username' => 'username', + 'password' => 'password', ]; $mailer->setTransport($transportConfig); $transport = $mailer->getTransport(); diff --git a/tests/unit/extensions/swiftmailer/MessageTest.php b/tests/unit/extensions/swiftmailer/MessageTest.php index fdecd88..6309f15 100644 --- a/tests/unit/extensions/swiftmailer/MessageTest.php +++ b/tests/unit/extensions/swiftmailer/MessageTest.php @@ -115,10 +115,48 @@ class MessageTest extends VendorTestCase /** * @depends testGetSwiftMessage */ + public function testSetGet() + { + $message = new Message(); + + $charset = 'utf-16'; + $message->setCharset($charset); + $this->assertEquals($charset, $message->getCharset(), 'Unable to set charset!'); + + $subject = 'Test Subject'; + $message->setSubject($subject); + $this->assertEquals($subject, $message->getSubject(), 'Unable to set subject!'); + + $from = 'from@somedomain.com'; + $message->setFrom($from); + $this->assertContains($from, array_keys($message->getFrom()), 'Unable to set from!'); + + $replyTo = 'reply-to@somedomain.com'; + $message->setReplyTo($replyTo); + $this->assertContains($replyTo, array_keys($message->getReplyTo()), 'Unable to set replyTo!'); + + $to = 'someuser@somedomain.com'; + $message->setTo($to); + $this->assertContains($to, array_keys($message->getTo()), 'Unable to set to!'); + + $cc = 'ccuser@somedomain.com'; + $message->setCc($cc); + $this->assertContains($cc, array_keys($message->getCc()), 'Unable to set cc!'); + + $bcc = 'bccuser@somedomain.com'; + $message->setBcc($bcc); + $this->assertContains($bcc, array_keys($message->getBcc()), 'Unable to set bcc!'); + } + + /** + * @depends testGetSwiftMessage + */ public function testSetupHeaders() { $charset = 'utf-16'; $subject = 'Test Subject'; + $from = 'from@somedomain.com'; + $replyTo = 'reply-to@somedomain.com'; $to = 'someuser@somedomain.com'; $cc = 'ccuser@somedomain.com'; $bcc = 'bccuser@somedomain.com'; @@ -126,6 +164,8 @@ class MessageTest extends VendorTestCase $messageString = $this->createTestMessage() ->setCharset($charset) ->setSubject($subject) + ->setFrom($from) + ->setReplyTo($replyTo) ->setTo($to) ->setCc($cc) ->setBcc($bcc) @@ -133,6 +173,8 @@ class MessageTest extends VendorTestCase $this->assertContains('charset=' . $charset, $messageString, 'Incorrect charset!'); $this->assertContains('Subject: ' . $subject, $messageString, 'Incorrect "Subject" header!'); + $this->assertContains('From: ' . $from, $messageString, 'Incorrect "From" header!'); + $this->assertContains('Reply-To: ' . $replyTo, $messageString, 'Incorrect "Reply-To" header!'); $this->assertContains('To: ' . $to, $messageString, 'Incorrect "To" header!'); $this->assertContains('Cc: ' . $cc, $messageString, 'Incorrect "Cc" header!'); $this->assertContains('Bcc: ' . $bcc, $messageString, 'Incorrect "Bcc" header!'); @@ -141,19 +183,6 @@ class MessageTest extends VendorTestCase /** * @depends testGetSwiftMessage */ - public function testSetupFrom() - { - $from = 'someuser@somedomain.com'; - $messageString = $this->createTestMessage() - ->setFrom($from) - ->toString(); - $this->assertContains('From: ' . $from, $messageString, 'Incorrect "From" header!'); - $this->assertContains('Reply-To: ' . $from, $messageString, 'Incorrect "Reply-To" header!'); - } - - /** - * @depends testGetSwiftMessage - */ public function testSend() { $message = $this->createTestMessage(); @@ -277,7 +306,7 @@ class MessageTest extends VendorTestCase $htmlPresent = false; foreach ($messageParts as $part) { if (!($part instanceof \Swift_Mime_Attachment)) { - /* @var $part \Swift_Mime_MimePart */ + /* @var \Swift_Mime_MimePart $part */ if ($part->getContentType() == 'text/plain') { $textPresent = true; } diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php index 3b445e0..4e4ca77 100644 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ b/tests/unit/framework/data/ActiveDataProviderTest.php @@ -10,6 +10,8 @@ namespace yiiunit\framework\data; use yii\data\ActiveDataProvider; use yii\db\Query; use yiiunit\data\ar\ActiveRecord; +use yiiunit\data\ar\Customer; +use yiiunit\data\ar\Item; use yiiunit\framework\db\DatabaseTestCase; use yiiunit\data\ar\Order; @@ -18,6 +20,7 @@ use yiiunit\data\ar\Order; * @since 2.0 * * @group data + * @group db */ class ActiveDataProviderTest extends DatabaseTestCase { @@ -35,6 +38,8 @@ class ActiveDataProviderTest extends DatabaseTestCase $orders = $provider->getModels(); $this->assertEquals(3, count($orders)); $this->assertTrue($orders[0] instanceof Order); + $this->assertTrue($orders[1] instanceof Order); + $this->assertTrue($orders[2] instanceof Order); $this->assertEquals([1, 2, 3], $provider->getKeys()); $provider = new ActiveDataProvider([ @@ -47,6 +52,75 @@ class ActiveDataProviderTest extends DatabaseTestCase $this->assertEquals(2, count($orders)); } + public function testActiveRelation() + { + /** @var Customer $customer */ + $customer = Customer::find(2); + $provider = new ActiveDataProvider([ + 'query' => $customer->getOrders(), + ]); + $orders = $provider->getModels(); + $this->assertEquals(2, count($orders)); + $this->assertTrue($orders[0] instanceof Order); + $this->assertTrue($orders[1] instanceof Order); + $this->assertEquals([2, 3], $provider->getKeys()); + + $provider = new ActiveDataProvider([ + 'query' => $customer->getOrders(), + 'pagination' => [ + 'pageSize' => 1, + ] + ]); + $orders = $provider->getModels(); + $this->assertEquals(1, count($orders)); + } + + public function testActiveRelationVia() + { + /** @var Order $order */ + $order = Order::find(2); + $provider = new ActiveDataProvider([ + 'query' => $order->getItems(), + ]); + $items = $provider->getModels(); + $this->assertEquals(3, count($items)); + $this->assertTrue($items[0] instanceof Item); + $this->assertTrue($items[1] instanceof Item); + $this->assertTrue($items[2] instanceof Item); + $this->assertEquals([3, 4, 5], $provider->getKeys()); + + $provider = new ActiveDataProvider([ + 'query' => $order->getItems(), + 'pagination' => [ + 'pageSize' => 2, + ] + ]); + $items = $provider->getModels(); + $this->assertEquals(2, count($items)); + } + + public function testActiveRelationViaTable() + { + /** @var Order $order */ + $order = Order::find(1); + $provider = new ActiveDataProvider([ + 'query' => $order->getBooks(), + ]); + $items = $provider->getModels(); + $this->assertEquals(2, count($items)); + $this->assertTrue($items[0] instanceof Item); + $this->assertTrue($items[1] instanceof Item); + + $provider = new ActiveDataProvider([ + 'query' => $order->getBooks(), + 'pagination' => [ + 'pageSize' => 1, + ] + ]); + $items = $provider->getModels(); + $this->assertEquals(1, count($items)); + } + public function testQuery() { $query = new Query; diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php index a86c084..f96f2d3 100644 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ b/tests/unit/framework/db/ActiveRecordTest.php @@ -117,12 +117,21 @@ class ActiveRecordTest extends DatabaseTestCase public function testFindLazy() { - /** @var $customer Customer */ + /** @var Customer $customer */ $customer = Customer::find(2); + $this->assertFalse($customer->isRelationPopulated('orders')); $orders = $customer->orders; + $this->assertTrue($customer->isRelationPopulated('orders')); $this->assertEquals(2, count($orders)); + $this->assertEquals(1, count($customer->populatedRelations)); + /** @var Customer $customer */ + $customer = Customer::find(2); + $this->assertFalse($customer->isRelationPopulated('orders')); $orders = $customer->getOrders()->where('id=3')->all(); + $this->assertFalse($customer->isRelationPopulated('orders')); + $this->assertEquals(0, count($customer->populatedRelations)); + $this->assertEquals(1, count($orders)); $this->assertEquals(3, $orders[0]->id); } @@ -131,13 +140,20 @@ class ActiveRecordTest extends DatabaseTestCase { $customers = Customer::find()->with('orders')->all(); $this->assertEquals(3, count($customers)); + $this->assertTrue($customers[0]->isRelationPopulated('orders')); + $this->assertTrue($customers[1]->isRelationPopulated('orders')); $this->assertEquals(1, count($customers[0]->orders)); $this->assertEquals(2, count($customers[1]->orders)); + + $customer = Customer::find()->with('orders')->one(); + $this->assertTrue($customer->isRelationPopulated('orders')); + $this->assertEquals(1, count($customer->orders)); + $this->assertEquals(1, count($customer->populatedRelations)); } public function testFindLazyVia() { - /** @var $order Order */ + /** @var Order $order */ $order = Order::find(1); $this->assertEquals(1, $order->id); $this->assertEquals(2, count($order->items)); @@ -162,7 +178,7 @@ class ActiveRecordTest extends DatabaseTestCase public function testFindLazyViaTable() { - /** @var $order Order */ + /** @var Order $order */ $order = Order::find(1); $this->assertEquals(1, $order->id); $this->assertEquals(2, count($order->books)); diff --git a/tests/unit/framework/db/QueryTest.php b/tests/unit/framework/db/QueryTest.php index a48d719..77c1ac0 100644 --- a/tests/unit/framework/db/QueryTest.php +++ b/tests/unit/framework/db/QueryTest.php @@ -86,19 +86,19 @@ class QueryTest extends DatabaseTestCase { $query = new Query; $query->orderBy('team'); - $this->assertEquals(['team' => false], $query->orderBy); + $this->assertEquals(['team' => SORT_ASC], $query->orderBy); $query->addOrderBy('company'); - $this->assertEquals(['team' => false, 'company' => false], $query->orderBy); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); $query->addOrderBy('age'); - $this->assertEquals(['team' => false, 'company' => false, 'age' => false], $query->orderBy); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - $query->addOrderBy(['age' => true]); - $this->assertEquals(['team' => false, 'company' => false, 'age' => true], $query->orderBy); + $query->addOrderBy(['age' => SORT_DESC]); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => false, 'company' => true, 'age' => false], $query->orderBy); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); } public function testLimitOffset() diff --git a/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php b/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php new file mode 100644 index 0000000..191442a --- /dev/null +++ b/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php @@ -0,0 +1,14 @@ +assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html by direct view!'); $this->assertEquals(strip_tags($htmlViewFileContent), $message->_textBody, 'Unable to render text by direct view!'); } + + public function testUseFileTransport() + { + $mailer = new Mailer(); + $this->assertFalse($mailer->useFileTransport); + $this->assertEquals('@runtime/mail', $mailer->fileTransportPath); + + $mailer->fileTransportPath = '@yiiunit/runtime/mail'; + $mailer->useFileTransport = true; + $mailer->fileTransportCallback = function () { + return 'message.txt'; + }; + $message = $mailer->compose() + ->setTo('to@example.com') + ->setFrom('from@example.com') + ->setSubject('test subject') + ->setTextBody('text body' . microtime(true)); + $this->assertTrue($mailer->send($message)); + $file = Yii::getAlias($mailer->fileTransportPath) . '/message.txt'; + $this->assertTrue(is_file($file)); + $this->assertEquals($message->toString(), file_get_contents($file)); + } } /** @@ -218,7 +240,7 @@ class Mailer extends BaseMailer public $messageClass = 'yiiunit\framework\mail\Message'; public $sentMessages = []; - public function send($message) + protected function sendMessage($message) { $this->sentMessages[] = $message; } @@ -340,6 +362,6 @@ class Message extends BaseMessage public function toString() { - return get_class($this); + return var_export($this, true); } } diff --git a/tests/unit/framework/mail/BaseMessageTest.php b/tests/unit/framework/mail/BaseMessageTest.php index 0ffedf3..d80d4f7 100644 --- a/tests/unit/framework/mail/BaseMessageTest.php +++ b/tests/unit/framework/mail/BaseMessageTest.php @@ -71,7 +71,7 @@ class TestMailer extends BaseMailer public $messageClass = 'yiiunit\framework\mail\TestMessage'; public $sentMessages = array(); - public function send($message) + protected function sendMessage($message) { $this->sentMessages[] = $message; } diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php index fc69c2f..5e5385b 100644 --- a/tests/unit/framework/validators/ValidatorTest.php +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -30,7 +30,7 @@ class ValidatorTest extends TestCase public function testCreateValidator() { $model = FakedValidationModel::createWithAttributes(['attr_test1' => 'abc', 'attr_test2' => '2013']); - /** @var $numberVal NumberValidator */ + /** @var NumberValidator $numberVal */ $numberVal = TestValidator::createValidator('number', $model, ['attr_test1']); $this->assertInstanceOf(NumberValidator::className(), $numberVal); $numberVal = TestValidator::createValidator('integer', $model, ['attr_test2']); @@ -39,7 +39,7 @@ class ValidatorTest extends TestCase $val = TestValidator::createValidator( 'boolean', $model, - 'attr_test1, attr_test2', + ['attr_test1', 'attr_test2'], ['on' => ['a', 'b']] ); $this->assertInstanceOf(BooleanValidator::className(), $val); @@ -48,13 +48,13 @@ class ValidatorTest extends TestCase $val = TestValidator::createValidator( 'boolean', $model, - 'attr_test1, attr_test2', - ['on' => 'a, b', 'except' => 'c,d,e'] + ['attr_test1', 'attr_test2'], + ['on' => ['a', 'b'], 'except' => ['c', 'd', 'e']] ); $this->assertInstanceOf(BooleanValidator::className(), $val); $this->assertSame(['a', 'b'], $val->on); $this->assertSame(['c', 'd', 'e'], $val->except); - $val = TestValidator::createValidator('inlineVal', $model, 'val_attr_a'); + $val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a']); $this->assertInstanceOf(InlineValidator::className(), $val); $this->assertSame('inlineVal', $val->method); } @@ -229,4 +229,4 @@ class ValidatorTest extends TestCase $errors = $m->getErrors('attr_msg_val'); $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); } -} \ No newline at end of file +}