Commit 0e31bb8c by RichWeber

Merge branch 'master' of github.com:yiisoft/yii2

parents d5bd6816 b927d36f
...@@ -30,7 +30,7 @@ install: ...@@ -30,7 +30,7 @@ install:
- tests/unit/data/travis/memcache-setup.sh - tests/unit/data/travis/memcache-setup.sh
- tests/unit/data/travis/cubrid-setup.sh - tests/unit/data/travis/cubrid-setup.sh
# basic and advanced application: # basic and advanced application:
# - tests/unit/data/travis/setup-apps.sh - tests/unit/data/travis/setup-apps.sh
before_script: before_script:
- echo 'elasticsearch version ' && curl http://localhost:9200/ - echo 'elasticsearch version ' && curl http://localhost:9200/
...@@ -39,16 +39,16 @@ before_script: ...@@ -39,16 +39,16 @@ before_script:
- tests/unit/data/travis/sphinx-setup.sh - tests/unit/data/travis/sphinx-setup.sh
- mongo yii2test --eval 'db.addUser("travis", "test");' - mongo yii2test --eval 'db.addUser("travis", "test");'
# basic and advanced application: # basic and advanced application:
# - tests/unit/data/travis/init-apps.sh - tests/unit/data/travis/init-apps.sh
script: script:
- vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group mssql,oci,wincache,xcache,zenddata - vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group mssql,oci,wincache,xcache,zenddata
# - cd apps/basic && php vendor/bin/codecept run - cd apps/basic && php vendor/bin/codecept run
# - cd ../advanced/backend && ../vendor/bin/codecept run - cd ../advanced/backend && ../vendor/bin/codecept run
# - cd ../common && ../vendor/bin/codecept run - cd ../common && ../vendor/bin/codecept run
# - cd ../frontend && ../vendor/bin/codecept run - cd ../frontend && ../vendor/bin/codecept run
after_script: after_script:
# - cd ../../.. - cd ../../..
- wget https://scrutinizer-ci.com/ocular.phar - wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
...@@ -112,7 +112,7 @@ if you are starting from `frontend` tests then you should run `yii migrate` in e ...@@ -112,7 +112,7 @@ if you are starting from `frontend` tests then you should run `yii migrate` in e
it will upgrade your database to the last state according migrations. it will upgrade your database to the last state according migrations.
To be able to run acceptance tests you need a running webserver. For this you can use the php builtin server and run it in the directory where your main project folder is located. For example if your application is located in `/www/advanced` all you need to is: To be able to run acceptance tests you need a running webserver. For this you can use the php builtin server and run it in the directory where your main project folder is located. For example if your application is located in `/www/advanced` all you need to is:
`cd /www` and then `php -S 127.0.0.1:8080 index-test.php` because the default configuration of acceptance tests expects the url of the application to be `/advanced/`. `cd /www` and then `php -S 127.0.0.1:8080` because the default configuration of acceptance tests expects the url of the application to be `/advanced/`.
If you already have a server configured or your application is not located in a folder called `advanced`, you may need to adjust the `TEST_ENTRY_URL` in `frontend/tests/_bootstrap.php` and `backend/tests/_bootstrap.php`. If you already have a server configured or your application is not located in a folder called `advanced`, you may need to adjust the `TEST_ENTRY_URL` in `frontend/tests/_bootstrap.php` and `backend/tests/_bootstrap.php`.
After that is done you should be able to run your tests, for example to run `frontend` tests do: After that is done you should be able to run your tests, for example to run `frontend` tests do:
......
...@@ -355,7 +355,7 @@ si tu no la usarás en tu código. ...@@ -355,7 +355,7 @@ si tu no la usarás en tu código.
### Propiedades Útiles <a name="useful-properties"></a> ### Propiedades Útiles <a name="useful-properties"></a>
Las propiedades especificadas en esta sub-sección are no son configuradas normalmente ya que sus valores por defecto Las propiedades especificadas en esta sub-sección no son configuradas normalmente ya que sus valores por defecto
estipulan convenciones comunes. De cualquier modo, aún puedes configurarlas en caso de que quieras romper con la convención. estipulan convenciones comunes. De cualquier modo, aún puedes configurarlas en caso de que quieras romper con la convención.
......
...@@ -396,10 +396,10 @@ In Yii in order to build it you can first form two query objects and then use `u ...@@ -396,10 +396,10 @@ In Yii in order to build it you can first form two query objects and then use `u
```php ```php
$query = new Query(); $query = new Query();
$query->select("id, 'post' as type, name")->from('post')->limit(10); $query->select("id, category_id as type, name")->from('post')->limit(10);
$anotherQuery = new Query(); $anotherQuery = new Query();
$anotherQuery->select('id, 'user' as type, name')->from('user')->limit(10); $anotherQuery->select('id, type, name')->from('user')->limit(10);
$query->union($anotherQuery); $query->union($anotherQuery);
``` ```
......
...@@ -316,7 +316,7 @@ to end users. ...@@ -316,7 +316,7 @@ to end users.
* For [[yii\web\Application|Web applications]], the return value can also be some arbitrary data which will * For [[yii\web\Application|Web applications]], the return value can also be some arbitrary data which will
be assigned to [[yii\web\Response::data]] and be further converted into a string representing the response body. be assigned to [[yii\web\Response::data]] and be further converted into a string representing the response body.
* For [[yii\console\Application|console applications], the return value can also be an integer representing * For [[yii\console\Application|console applications]], the return value can also be an integer representing
the [[yii\console\Response::exitStatus|exit status]] of the command execution. the [[yii\console\Response::exitStatus|exit status]] of the command execution.
In the examples shown above, the action results are all strings which will be treated as the response body In the examples shown above, the action results are all strings which will be treated as the response body
......
...@@ -93,7 +93,7 @@ You can get the label of an attribute by calling [[yii\base\Model::getAttributeL ...@@ -93,7 +93,7 @@ You can get the label of an attribute by calling [[yii\base\Model::getAttributeL
```php ```php
$model = new \app\models\ContactForm; $model = new \app\models\ContactForm;
// displays "Label" // displays "Name"
echo $model->getAttributeLabel('name'); echo $model->getAttributeLabel('name');
``` ```
...@@ -500,7 +500,7 @@ you may take the following strategy: ...@@ -500,7 +500,7 @@ you may take the following strategy:
[modules](structure-modules.md). These model classes should contain minimal sets of rules and logic that [modules](structure-modules.md). These model classes should contain minimal sets of rules and logic that
are common among all their usages. are common among all their usages.
* In each [application](structure-applications.md) or [module](structure-modules.md) that uses a model, * In each [application](structure-applications.md) or [module](structure-modules.md) that uses a model,
define a crete model class by extending from the corresponding base model class. The concrete model classes define a concrete model class by extending from the corresponding base model class. The concrete model classes
should contain rules and logic that are specific for that application or module. should contain rules and logic that are specific for that application or module.
For example, in the [Advanced Application Template](tutorial-advanced-app.md), you may define a base model For example, in the [Advanced Application Template](tutorial-advanced-app.md), you may define a base model
......
...@@ -361,10 +361,10 @@ the places where these methods are called. ...@@ -361,10 +361,10 @@ the places where these methods are called.
- [[yii\web\View::head()|head()]]: This method should be called within the `<head>` section of an HTML page. - [[yii\web\View::head()|head()]]: This method should be called within the `<head>` section of an HTML page.
It generates a placeholder which will be replaced with the registered head HTML code (e.g. link tags, meta tags) It generates a placeholder which will be replaced with the registered head HTML code (e.g. link tags, meta tags)
when a page finishes rendering. when a page finishes rendering.
- [[yii\base\View::beginBody()|beginBody()]]: This method should be called at the beginning of the `<body>` section. - [[yii\web\View::beginBody()|beginBody()]]: This method should be called at the beginning of the `<body>` section.
It triggers the [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] event and generates a placeholder which will It triggers the [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] event and generates a placeholder which will
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body begin position. be replaced by the registered HTML code (e.g. JavaScript) targeted at the body begin position.
- [[yii\base\View::endBody()|endBody()]]: This method should be called at the end of the `<body>` section. - [[yii\web\View::endBody()|endBody()]]: This method should be called at the end of the `<body>` section.
It triggers the [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] event and generates a placeholder which will It triggers the [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] event and generates a placeholder which will
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body end position. be replaced by the registered HTML code (e.g. JavaScript) targeted at the body end position.
......
...@@ -187,7 +187,7 @@ if (YII_ENV_DEV) { ...@@ -187,7 +187,7 @@ if (YII_ENV_DEV) {
'crud' => [ //name generator 'crud' => [ //name generator
'class' => 'yii\gii\generators\crud\Generator', //class generator 'class' => 'yii\gii\generators\crud\Generator', //class generator
'templates' => [ //setting for out templates 'templates' => [ //setting for out templates
'myCrud' => '@app\myTemplates\crud\default', //name template => path to template 'myCrud' => '@app/myTemplates/crud/default', //name template => path to template
] ]
] ]
], ],
......
...@@ -65,7 +65,7 @@ webserver: ...@@ -65,7 +65,7 @@ webserver:
``` ```
cd apps/advanced/frontend/www cd apps/advanced/frontend/www
php -S 127.0.0.1:8080 index-test.php php -S 127.0.0.1:8080
``` ```
Note that you should have Codeception and PHPUnit installed globally: Note that you should have Codeception and PHPUnit installed globally:
......
...@@ -55,7 +55,7 @@ class Alert extends Widget ...@@ -55,7 +55,7 @@ class Alert extends Widget
/** /**
* @var array the options for rendering the close button tag. * @var array the options for rendering the close button tag.
* The close button is displayed in the header of the modal window. Clicking * The close button is displayed in the header of the modal window. Clicking
* on the button will hide the modal window. If this is null, no close button will be rendered. * on the button will hide the modal window. If this is false, no close button will be rendered.
* *
* The following special options are supported: * The following special options are supported:
* *
...@@ -117,7 +117,7 @@ class Alert extends Widget ...@@ -117,7 +117,7 @@ class Alert extends Widget
*/ */
protected function renderCloseButton() protected function renderCloseButton()
{ {
if ($this->closeButton !== null) { if ($this->closeButton !== false) {
$tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button');
$label = ArrayHelper::remove($this->closeButton, 'label', '&times;'); $label = ArrayHelper::remove($this->closeButton, 'label', '&times;');
if ($tag === 'button' && !isset($this->closeButton['type'])) { if ($tag === 'button' && !isset($this->closeButton['type'])) {
......
...@@ -8,9 +8,15 @@ Yii Framework 2 bootstrap extension Change Log ...@@ -8,9 +8,15 @@ Yii Framework 2 bootstrap extension Change Log
- Bug #3740: Fixed duplicate error message when client validation is enabled (tadaszelvys) - Bug #3740: Fixed duplicate error message when client validation is enabled (tadaszelvys)
- Bug #3749: Fixed invalid plugin registration and ensure clickable links in dropdown (kartik-v) - Bug #3749: Fixed invalid plugin registration and ensure clickable links in dropdown (kartik-v)
- Enh #4024: Added ability to `yii\bootstrap\Tabs` to encode each `Tabs::items['label']` separately (creocoder, umneeq) - Enh #4024: Added ability to `yii\bootstrap\Tabs` to encode each `Tabs::items['label']` separately (creocoder, umneeq)
- Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue)
- Enh #4120: Added ability for each item to choose it's encoding option in `Dropdown` and `Nav` (Alex-Code) - Enh #4120: Added ability for each item to choose it's encoding option in `Dropdown` and `Nav` (Alex-Code)
- Enh #4363: Added `showIndicators` property to make Carousel indicators optional (sdkiller) - Enh #4363: Added `showIndicators` property to make Carousel indicators optional (sdkiller)
- Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue)
- Chg #4595: The following properties are now taking `false` instead of `null` for "don't use" case (samdark)
- `yii\bootstrap\NavBar::$brandLabel`.
- `yii\bootstrap\NavBar::$brandUrl`.
- `yii\bootstrap\Modal::$closeButton`.
- `yii\bootstrap\Modal::$toggleButton`.
- `yii\bootstrap\Alert::$closeButton`.
2.0.0-beta April 13, 2014 2.0.0-beta April 13, 2014
------------------------- -------------------------
......
...@@ -52,9 +52,9 @@ class Modal extends Widget ...@@ -52,9 +52,9 @@ class Modal extends Widget
*/ */
public $size; public $size;
/** /**
* @var array the options for rendering the close button tag. * @var array|false the options for rendering the close button tag.
* The close button is displayed in the header of the modal window. Clicking * The close button is displayed in the header of the modal window. Clicking
* on the button will hide the modal window. If this is null, no close button will be rendered. * on the button will hide the modal window. If this is false, no close button will be rendered.
* *
* The following special options are supported: * The following special options are supported:
* *
...@@ -69,7 +69,7 @@ class Modal extends Widget ...@@ -69,7 +69,7 @@ class Modal extends Widget
/** /**
* @var array the options for rendering the toggle button tag. * @var array the options for rendering the toggle button tag.
* The toggle button is used to toggle the visibility of the modal window. * The toggle button is used to toggle the visibility of the modal window.
* If this property is null, no toggle button will be rendered. * If this property is false, no toggle button will be rendered.
* *
* The following special options are supported: * The following special options are supported:
* *
...@@ -80,7 +80,7 @@ class Modal extends Widget ...@@ -80,7 +80,7 @@ class Modal extends Widget
* Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals) * Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals)
* for the supported HTML attributes. * for the supported HTML attributes.
*/ */
public $toggleButton; public $toggleButton = false;
/** /**
...@@ -187,7 +187,7 @@ class Modal extends Widget ...@@ -187,7 +187,7 @@ class Modal extends Widget
*/ */
protected function renderCloseButton() protected function renderCloseButton()
{ {
if ($this->closeButton !== null) { if ($this->closeButton !== false) {
$tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button');
$label = ArrayHelper::remove($this->closeButton, 'label', '&times;'); $label = ArrayHelper::remove($this->closeButton, 'label', '&times;');
if ($tag === 'button' && !isset($this->closeButton['type'])) { if ($tag === 'button' && !isset($this->closeButton['type'])) {
...@@ -217,7 +217,7 @@ class Modal extends Widget ...@@ -217,7 +217,7 @@ class Modal extends Widget
$this->clientOptions = array_merge(['show' => false], $this->clientOptions); $this->clientOptions = array_merge(['show' => false], $this->clientOptions);
} }
if ($this->closeButton !== null) { if ($this->closeButton !== false) {
$this->closeButton = array_merge([ $this->closeButton = array_merge([
'data-dismiss' => 'modal', 'data-dismiss' => 'modal',
'aria-hidden' => 'true', 'aria-hidden' => 'true',
...@@ -225,7 +225,7 @@ class Modal extends Widget ...@@ -225,7 +225,7 @@ class Modal extends Widget
], $this->closeButton); ], $this->closeButton);
} }
if ($this->toggleButton !== null) { if ($this->toggleButton !== false) {
$this->toggleButton = array_merge([ $this->toggleButton = array_merge([
'data-toggle' => 'modal', 'data-toggle' => 'modal',
], $this->toggleButton); ], $this->toggleButton);
......
...@@ -56,15 +56,16 @@ class NavBar extends Widget ...@@ -56,15 +56,16 @@ class NavBar extends Widget
*/ */
public $containerOptions = []; public $containerOptions = [];
/** /**
* @var string the text of the brand. Note that this is not HTML-encoded. * @var string|boolean the text of the brand of false if it's not used. Note that this is not HTML-encoded.
* @see http://getbootstrap.com/components/#navbar * @see http://getbootstrap.com/components/#navbar
*/ */
public $brandLabel; public $brandLabel = false;
/** /**
* @param array|string $url the URL for the brand's hyperlink tag. This parameter will be processed by [[Url::to()]] * @param array|string|boolean $url the URL for the brand's hyperlink tag. This parameter will be processed by [[Url::to()]]
* and will be used for the "href" attribute of the brand link. If not set, [[\yii\web\Application::homeUrl]] will be used. * and will be used for the "href" attribute of the brand link. Default value is false that means
* [[\yii\web\Application::homeUrl]] will be used.
*/ */
public $brandUrl; public $brandUrl = false;
/** /**
* @var array the HTML attributes of the brand link. * @var array the HTML attributes of the brand link.
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
...@@ -115,9 +116,9 @@ class NavBar extends Widget ...@@ -115,9 +116,9 @@ class NavBar extends Widget
$this->containerOptions['id'] = "{$this->options['id']}-collapse"; $this->containerOptions['id'] = "{$this->options['id']}-collapse";
} }
echo $this->renderToggleButton(); echo $this->renderToggleButton();
if ($this->brandLabel !== null) { if ($this->brandLabel !== false) {
Html::addCssClass($this->brandOptions, 'navbar-brand'); Html::addCssClass($this->brandOptions, 'navbar-brand');
echo Html::a($this->brandLabel, $this->brandUrl === null ? Yii::$app->homeUrl : $this->brandUrl, $this->brandOptions); echo Html::a($this->brandLabel, $this->brandUrl === false ? Yii::$app->homeUrl : $this->brandUrl, $this->brandOptions);
} }
echo Html::endTag('div'); echo Html::endTag('div');
Html::addCssClass($this->containerOptions, 'collapse'); Html::addCssClass($this->containerOptions, 'collapse');
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\console\Exception; use yii\console\Exception;
use yii\helpers\Console; use yii\helpers\Console;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yii\helpers\VarDumper;
/** /**
* This command manage fixtures creations based on given template. * This command manage fixtures creations based on given template.
...@@ -316,22 +317,7 @@ class FixtureController extends \yii\console\controllers\FixtureController ...@@ -316,22 +317,7 @@ class FixtureController extends \yii\console\controllers\FixtureController
*/ */
public function exportFixtures($fixtures) public function exportFixtures($fixtures)
{ {
$content = "<?php\n\nreturn ["; return "<?php\n\nreturn " . VarDumper::export($fixtures) . ";\n";
foreach ($fixtures as $fixture) {
$content .= "\n\t[";
foreach ($fixture as $name => $value) {
$content .= "\n\t\t'{$name}' => '{$value}',";
}
$content .= "\n\t],";
}
$content .= "\n];\n";
return $content;
} }
/** /**
......
...@@ -7,6 +7,7 @@ Yii Framework 2 twig extension Change Log ...@@ -7,6 +7,7 @@ Yii Framework 2 twig extension Change Log
- Bug #2925: Fixed throwing exception when accessing AR property with null value (samdark) - Bug #2925: Fixed throwing exception when accessing AR property with null value (samdark)
- Bug #3767: Fixed repeated adding of extensions when using config. One may now pass extension instances as well (grachov) - Bug #3767: Fixed repeated adding of extensions when using config. One may now pass extension instances as well (grachov)
- Bug #3877: Fixed `lexerOptions` throwing exception (dapatrese) - Bug #3877: Fixed `lexerOptions` throwing exception (dapatrese)
- Bug #4290: Fixed throwing exception when trying to access AR relation that is null (samdark, tenitski)
- Enh #1799: Added `form_begin`, `form_end` to twig extension (samdark) - Enh #1799: Added `form_begin`, `form_end` to twig extension (samdark)
- Enh #3674: Various enhancements (samdark) - Enh #3674: Various enhancements (samdark)
- Removed `FileLoader` and used `\Twig_Loader_Filesystem` instead. - Removed `FileLoader` and used `\Twig_Loader_Filesystem` instead.
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\twig;
/**
* Template base class
*
* @author Alexei Tenitski <alexei@ten.net.nz>
*/
abstract class Template extends \Twig_Template
{
/**
* @inheritdoc
*/
protected function getAttribute($object, $item, array $arguments = [], $type = \Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
{
// Twig uses isset() to check if attribute exists which does not work when attribute exists but is null
if ($object instanceof \yii\db\BaseActiveRecord) {
if ($type === \Twig_Template::METHOD_CALL) {
return $object->$item();
} else {
return $object->$item;
}
}
return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
}
}
...@@ -98,6 +98,8 @@ class ViewRenderer extends BaseViewRenderer ...@@ -98,6 +98,8 @@ class ViewRenderer extends BaseViewRenderer
'charset' => Yii::$app->charset, 'charset' => Yii::$app->charset,
], $this->options)); ], $this->options));
$this->twig->setBaseTemplateClass('yii\twig\Template');
// Adding custom globals (objects or static classes) // Adding custom globals (objects or static classes)
if (!empty($this->globals)) { if (!empty($this->globals)) {
$this->addGlobals($this->globals); $this->addGlobals($this->globals);
......
...@@ -78,6 +78,7 @@ Yii Framework 2 Change Log ...@@ -78,6 +78,7 @@ Yii Framework 2 Change Log
- Bug #4497: Fixed StringHelper::byteSubstr() returning empty string on null $length param (mbman) - Bug #4497: Fixed StringHelper::byteSubstr() returning empty string on null $length param (mbman)
- Bug #4514: Fixed Request class crashing when empty CSRF token value is sent in cookie (cebe) - Bug #4514: Fixed Request class crashing when empty CSRF token value is sent in cookie (cebe)
- Bug #4519: `yii\base\Model::isAttributeRequired()` should check if the `when` option of the validator is set (thiagotalma) - Bug #4519: `yii\base\Model::isAttributeRequired()` should check if the `when` option of the validator is set (thiagotalma)
- Bug #4592: Fixed `yii help` command was listing incorrect action names for methods like `actionSayNO` (samdark)
- Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark) - Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark)
- Bug: URL encoding for the route parameter added to `\yii\web\UrlManager` (klimov-paul) - Bug: URL encoding for the route parameter added to `\yii\web\UrlManager` (klimov-paul)
- Bug: Fixed the bug that requesting protected or private action methods would cause 500 error instead of 404 (qiangxue) - Bug: Fixed the bug that requesting protected or private action methods would cause 500 error instead of 404 (qiangxue)
...@@ -168,7 +169,10 @@ Yii Framework 2 Change Log ...@@ -168,7 +169,10 @@ Yii Framework 2 Change Log
- Enh #4436: Added callback functions to AJAX-based form validation (thiagotalma) - Enh #4436: Added callback functions to AJAX-based form validation (thiagotalma)
- Enh #4485: Added support for deferred validation in `ActiveForm` (Alex-Code) - Enh #4485: Added support for deferred validation in `ActiveForm` (Alex-Code)
- Enh #4520: Added sasl support to `yii\caching\MemCache` (xjflyttp) - Enh #4520: Added sasl support to `yii\caching\MemCache` (xjflyttp)
- Enh #4559: Added `beforeValidateAll` and `afterValidateAll` callbacks to `ActiveForm` (Alex-Code)
- Enh #4566: Added client validation support for image validator (Skysplit, qiangxue) - Enh #4566: Added client validation support for image validator (Skysplit, qiangxue)
- Enh #4581: Added ability to disable url encoding in `UrlRule` (tadaszelvys)
- Enh #4602: Added $key param in ActionColumn buttons Closure call (disem)
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue) - Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue) - Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue) - Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
...@@ -214,6 +218,8 @@ Yii Framework 2 Change Log ...@@ -214,6 +218,8 @@ Yii Framework 2 Change Log
- Chg #4310: Removed `$data` from signature of `yii\rbac\ManagerInterface` (samdark) - Chg #4310: Removed `$data` from signature of `yii\rbac\ManagerInterface` (samdark)
- Chg #4318: `yii\helpers\Html::ul()` and `ol()` will return an empty list tag if an empty item array is given (qiangxue) - Chg #4318: `yii\helpers\Html::ul()` and `ol()` will return an empty list tag if an empty item array is given (qiangxue)
- Chg #4331: `yii\helpers\Url` now uses `UrlManager` to determine base URL when generating URLs (qiangxue) - Chg #4331: `yii\helpers\Url` now uses `UrlManager` to determine base URL when generating URLs (qiangxue)
- Chg #4591: `yii\helpers\Url::to()` will no longer prefix relative URLs with the base URL (qiangxue)
- Chg #4595: `yii\widgets\LinkPager`'s `nextPageLabel`, `prevPageLabel`, `firstPageLabel`, `lastPageLabel` are now taking `false` instead of `null` for "no label" (samdark)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue) - Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue) - Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
- Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe) - Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
...@@ -225,6 +231,7 @@ Yii Framework 2 Change Log ...@@ -225,6 +231,7 @@ Yii Framework 2 Change Log
- Chg: `yii\web\Request::cookieValidationKey` must be explicitly specified for each application that wants to use cookie validation (qiangxue) - Chg: `yii\web\Request::cookieValidationKey` must be explicitly specified for each application that wants to use cookie validation (qiangxue)
- New #3911: Added `yii\behaviors\SluggableBehavior` that fills the specified model attribute with the transliterated and adjusted version to use in URLs (creocoder) - New #3911: Added `yii\behaviors\SluggableBehavior` that fills the specified model attribute with the transliterated and adjusted version to use in URLs (creocoder)
- New #4193: Added `yii\filters\Cors` CORS filter to allow Cross Origin Resource Sharing (pgaultier) - New #4193: Added `yii\filters\Cors` CORS filter to allow Cross Origin Resource Sharing (pgaultier)
- New: Added `yii\base\InvalidValueException` (qiangxue)
2.0.0-beta April 13, 2014 2.0.0-beta April 13, 2014
......
...@@ -174,6 +174,20 @@ new ones save the following code as `convert.php` that should be placed in the s ...@@ -174,6 +174,20 @@ new ones save the following code as `convert.php` that should be placed in the s
``` ```
* Due to significant changes to security you need to upgrade your code to use `\yii\base\Security` component instead of * Due to significant changes to security you need to upgrade your code to use `\yii\base\Security` component instead of
helper. If you have any data encrypted it should be re-encrypted. In order to do so you can use old security helper [as helper. If you have any data encrypted it should be re-encrypted. In order to do so you can use old security helper
explained by @docsolver at github](https://github.com/yiisoft/yii2/issues/4461#issuecomment-50237807). [as explained by @docsolver at github](https://github.com/yiisoft/yii2/issues/4461#issuecomment-50237807).
* [[yii\helpers\Url::to()]] will no longer prefix base URL to relative URLs. For example, `Url::to('images/logo.png')`
will return `images/logo.png` directly. If you want a relative URL to be prefix with base URL, you should make use
of the alias `@web`. For example, `Url::to('@web/images/logo.png')` will return `/BaseUrl/images/logo.png`.
- The following properties are now taking `false` instead of `null` for "don't use" case:
- `yii\bootstrap\NavBar::$brandLabel`.
- `yii\bootstrap\NavBar::$brandUrl`.
- `yii\bootstrap\Modal::$closeButton`.
- `yii\bootstrap\Modal::$toggleButton`.
- `yii\bootstrap\Alert::$closeButton`.
- `yii\widgets\LinkPager::$nextPageLabel`.
- `yii\widgets\LinkPager::$prevPageLabel`.
- `yii\widgets\LinkPager::$firstPageLabel`.
- `yii\widgets\LinkPager::$lastPageLabel`.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -41,9 +41,15 @@ ...@@ -41,9 +41,15 @@
// a callback that is called before validating each attribute. The signature of the callback should be: // a callback that is called before validating each attribute. The signature of the callback should be:
// function ($form, attribute, messages) { ...return false to cancel the validation...} // function ($form, attribute, messages) { ...return false to cancel the validation...}
beforeValidate: undefined, beforeValidate: undefined,
// a callback that is called before validation starts (This callback is only called when the form is submitted). This signature of the callback should be:
// function($form, data) { ...return false to cancel the validation...}
beforeValidateAll: undefined,
// a callback that is called after an attribute is validated. The signature of the callback should be: // a callback that is called after an attribute is validated. The signature of the callback should be:
// function ($form, attribute, messages) // function ($form, attribute, messages)
afterValidate: undefined, afterValidate: undefined,
// a callback that is called after all validation has run (This callback is only called when the form is submitted). The signature of the callback should be:
// function ($form, data, messages)
afterValidateAll: undefined,
// a pre-request callback function on AJAX-based validation. The signature of the callback should be: // a pre-request callback function on AJAX-based validation. The signature of the callback should be:
// function ($form, jqXHR, textStatus) // function ($form, jqXHR, textStatus)
ajaxBeforeSend: undefined, ajaxBeforeSend: undefined,
...@@ -152,6 +158,11 @@ ...@@ -152,6 +158,11 @@
clearTimeout(data.settings.timer); clearTimeout(data.settings.timer);
} }
data.submitting = true; data.submitting = true;
if (data.settings.beforeValidateAll && !data.settings.beforeValidateAll($form, data)) {
data.submitting = false;
return false;
}
validate($form, function (messages) { validate($form, function (messages) {
var errors = []; var errors = [];
$.each(data.attributes, function () { $.each(data.attributes, function () {
...@@ -159,6 +170,11 @@ ...@@ -159,6 +170,11 @@
errors.push(this.input); errors.push(this.input);
} }
}); });
if (data.settings.afterValidateAll) {
data.settings.afterValidateAll($form, data, messages);
}
updateSummary($form, messages); updateSummary($form, messages);
if (errors.length) { if (errors.length) {
var top = $form.find(errors.join(',')).first().offset().top; var top = $form.find(errors.join(',')).first().offset().top;
......
...@@ -111,7 +111,7 @@ yii.validation = (function ($) { ...@@ -111,7 +111,7 @@ yii.validation = (function ($) {
}; };
img.onerror = function () { img.onerror = function () {
messages.push(options.notImage); messages.push(options.notImage.replace(/\{file\}/g, file.name));
def.resolve(); def.resolve();
}; };
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* InvalidValueException represents an exception caused by a function returning a value of unexpected type.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidValueException extends \UnexpectedValueException
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return 'Invalid Return Value';
}
}
...@@ -121,7 +121,7 @@ class HelpController extends Controller ...@@ -121,7 +121,7 @@ class HelpController extends Controller
foreach ($class->getMethods() as $method) { foreach ($class->getMethods() as $method) {
$name = $method->getName(); $name = $method->getName();
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') { if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') {
$actions[] = Inflector::camel2id(substr($name, 6)); $actions[] = Inflector::camel2id(substr($name, 6), '-', true);
} }
} }
sort($actions); sort($actions);
......
...@@ -54,20 +54,20 @@ class ActionColumn extends Column ...@@ -54,20 +54,20 @@ class ActionColumn extends Column
* signature: * signature:
* *
* ```php * ```php
* function ($url, $model) { * function ($url, $model, $key) {
* // return the button HTML code * // return the button HTML code
* } * }
* ``` * ```
* *
* where `$url` is the URL that the column creates for the button, and `$model` is the model object * where `$url` is the URL that the column creates for the button, `$model` is the model object
* being rendered for the current row. * being rendered for the current row, and `$key` is the key of the model in the data provider array.
* *
* You can add further conditions to the button, for example only display it, when the model is * You can add further conditions to the button, for example only display it, when the model is
* editable (here assuming you have a status field that indicates that): * editable (here assuming you have a status field that indicates that):
* *
* ```php * ```php
* [ * [
* 'update' => function ($url, $model) { * 'update' => function ($url, $model, $key) {
* return $model->status == 'editable' ? Html::a('Update', $url) : ''; * return $model->status == 'editable' ? Html::a('Update', $url) : '';
* }; * };
* ], * ],
...@@ -155,7 +155,7 @@ class ActionColumn extends Column ...@@ -155,7 +155,7 @@ class ActionColumn extends Column
if (isset($this->buttons[$name])) { if (isset($this->buttons[$name])) {
$url = $this->createUrl($name, $model, $key, $index); $url = $this->createUrl($name, $model, $key, $index);
return call_user_func($this->buttons[$name], $url, $model); return call_user_func($this->buttons[$name], $url, $model, $key);
} else { } else {
return ''; return '';
} }
......
...@@ -33,7 +33,7 @@ class BaseMarkdown ...@@ -33,7 +33,7 @@ class BaseMarkdown
'html5' => true, 'html5' => true,
], ],
'gfm-comment' => [ 'gfm-comment' => [
'class' => 'cebe\markdown\Markdown', 'class' => 'cebe\markdown\GithubMarkdown',
'html5' => true, 'html5' => true,
'enableNewlines' => true, 'enableNewlines' => true,
], ],
......
...@@ -73,7 +73,7 @@ class BaseUrl ...@@ -73,7 +73,7 @@ class BaseUrl
* @param boolean|string $scheme the URI scheme to use in the generated URL: * @param boolean|string $scheme the URI scheme to use in the generated URL:
* *
* - `false` (default): generating a relative URL. * - `false` (default): generating a relative URL.
* - `true`: generating an absolute URL whose scheme is the same as the current request. * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::hostInfo]].
* - string: generating an absolute URL with the specified scheme (either `http` or `https`). * - string: generating an absolute URL with the specified scheme (either `http` or `https`).
* *
* @return string the generated URL * @return string the generated URL
...@@ -133,21 +133,20 @@ class BaseUrl ...@@ -133,21 +133,20 @@ class BaseUrl
* Creates a URL based on the given parameters. * Creates a URL based on the given parameters.
* *
* This method is very similar to [[toRoute()]]. The only difference is that this method * This method is very similar to [[toRoute()]]. The only difference is that this method
* requires a route to be specified as an array only. If a string is given, it will be treated * requires a route to be specified as an array only. If a string is given, it will be treated as a URL.
* as a URL which will be prefixed with the base URL if it does not start with a slash.
* In particular, if `$url` is * In particular, if `$url` is
* *
* - an array: [[toRoute()]] will be called to generate the URL. For example: * - an array: [[toRoute()]] will be called to generate the URL. For example:
* `['site/index']`, `['post/index', 'page' => 2]`. Please refer to [[toRoute()]] for more details * `['site/index']`, `['post/index', 'page' => 2]`. Please refer to [[toRoute()]] for more details
* on how to specify a route. * on how to specify a route.
* - a string with a leading `@`: it is treated as an alias and the corresponding aliased string * - a string with a leading `@`: it is treated as an alias, and the corresponding aliased string
* will be subject to the following rules. * will be returned.
* - an empty string: the currently requested URL will be returned; * - an empty string: the currently requested URL will be returned;
* - a string without a leading slash: it will be prefixed with [[\yii\web\Request::baseUrl]]. * - a normal string: it will be returned as is.
* - a string with a leading slash: it will be returned as is.
* *
* Note that in case `$scheme` is specified (either a string or true), an absolute URL with host info * When `$scheme` is specified (either a string or true), an absolute URL with host info (obtained from
* will be returned. * [[\yii\web\UrlManager::hostInfo]]) will be returned. If `$url` is already an absolute URL, its scheme
* will be replaced with the specified one.
* *
* Below are some examples of using this method: * Below are some examples of using this method:
* *
...@@ -162,13 +161,16 @@ class BaseUrl ...@@ -162,13 +161,16 @@ class BaseUrl
* echo Url::to(); * echo Url::to();
* *
* // /images/logo.gif * // /images/logo.gif
* echo Url::to('@web/images/logo.gif');
*
* // images/logo.gif
* echo Url::to('images/logo.gif'); * echo Url::to('images/logo.gif');
* *
* // http://www.example.com/index.php?r=site/index * // http://www.example.com/images/logo.gif
* echo Url::to(['site/index'], true); * echo Url::to('@web/images/logo.gif', true);
* *
* // https://www.example.com/index.php?r=site/index * // https://www.example.com/images/logo.gif
* echo Url::to(['site/index'], 'https'); * echo Url::to('@web/images/logo.gif', 'https');
* ``` * ```
* *
* *
...@@ -176,7 +178,7 @@ class BaseUrl ...@@ -176,7 +178,7 @@ class BaseUrl
* @param boolean|string $scheme the URI scheme to use in the generated URL: * @param boolean|string $scheme the URI scheme to use in the generated URL:
* *
* - `false` (default): generating a relative URL. * - `false` (default): generating a relative URL.
* - `true`: generating an absolute URL whose scheme is the same as the current request. * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::hostInfo]].
* - string: generating an absolute URL with the specified scheme (either `http` or `https`). * - string: generating an absolute URL with the specified scheme (either `http` or `https`).
* *
* @return string the generated URL * @return string the generated URL
...@@ -188,26 +190,29 @@ class BaseUrl ...@@ -188,26 +190,29 @@ class BaseUrl
return static::toRoute($url, $scheme); return static::toRoute($url, $scheme);
} }
$url = (string) Yii::getAlias($url); $url = Yii::getAlias($url);
if ($url === '') { if ($url === '') {
$url = Yii::$app->getRequest()->getUrl(); $url = Yii::$app->getRequest()->getUrl();
} else {
$hasScheme = ($pos = strpos($url, ':')) > 0 && ctype_alpha(substr($url, 0, $pos));
$char = $url[0];
if ($char !== '/' && $char !== '#' && $char !== '.' && !$hasScheme) {
$url = Yii::$app->getUrlManager()->getBaseUrl() . '/' . $url;
} }
if (!$scheme) {
return $url;
} }
if ($scheme) { if (strncmp($url, '//', 2) === 0) {
if (empty($hasScheme)) { // e.g. //hostname/path/to/resource
return is_string($scheme) ? "$scheme:$url" : $url;
}
if (($pos = strpos($url, ':')) == false || !ctype_alpha(substr($url, 0, $pos))) {
// turn relative URL into absolute
$url = Yii::$app->getUrlManager()->getHostInfo() . '/' . ltrim($url, '/'); $url = Yii::$app->getUrlManager()->getHostInfo() . '/' . ltrim($url, '/');
} }
if (is_string($scheme) && ($pos = strpos($url, ':')) !== false) { if (is_string($scheme) && ($pos = strpos($url, ':')) !== false) {
// replace the scheme with the specified one
$url = $scheme . substr($url, $pos); $url = $scheme . substr($url, $pos);
} }
}
return $url; return $url;
} }
...@@ -217,7 +222,7 @@ class BaseUrl ...@@ -217,7 +222,7 @@ class BaseUrl
* @param boolean|string $scheme the URI scheme to use in the returned base URL: * @param boolean|string $scheme the URI scheme to use in the returned base URL:
* *
* - `false` (default): returning the base URL without host info. * - `false` (default): returning the base URL without host info.
* - `true`: returning an absolute base URL whose scheme is the same as the current request. * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::hostInfo]].
* - string: returning an absolute base URL with the specified scheme (either `http` or `https`). * - string: returning an absolute base URL with the specified scheme (either `http` or `https`).
* @return string * @return string
*/ */
...@@ -296,7 +301,7 @@ class BaseUrl ...@@ -296,7 +301,7 @@ class BaseUrl
* @param boolean|string $scheme the URI scheme to use for the returned URL: * @param boolean|string $scheme the URI scheme to use for the returned URL:
* *
* - `false` (default): returning a relative URL. * - `false` (default): returning a relative URL.
* - `true`: returning an absolute URL whose scheme is the same as the current request. * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::hostInfo]].
* - string: returning an absolute URL with the specified scheme (either `http` or `https`). * - string: returning an absolute URL with the specified scheme (either `http` or `https`).
* *
* @return string home URL * @return string home URL
......
...@@ -197,13 +197,8 @@ class Validator extends Component ...@@ -197,13 +197,8 @@ class Validator extends Component
$type = static::$builtInValidators[$type]; $type = static::$builtInValidators[$type];
} }
if (is_array($type)) { if (is_array($type)) {
foreach ($type as $name => $value) { $params = array_merge($type, $params);
$params[$name] = $value;
}
} else { } else {
if (!class_exists($type)) {
throw new InvalidConfigException("Unknown validator: '$type'.");
}
$params['class'] = $type; $params['class'] = $type;
} }
} }
...@@ -308,6 +303,7 @@ class Validator extends Component ...@@ -308,6 +303,7 @@ class Validator extends Component
* - `attribute`: the name of the attribute being validated. * - `attribute`: the name of the attribute being validated.
* - `value`: the value being validated. * - `value`: the value being validated.
* - `messages`: an array used to hold the validation error messages for the attribute. * - `messages`: an array used to hold the validation error messages for the attribute.
* - `deferred`: an array used to hold deferred objects for asynchronous validation
* *
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
......
...@@ -83,6 +83,10 @@ class UrlRule extends Object implements UrlRuleInterface ...@@ -83,6 +83,10 @@ class UrlRule extends Object implements UrlRuleInterface
* If it is [[CREATION_ONLY]], the rule is for URL creation only. * If it is [[CREATION_ONLY]], the rule is for URL creation only.
*/ */
public $mode; public $mode;
/**
* @var bool a value indicating if parameters should be url encoded.
*/
public $encodeParams = true;
/** /**
* @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL. * @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL.
...@@ -310,7 +314,7 @@ class UrlRule extends Object implements UrlRuleInterface ...@@ -310,7 +314,7 @@ class UrlRule extends Object implements UrlRuleInterface
// match params in the pattern // match params in the pattern
foreach ($this->_paramRules as $name => $rule) { foreach ($this->_paramRules as $name => $rule) {
if (isset($params[$name]) && !is_array($params[$name]) && ($rule === '' || preg_match($rule, $params[$name]))) { if (isset($params[$name]) && !is_array($params[$name]) && ($rule === '' || preg_match($rule, $params[$name]))) {
$tr["<$name>"] = urlencode($params[$name]); $tr["<$name>"] = $this->encodeParams ? urlencode($params[$name]) : $params[$name];
unset($params[$name]); unset($params[$name]);
} elseif (!isset($this->defaults[$name]) || isset($params[$name])) { } elseif (!isset($this->defaults[$name]) || isset($params[$name])) {
return false; return false;
......
...@@ -10,6 +10,7 @@ namespace yii\web; ...@@ -10,6 +10,7 @@ namespace yii\web;
use Yii; use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidValueException;
/** /**
* User is the class for the "user" application component that manages the user authentication status. * User is the class for the "user" application component that manages the user authentication status.
...@@ -186,11 +187,18 @@ class User extends Component ...@@ -186,11 +187,18 @@ class User extends Component
* *
* @param IdentityInterface|null $identity the identity object associated with the currently logged user. * @param IdentityInterface|null $identity the identity object associated with the currently logged user.
* If null, it means the current user will be a guest without any associated identity. * If null, it means the current user will be a guest without any associated identity.
* @throws InvalidValueException if `$identity` object does not implement [[IdentityInterface]].
*/ */
public function setIdentity($identity) public function setIdentity($identity)
{ {
if ($identity instanceof IdentityInterface) {
$this->_identity = $identity; $this->_identity = $identity;
$this->_access = []; $this->_access = [];
} elseif ($identity === null) {
$this->_identity = null;
} else {
throw new InvalidValueException('The identity object must implement IdentityInterface.');
}
} }
/** /**
...@@ -219,7 +227,7 @@ class User extends Component ...@@ -219,7 +227,7 @@ class User extends Component
* Note that if [[enableSession]] is false, this parameter will be ignored. * Note that if [[enableSession]] is false, this parameter will be ignored.
* @return boolean whether the user is logged in * @return boolean whether the user is logged in
*/ */
public function login($identity, $duration = 0) public function login(IdentityInterface $identity, $duration = 0)
{ {
if ($this->beforeLogin($identity, false, $duration)) { if ($this->beforeLogin($identity, false, $duration)) {
$this->switchIdentity($identity, $duration); $this->switchIdentity($identity, $duration);
...@@ -274,23 +282,31 @@ class User extends Component ...@@ -274,23 +282,31 @@ class User extends Component
} }
$data = json_decode($value, true); $data = json_decode($value, true);
if (count($data) === 3 && isset($data[0], $data[1], $data[2])) { if (count($data) !== 3 || !isset($data[0], $data[1], $data[2])) {
return;
}
list ($id, $authKey, $duration) = $data; list ($id, $authKey, $duration) = $data;
/* @var $class IdentityInterface */ /* @var $class IdentityInterface */
$class = $this->identityClass; $class = $this->identityClass;
$identity = $class::findIdentity($id); $identity = $class::findIdentity($id);
if ($identity !== null && $identity->validateAuthKey($authKey)) { if ($identity === null) {
return;
} elseif (!$identity instanceof IdentityInterface) {
throw new InvalidValueException("$class::findIdentity() must return an object implementing IdentityInterface.");
}
if ($identity->validateAuthKey($authKey)) {
if ($this->beforeLogin($identity, true, $duration)) { if ($this->beforeLogin($identity, true, $duration)) {
$this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0); $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
$ip = Yii::$app->getRequest()->getUserIP(); $ip = Yii::$app->getRequest()->getUserIP();
Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__); Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__);
$this->afterLogin($identity, true, $duration); $this->afterLogin($identity, true, $duration);
} }
} elseif ($identity !== null) { } else {
Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__); Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__);
} }
} }
}
/** /**
* Logs out the current user. * Logs out the current user.
...@@ -552,7 +568,7 @@ class User extends Component ...@@ -552,7 +568,7 @@ class User extends Component
$session->remove($this->idParam); $session->remove($this->idParam);
$session->remove($this->authTimeoutParam); $session->remove($this->authTimeoutParam);
if ($identity instanceof IdentityInterface) { if ($identity) {
$session->set($this->idParam, $identity->getId()); $session->set($this->idParam, $identity->getId());
if ($this->authTimeout !== null) { if ($this->authTimeout !== null) {
$session->set($this->authTimeoutParam, time() + $this->authTimeout); $session->set($this->authTimeoutParam, time() + $this->authTimeout);
......
...@@ -142,6 +142,17 @@ class ActiveForm extends Widget ...@@ -142,6 +142,17 @@ class ActiveForm extends Widget
*/ */
public $beforeValidate; public $beforeValidate;
/** /**
* @var string|JsExpression a JS callback that is called before any validation has run (Only called when the form is submitted).
* The signature of the callback should be:
*
* ~~~
* function ($form, data) {
* ...return false to cancel the validation...
* }
* ~~~
*/
public $beforeValidateAll;
/**
* @var string|JsExpression a JS callback that is called after validating an attribute. * @var string|JsExpression a JS callback that is called after validating an attribute.
* The signature of the callback should be: * The signature of the callback should be:
* *
...@@ -152,6 +163,16 @@ class ActiveForm extends Widget ...@@ -152,6 +163,16 @@ class ActiveForm extends Widget
*/ */
public $afterValidate; public $afterValidate;
/** /**
* @var string|JsExpression a JS callback that is called after all validation has run (Only called when the form is submitted).
* The signature of the callback should be:
*
* ~~~
* function ($form, data, messages) {
* }
* ~~~
*/
public $afterValidateAll;
/**
* @var string|JsExpression a JS pre-request callback function on AJAX-based validation. * @var string|JsExpression a JS pre-request callback function on AJAX-based validation.
* The signature of the callback should be: * The signature of the callback should be:
* *
...@@ -229,7 +250,7 @@ class ActiveForm extends Widget ...@@ -229,7 +250,7 @@ class ActiveForm extends Widget
if ($this->validationUrl !== null) { if ($this->validationUrl !== null) {
$options['validationUrl'] = Url::to($this->validationUrl); $options['validationUrl'] = Url::to($this->validationUrl);
} }
foreach (['beforeSubmit', 'beforeValidate', 'afterValidate', 'ajaxBeforeSend', 'ajaxComplete'] as $name) { foreach (['beforeSubmit', 'beforeValidate', 'beforeValidateAll', 'afterValidate', 'afterValidateAll', 'ajaxBeforeSend', 'ajaxComplete'] as $name) {
if (($value = $this->$name) !== null) { if (($value = $this->$name) !== null) {
$options[$name] = $value instanceof JsExpression ? $value : new JsExpression($value); $options[$name] = $value instanceof JsExpression ? $value : new JsExpression($value);
} }
......
...@@ -72,25 +72,25 @@ class LinkPager extends Widget ...@@ -72,25 +72,25 @@ class LinkPager extends Widget
*/ */
public $maxButtonCount = 10; public $maxButtonCount = 10;
/** /**
* @var string the label for the "next" page button. Note that this will NOT be HTML-encoded. * @var string|boolean the label for the "next" page button. Note that this will NOT be HTML-encoded.
* If this property is null, the "next" page button will not be displayed. * If this property is false, the "next" page button will not be displayed.
*/ */
public $nextPageLabel = '&raquo;'; public $nextPageLabel = '&raquo;';
/** /**
* @var string the text label for the previous page button. Note that this will NOT be HTML-encoded. * @var string|boolean the text label for the previous page button. Note that this will NOT be HTML-encoded.
* If this property is null, the "previous" page button will not be displayed. * If this property is false, the "previous" page button will not be displayed.
*/ */
public $prevPageLabel = '&laquo;'; public $prevPageLabel = '&laquo;';
/** /**
* @var string the text label for the "first" page button. Note that this will NOT be HTML-encoded. * @var string|boolean the text label for the "first" page button. Note that this will NOT be HTML-encoded.
* If this property is null, the "first" page button will not be displayed. * Default is false that means the "first" page button will not be displayed.
*/ */
public $firstPageLabel; public $firstPageLabel = false;
/** /**
* @var string the text label for the "last" page button. Note that this will NOT be HTML-encoded. * @var string|boolean the text label for the "last" page button. Note that this will NOT be HTML-encoded.
* If this property is null, the "last" page button will not be displayed. * Default is false that means the "last" page button will not be displayed.
*/ */
public $lastPageLabel; public $lastPageLabel = false;
/** /**
* @var boolean whether to register link tags in the HTML header for prev, next, first and last page. * @var boolean whether to register link tags in the HTML header for prev, next, first and last page.
* Defaults to `false` to avoid conflicts when multiple pagers are used on one page. * Defaults to `false` to avoid conflicts when multiple pagers are used on one page.
...@@ -154,12 +154,12 @@ class LinkPager extends Widget ...@@ -154,12 +154,12 @@ class LinkPager extends Widget
$currentPage = $this->pagination->getPage(); $currentPage = $this->pagination->getPage();
// first page // first page
if ($this->firstPageLabel !== null) { if ($this->firstPageLabel !== false) {
$buttons[] = $this->renderPageButton($this->firstPageLabel, 0, $this->firstPageCssClass, $currentPage <= 0, false); $buttons[] = $this->renderPageButton($this->firstPageLabel, 0, $this->firstPageCssClass, $currentPage <= 0, false);
} }
// prev page // prev page
if ($this->prevPageLabel !== null) { if ($this->prevPageLabel !== false) {
if (($page = $currentPage - 1) < 0) { if (($page = $currentPage - 1) < 0) {
$page = 0; $page = 0;
} }
...@@ -173,7 +173,7 @@ class LinkPager extends Widget ...@@ -173,7 +173,7 @@ class LinkPager extends Widget
} }
// next page // next page
if ($this->nextPageLabel !== null) { if ($this->nextPageLabel !== false) {
if (($page = $currentPage + 1) >= $pageCount - 1) { if (($page = $currentPage + 1) >= $pageCount - 1) {
$page = $pageCount - 1; $page = $pageCount - 1;
} }
...@@ -181,7 +181,7 @@ class LinkPager extends Widget ...@@ -181,7 +181,7 @@ class LinkPager extends Widget
} }
// last page // last page
if ($this->lastPageLabel !== null) { if ($this->lastPageLabel !== false) {
$buttons[] = $this->renderPageButton($this->lastPageLabel, $pageCount - 1, $this->lastPageCssClass, $currentPage >= $pageCount - 1, false); $buttons[] = $this->renderPageButton($this->lastPageLabel, $pageCount - 1, $this->lastPageCssClass, $currentPage >= $pageCount - 1, false);
} }
......
...@@ -4,8 +4,9 @@ namespace yiiunit\extensions\twig; ...@@ -4,8 +4,9 @@ namespace yiiunit\extensions\twig;
use yii\web\AssetManager; use yii\web\AssetManager;
use yii\web\View; use yii\web\View;
use Yii; use Yii;
use yiiunit\data\ar\Order;
use yiiunit\data\base\Singer; use yiiunit\data\base\Singer;
use yiiunit\TestCase; use yiiunit\framework\db\DatabaseTestCase;
/** /**
* Tests Twig view renderer * Tests Twig view renderer
...@@ -13,10 +14,13 @@ use yiiunit\TestCase; ...@@ -13,10 +14,13 @@ use yiiunit\TestCase;
* @author Alexander Makarov <sam@rmcreative.ru> * @author Alexander Makarov <sam@rmcreative.ru>
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
*/ */
class ViewRendererTest extends TestCase class ViewRendererTest extends DatabaseTestCase
{ {
protected $driverName = 'sqlite';
protected function setUp() protected function setUp()
{ {
parent::setUp();
$this->mockApplication(); $this->mockApplication();
} }
...@@ -93,6 +97,14 @@ class ViewRendererTest extends TestCase ...@@ -93,6 +97,14 @@ class ViewRendererTest extends TestCase
$this->assertFalse(strpos($content, 'Original title') !== false, 'Original title should not be there:' . $content); $this->assertFalse(strpos($content, 'Original title') !== false, 'Original title should not be there:' . $content);
} }
public function testNullsInAr()
{
$view = $this->mockView();
$order = new Order();
$order::$db = $this->getConnection();
$view->renderFile('@yiiunit/extensions/twig/views/nulls.twig', ['order' => $order]);
}
/** /**
* Mocks view instance * Mocks view instance
* @return View * @return View
......
{{ order.customer }}
\ No newline at end of file
...@@ -121,21 +121,27 @@ class UrlTest extends TestCase ...@@ -121,21 +121,27 @@ class UrlTest extends TestCase
\Yii::setAlias('@web4', '/test'); \Yii::setAlias('@web4', '/test');
\Yii::setAlias('@web5', '#test'); \Yii::setAlias('@web5', '#test');
$this->assertEquals('/base/test/me1', Url::to('test/me1')); $this->assertEquals('test/me1', Url::to('test/me1'));
$this->assertEquals('javascript:test/me1', Url::to('javascript:test/me1')); $this->assertEquals('javascript:test/me1', Url::to('javascript:test/me1'));
$this->assertEquals('/base/java/script:test/me1', Url::to('java/script:test/me1')); $this->assertEquals('java/script:test/me1', Url::to('java/script:test/me1'));
$this->assertEquals('#test/me1', Url::to('#test/me1')); $this->assertEquals('#test/me1', Url::to('#test/me1'));
$this->assertEquals('.test/me1', Url::to('.test/me1')); $this->assertEquals('.test/me1', Url::to('.test/me1'));
$this->assertEquals('http://example.com/base/test/me1', Url::to('test/me1', true)); $this->assertEquals('http://example.com/test/me1', Url::to('test/me1', true));
$this->assertEquals('https://example.com/base/test/me1', Url::to('test/me1', 'https')); $this->assertEquals('https://example.com/test/me1', Url::to('test/me1', 'https'));
$this->assertEquals('https://example.com/test/test/me1', Url::to('@web4/test/me1', 'https'));
$this->assertEquals('/test/me1', Url::to('/test/me1'));
$this->assertEquals('http://example.com/test/me1', Url::to('/test/me1', true));
$this->assertEquals('https://example.com/test/me1', Url::to('/test/me1', 'https'));
$this->assertEquals('./test/me1', Url::to('./test/me1'));
$this->assertEquals('http://test.example.com/test/me1', Url::to('@web1')); $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1'));
$this->assertEquals('http://test.example.com/test/me1', Url::to('@web1', true)); $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1', true));
$this->assertEquals('https://test.example.com/test/me1', Url::to('@web1', 'https')); $this->assertEquals('https://test.example.com/test/me1', Url::to('@web1', 'https'));
$this->assertEquals('/base/test/me2', Url::to('@web2')); $this->assertEquals('test/me2', Url::to('@web2'));
$this->assertEquals('http://example.com/base/test/me2', Url::to('@web2', true)); $this->assertEquals('http://example.com/test/me2', Url::to('@web2', true));
$this->assertEquals('https://example.com/base/test/me2', Url::to('@web2', 'https')); $this->assertEquals('https://example.com/test/me2', Url::to('@web2', 'https'));
$this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3')); $this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3'));
$this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', true)); $this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', true));
......
...@@ -11,6 +11,15 @@ function filemtime($file) ...@@ -11,6 +11,15 @@ function filemtime($file)
return \yiiunit\framework\rbac\PhpManagerTest::$filemtime ?: \filemtime($file); return \yiiunit\framework\rbac\PhpManagerTest::$filemtime ?: \filemtime($file);
} }
/**
* Mock for the time() function for rbac classes. Avoid random test fails.
* @return int
*/
function time()
{
return \yiiunit\framework\rbac\PhpManagerTest::$time ?: \time();
}
namespace yiiunit\framework\rbac; namespace yiiunit\framework\rbac;
use Yii; use Yii;
...@@ -22,6 +31,7 @@ use Yii; ...@@ -22,6 +31,7 @@ use Yii;
class PhpManagerTest extends ManagerTestCase class PhpManagerTest extends ManagerTestCase
{ {
public static $filemtime; public static $filemtime;
public static $time;
protected function getItemFile() protected function getItemFile()
{ {
...@@ -60,6 +70,7 @@ class PhpManagerTest extends ManagerTestCase ...@@ -60,6 +70,7 @@ class PhpManagerTest extends ManagerTestCase
protected function setUp() protected function setUp()
{ {
static::$filemtime = null; static::$filemtime = null;
static::$time = null;
parent::setUp(); parent::setUp();
$this->mockApplication(); $this->mockApplication();
$this->removeDataFiles(); $this->removeDataFiles();
...@@ -70,18 +81,19 @@ class PhpManagerTest extends ManagerTestCase ...@@ -70,18 +81,19 @@ class PhpManagerTest extends ManagerTestCase
{ {
$this->removeDataFiles(); $this->removeDataFiles();
static::$filemtime = null; static::$filemtime = null;
static::$time = null;
parent::tearDown(); parent::tearDown();
} }
public function testSaveLoad() public function testSaveLoad()
{ {
$this->prepareData(); static::$time = static::$filemtime = \time();
$this->prepareData();
$items = $this->auth->items; $items = $this->auth->items;
$children = $this->auth->children; $children = $this->auth->children;
$assignments = $this->auth->assignments; $assignments = $this->auth->assignments;
$rules = $this->auth->rules; $rules = $this->auth->rules;
static::$filemtime = time();
$this->auth->save(); $this->auth->save();
$this->auth = $this->createManager(); $this->auth = $this->createManager();
......
...@@ -17,8 +17,8 @@ class BreadcrumbsTest extends \yiiunit\TestCase ...@@ -17,8 +17,8 @@ class BreadcrumbsTest extends \yiiunit\TestCase
public function setUp() public function setUp()
{ {
// dirty way to have Request object not throwing exception when running testHomeLinkNull() // dirty way to have Request object not throwing exception when running testHomeLinkNull()
$_SERVER['SCRIPT_FILENAME'] = "index.php"; $_SERVER['SCRIPT_FILENAME'] = "/index.php";
$_SERVER['SCRIPT_NAME'] = "index.php"; $_SERVER['SCRIPT_NAME'] = "/index.php";
$this->mockWebApplication(); $this->mockWebApplication();
$this->breadcrumbs = new Breadcrumbs(); $this->breadcrumbs = new Breadcrumbs();
...@@ -29,7 +29,7 @@ class BreadcrumbsTest extends \yiiunit\TestCase ...@@ -29,7 +29,7 @@ class BreadcrumbsTest extends \yiiunit\TestCase
$this->breadcrumbs->homeLink = null; $this->breadcrumbs->homeLink = null;
$this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page'];
$expectedHtml = "<ul class=\"breadcrumb\"><li><a href=\"./index.php\">Home</a></li>\n" $expectedHtml = "<ul class=\"breadcrumb\"><li><a href=\"/index.php\">Home</a></li>\n"
. "<li class=\"active\">My Home Page</li>\n" . "<li class=\"active\">My Home Page</li>\n"
. "<li class=\"active\">http://my.example.com/yii2/link/page</li>\n" . "<li class=\"active\">http://my.example.com/yii2/link/page</li>\n"
. "</ul>"; . "</ul>";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment