From fec58f4e298fe23404ddfecb4a684e2a8cb3e26e Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 10 Dec 2013 09:25:01 -0500 Subject: [PATCH 01/55] Fixes #1472: set event sender if possible. --- framework/yii/base/Event.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework/yii/base/Event.php b/framework/yii/base/Event.php index a678c89..974a1a4 100644 --- a/framework/yii/base/Event.php +++ b/framework/yii/base/Event.php @@ -161,6 +161,9 @@ class Event extends Object $event->name = $name; if (is_object($class)) { + if ($event->sender === null) { + $event->sender = $class; + } $class = get_class($class); } else { $class = ltrim($class, '\\'); From 2c9a8b910f7e4f9d2ecbf4be1ea64d56797928db Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 10 Dec 2013 20:42:09 +0100 Subject: [PATCH 02/55] make null format look nice by default --- apps/advanced/backend/web/css/site.css | 5 +++++ apps/advanced/frontend/web/css/site.css | 5 +++++ apps/basic/web/css/site.css | 5 +++++ framework/yii/base/Formatter.php | 4 ++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/advanced/backend/web/css/site.css b/apps/advanced/backend/web/css/site.css index 6a355bd..2d27436 100644 --- a/apps/advanced/backend/web/css/site.css +++ b/apps/advanced/backend/web/css/site.css @@ -18,6 +18,11 @@ body { padding: 14px 24px; } +.not-set { + color: #c55; + font-style: italic; +} + /* add sorting icons to gridview sort links */ a.asc:after, a.desc:after { position: relative; diff --git a/apps/advanced/frontend/web/css/site.css b/apps/advanced/frontend/web/css/site.css index 6a355bd..2d27436 100644 --- a/apps/advanced/frontend/web/css/site.css +++ b/apps/advanced/frontend/web/css/site.css @@ -18,6 +18,11 @@ body { padding: 14px 24px; } +.not-set { + color: #c55; + font-style: italic; +} + /* add sorting icons to gridview sort links */ a.asc:after, a.desc:after { position: relative; diff --git a/apps/basic/web/css/site.css b/apps/basic/web/css/site.css index 707c66d..d44558d 100644 --- a/apps/basic/web/css/site.css +++ b/apps/basic/web/css/site.css @@ -19,6 +19,11 @@ body { padding: 14px 24px; } +.not-set { + color: #c55; + font-style: italic; +} + /* add sorting icons to gridview sort links */ a.asc:after, a.desc:after { position: relative; diff --git a/framework/yii/base/Formatter.php b/framework/yii/base/Formatter.php index 33a6c16..bfc1e36 100644 --- a/framework/yii/base/Formatter.php +++ b/framework/yii/base/Formatter.php @@ -40,7 +40,7 @@ class Formatter extends Component */ public $datetimeFormat = 'Y/m/d h:i:s A'; /** - * @var string the text to be displayed when formatting a null. Defaults to '(not set)'. + * @var string the text to be displayed when formatting a null. Defaults to '(not set)'. */ public $nullDisplay; /** @@ -69,7 +69,7 @@ class Formatter extends Component $this->booleanFormat = [Yii::t('yii', 'No'), Yii::t('yii', 'Yes')]; } if ($this->nullDisplay === null) { - $this->nullDisplay = Yii::t('yii', '(not set)'); + $this->nullDisplay = '' . Yii::t('yii', '(not set)') . ''; } } From 12217a3ed83f062efaf9475f5d7633cb4e01e362 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 10 Dec 2013 20:42:43 +0100 Subject: [PATCH 03/55] code style and docs --- extensions/yii/gii/generators/crud/Generator.php | 4 ++-- framework/yii/grid/DataColumn.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/yii/gii/generators/crud/Generator.php b/extensions/yii/gii/generators/crud/Generator.php index b126c7b..bbd2ab5 100644 --- a/extensions/yii/gii/generators/crud/Generator.php +++ b/extensions/yii/gii/generators/crud/Generator.php @@ -188,9 +188,9 @@ class Generator extends \yii\gii\Generator $tableSchema = $this->getTableSchema(); if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) { if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) { - return "\$form->field(\$model, '$attribute')->passwordInput();"; + return "\$form->field(\$model, '$attribute')->passwordInput()"; } else { - return "\$form->field(\$model, '$attribute');"; + return "\$form->field(\$model, '$attribute')"; } } $column = $tableSchema->columns[$attribute]; diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php index d51af8f..032c21c 100644 --- a/framework/yii/grid/DataColumn.php +++ b/framework/yii/grid/DataColumn.php @@ -41,6 +41,7 @@ class DataColumn extends Column public $label; /** * @var \Closure an anonymous function that returns the value to be displayed for every data model. + * The signature of this function is `function ($model, $index, $widget)`. * If this is not set, `$model[$attribute]` will be used to obtain the value. */ public $value; From bfa7c80129c51be53c4c77d6f044fcff24027efa Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 10 Dec 2013 20:42:54 +0100 Subject: [PATCH 04/55] improved redis error message --- extensions/yii/redis/Connection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/yii/redis/Connection.php b/extensions/yii/redis/Connection.php index cea559f..b05223d 100644 --- a/extensions/yii/redis/Connection.php +++ b/extensions/yii/redis/Connection.php @@ -263,8 +263,8 @@ class Connection extends Component $this->executeCommand('SELECT', [$this->database]); $this->initConnection(); } else { - \Yii::error("Failed to open DB connection ($connection): " . $errorNumber . ' - ' . $errorDescription, __CLASS__); - $message = YII_DEBUG ? 'Failed to open DB connection: ' . $errorNumber . ' - ' . $errorDescription : 'Failed to open DB connection.'; + \Yii::error("Failed to open redis DB connection ($connection): $errorNumber - $errorDescription", __CLASS__); + $message = YII_DEBUG ? "Failed to open redis DB connection ($connection): $errorNumber - $errorDescription" : 'Failed to open DB connection.'; throw new Exception($message, $errorDescription, (int)$errorNumber); } } From e56d60ad49eed1156081f9371fa84ca0a5b83e4d Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 10 Dec 2013 17:04:39 -0500 Subject: [PATCH 05/55] Escape special chars in URL rules. --- framework/yii/web/UrlRule.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/framework/yii/web/UrlRule.php b/framework/yii/web/UrlRule.php index a2e34f9..2934b26 100644 --- a/framework/yii/web/UrlRule.php +++ b/framework/yii/web/UrlRule.php @@ -143,7 +143,16 @@ class UrlRule extends Object } } - $tr = $tr2 = []; + $tr = [ + '.' => '\\.', + '*' => '\\*', + '$' => '\\$', + '[' => '\\[', + ']' => '\\]', + '(' => '\\(', + ')' => '\\)', + ]; + $tr2 = []; if (preg_match_all('/<(\w+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { foreach ($matches as $match) { $name = $match[1][0]; @@ -166,7 +175,6 @@ class UrlRule extends Object } } } - $tr['.'] = '\\.'; $this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern); $this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u'; From 5caac5b0a3be3e5685c2cbee00cf3a5b7d72e94b Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 10 Dec 2013 23:14:04 +0100 Subject: [PATCH 06/55] Moved extensions docs draft from wiki to main repository --- docs/guide/extensions.md | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md index 2fcea72..fd7c3cc 100644 --- a/docs/guide/extensions.md +++ b/docs/guide/extensions.md @@ -1,4 +1,46 @@ Extending Yii ============= -TDB \ No newline at end of file +Code style +---------- + +- Extension code style should be similar to [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style). +- In case of using getter and setter for defining a property it's preferred to use method in extension code rather than property. +- TBD: namespace +- All classes, methods and properties should be documented using phpdoc. Note that you can use markdown and like to API +documents using `[[name()]]`. +- If you're displaying errors to developers do not translate these (i.e. do not use `\Yii::t()`). Errors should be + translated only if they're displayed to end users. + +Distribution +------------ + +- There should be a `readme.md` file clearly describing what extension does in English, its requirements, how to install + and use it. It should be written using markdown. If you want to provide translated readme, name it as `readme_ru.md` + where `ru` is your language code. +- TBD: composer.json + +Working with database +--------------------- + +- If extension creates or modifies database schema always use Yii migrations instead of SQL files or custom scripts. + +Assets +------ + +TBD + +Events +------ + +TBD + +i18n +---- + +TBD + +Testing your extension +---------------------- + +TBD \ No newline at end of file From ec7546efa8ae1201a854c61b71fb322fd6d291b8 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 10 Dec 2013 23:14:22 +0100 Subject: [PATCH 07/55] Copied and adjusted 1.1 git workflow document --- docs/internals/git-workflow.md | 175 +++++++++++++++++++++++++++++++++++++++++ docs/internals/git.md | 13 --- 2 files changed, 175 insertions(+), 13 deletions(-) create mode 100644 docs/internals/git-workflow.md delete mode 100644 docs/internals/git.md diff --git a/docs/internals/git-workflow.md b/docs/internals/git-workflow.md new file mode 100644 index 0000000..3386df6 --- /dev/null +++ b/docs/internals/git-workflow.md @@ -0,0 +1,175 @@ +Git workflow for Yii 2 contributors +=================================== + +So you want to contribute to Yii? Great! But to increase the chances of your changes being accepted quickly, please +follow the following steps (the first 2 steps only need to be done the first time you contribute). If you are new to git +and github, you might want to first check out [github help](http://help.github.com/), [learn git](http://gitref.org/) +or learn something about [git internal data model](http://nfarina.com/post/9868516270/git-is-simpler). + +### 1. [Fork](http://help.github.com/fork-a-repo/) the Yii repository on github and clone your fork to your development +environment + +``` +git clone git@github.com:YOUR-GITHUB-USERNAME/yii2.git +``` + +If you have trouble setting up GIT with GitHub in Linux, or are getting errors like "Permission Denied (publickey)", +then you must [setup your GIT installation to work with GitHub](http://help.github.com/linux-set-up-git/) + +### 2. Add the main Yii repository as an additional git remote called "upstream" + +Change to the directory where you cloned Yii, normally, "yii". Then enter the following command: + +``` +git remote add upstream git://github.com/yiisoft/yii.git +``` + +### 3. Make sure there is an issue created for the thing you are working on. + +All new features and bug fixes should have an associated issue to provide a single point of reference for discussion +and documentation. Take a few minutes to look through the existing issue list for one that matches the contribution you +intend to make. If you find one already on the issue list, then please leave a comment on that issue indicating you +intend to work on that item. If you do not find an existing issue matching what you intend to work on, please open a +new issue for your item. This will allow the team to review your suggestion, and provide appropriate feedback along +the way. + +> For small changes or documentation issues, you don't need to create an issue, a pull request is enough in this case. + +### 4. Fetch the latest code from the main Yii branch + +``` +git fetch upstream +``` + +You should start at this point for every new contribution to make sure you are working on the latest code. + +### 5. Create a new branch for your feature based on the current Yii master branch + +> That's very important since you will not be able to submit more than one pull request from your account if you'll + use master. + +Each separate bug fix or change should go in its own branch. Branch names should be descriptive and start with +the number of the issue that your code relates to. If you aren't fixing any particular issue, just skip number. +For example: + +``` +git checkout upstream/master +git checkout -b 999-name-of-your-branch-goes-here +``` + +### 6. Do your magic, write your code + +Make sure it works :) + +Unit tests are always welcome. Tested and well covered code greatly simplifies the task of checking your contributions. +Failing unit tests as issue description are also accepted. + +### 7. Update the CHANGELOG + +Edit the CHANGELOG file to include your change, you should insert this at the top of the file under the +"Work in progress" heading, the line in the change log should look like one of the following: + +``` +Bug #999: a description of the bug fix (Your Name) +Enh #999: a description of the enhancement (Your Name) +``` + +`#999` is the issue number that the `Bug` or `Enh` is referring to. +The changelog should be grouped by type (`Bug`,`Enh`) and ordered by issue number. + +For very small fixes, e.g. typos and documentation changes, there is no need to update the CHANGELOG. + +### 8. Commit your changes + +add the files/changes you want to commit to the [staging area](http://gitref.org/basic/#add) with + +``` +git add path/to/my/file.php +``` + +You can use the `-p` option to select the changes you want to have in your commit. + +Commit your changes with a descriptive commit message. Make sure to mention the ticket number with `#XXX` so github will +automatically link your commit with the ticket: + +``` +git commit -m "A brief description of this change which fixes #42 goes here" +``` + +### 9. Pull the latest Yii code from upstream into your branch + +``` +git pull upstream master +``` + +This ensures you have the latest code in your branch before you open your pull request. If there are any merge conflicts, +you should fix them now and commit the changes again. This ensures that it's easy for the Yii team to merge your changes +with one click. + +### 10. Having resolved any conflicts, push your code to github + +``` +git push -u origin 999-name-of-your-branch-goes-here +``` + +The `-u` parameter ensures that your branch will now automatically push and pull from the github branch. That means +if you type `git push` the next time it will know where to push to. + +### 11. Open a [pull request](http://help.github.com/send-pull-requests/) against upstream. + +Go to your repository on github and click "Pull Request", choose your branch on the right and enter some more details +in the comment box. To link the pull request to the issue put anywhere in the pull comment `#999` where 999 is the +issue number. + +> Note that each pull-request should fix a single change. + +### 12. Someone will review your code + +Someone will review your code, and you might be asked to make some changes, if so go to step #6 (you don't need to open +another pull request if your current one is still open). If your code is accepted it will be merged into the main branch +and become part of the next Yii release. If not, don't be disheartened, different people need different features and Yii +can't be everything to everyone, your code will still be available on github as a reference for people who need it. + +### 13. Cleaning it up + +After your code was either accepted or declined you can delete branches you've worked with from your local repository +and `origin`. + +``` +git checkout master +git branch -D 999-name-of-your-branch-goes-here +git push origin --delete 999-name-of-your-branch-goes-here +``` + +### Note: + +To detect regressions early every merge to the Yii codebase on github will be picked up by +[Travis CI](http://travis-ci.org) for an automated testrun. As core team doesn't wish to overtax this service, +[`[ci skip]`](http://about.travis-ci.org/docs/user/how-to-skip-a-build/) will be included to the merge description if +the pull request: + +* affect javascript, css or image files only, +* updates the documentation, +* modify fixed strings only (e.g. translation updates) + +Doing so will save travis from commencing testruns on changes that are not covered by tests in the first place. + +### Command overview (for advanced contributors) + +``` +git clone git@github.com:YOUR-GITHUB-USERNAME/yii.git +git remote add upstream git://github.com/yiisoft/yii.github +``` + +``` +git fetch upstream +git checkout upstream/master +git checkout -b 999-name-of-your-branch-goes-here + +/* do your magic, update changelog if needed */ + +git add path/to/my/file.php +git commit -m "A brief description of this change which fixes #42 goes here" +git pull upstream master +git push -u origin 999-name-of-your-branch-goes-here +``` diff --git a/docs/internals/git.md b/docs/internals/git.md deleted file mode 100644 index 0d660aa..0000000 --- a/docs/internals/git.md +++ /dev/null @@ -1,13 +0,0 @@ -Git branches and tags -===================== - -Tags ----- - -Each release should be tagged with v2.X.X and message "Yii 2.X.X release". - -Branches --------- - -What should be in master branch? -Do we need another branches? \ No newline at end of file From 86dd428257b4a3f782aa88e36ddeeff91ca6c3f0 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 10 Dec 2013 23:20:43 +0100 Subject: [PATCH 08/55] Added rules about namespace and package naming to extension docs --- docs/guide/extensions.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md index fd7c3cc..271ba11 100644 --- a/docs/guide/extensions.md +++ b/docs/guide/extensions.md @@ -6,12 +6,19 @@ Code style - Extension code style should be similar to [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style). - In case of using getter and setter for defining a property it's preferred to use method in extension code rather than property. -- TBD: namespace - All classes, methods and properties should be documented using phpdoc. Note that you can use markdown and like to API documents using `[[name()]]`. - If you're displaying errors to developers do not translate these (i.e. do not use `\Yii::t()`). Errors should be translated only if they're displayed to end users. +### Namespace and package names + +- Extension MUST use the type `yii2-extension` in `composer.json` file. +- Extension MUST NOT use `yii` or `yii2` in the composer package name or in the namespaces used in the package. +- Extension SHOULD use namespaces in this format `vendor-name\package` (all lowercase). +- Extension MAY use a `yii2-` prefix in the composer vendor name (URL). +- Extension MAY use a `yii2-` prefix in the repository name (URL). + Distribution ------------ From 45fa25f796ccacc2e379f6611aca0dc968fed8d7 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 10 Dec 2013 23:30:45 +0100 Subject: [PATCH 09/55] Added notes about github and screenshots to extension docs --- docs/guide/extensions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md index 271ba11..1aa5ce2 100644 --- a/docs/guide/extensions.md +++ b/docs/guide/extensions.md @@ -24,8 +24,9 @@ Distribution - There should be a `readme.md` file clearly describing what extension does in English, its requirements, how to install and use it. It should be written using markdown. If you want to provide translated readme, name it as `readme_ru.md` - where `ru` is your language code. + where `ru` is your language code. If extension provides a widget it is a good idea to include some screenshots. - TBD: composer.json +- It is recommended to host your extensions at github.com. Working with database --------------------- From eab7e4a21aabf04fa0bac76203122460cc79817e Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 10 Dec 2013 18:17:24 -0500 Subject: [PATCH 10/55] Added $formName to Model::load(). --- framework/yii/base/Model.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php index 22849b2..ba51ec7 100644 --- a/framework/yii/base/Model.php +++ b/framework/yii/base/Model.php @@ -714,11 +714,13 @@ class Model extends Component implements IteratorAggregate, ArrayAccess * The data being populated is subject to the safety check by [[setAttributes()]]. * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array * supplied by end user. + * @param string $formName the form name to be used for loading the data into the model. + * If not set, [[formName()]] will be used. * @return boolean whether the model is successfully populated with some data. */ - public function load($data) + public function load($data, $formName = null) { - $scope = $this->formName(); + $scope = $formName === null ? $this->formName() : $formName; if ($scope == '') { $this->setAttributes($data); return true; From 97645bcfb5a56932e243cd54dec99f833a045acb Mon Sep 17 00:00:00 2001 From: DaSourcerer Date: Wed, 11 Dec 2013 14:07:17 +0100 Subject: [PATCH 11/55] Removed compatibility code for PHP < 5.4 --- framework/yii/web/Session.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php index 894d75d..e957040 100644 --- a/framework/yii/web/Session.php +++ b/framework/yii/web/Session.php @@ -179,13 +179,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co */ public function getIsActive() { - if (function_exists('session_status')) { - // available in PHP 5.4.0+ - return session_status() == PHP_SESSION_ACTIVE; - } else { - // this is not very reliable - return $this->_opened && session_id() !== ''; - } + return session_status() == PHP_SESSION_ACTIVE; } /** From be66f43d52114a3c38bf8270f58a7141c7a80ebf Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 16:12:11 +0100 Subject: [PATCH 12/55] invalidate opcache of extensions.php file in composer installer fixes #1480 --- extensions/yii/composer/Installer.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extensions/yii/composer/Installer.php b/extensions/yii/composer/Installer.php index d8d799f..6f69afc 100644 --- a/extensions/yii/composer/Installer.php +++ b/extensions/yii/composer/Installer.php @@ -135,6 +135,10 @@ class Installer extends LibraryInstaller if (!is_file($file)) { return []; } + // invalidate opcache of extensions.php if exists + if (function_exists('opcache_invalidate')) { + opcache_invalidate($file, true); + } $extensions = require($file); $vendorDir = str_replace('\\', '/', $this->vendorDir); @@ -159,6 +163,10 @@ class Installer extends LibraryInstaller $file = $this->vendorDir . '/' . self::EXTENSION_FILE; $array = str_replace("'", '$vendorDir . \'', var_export($extensions, true)); file_put_contents($file, " Date: Wed, 11 Dec 2013 16:46:09 +0100 Subject: [PATCH 13/55] doc typos --- docs/guide/extensions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md index 1aa5ce2..47ba380 100644 --- a/docs/guide/extensions.md +++ b/docs/guide/extensions.md @@ -6,8 +6,8 @@ Code style - Extension code style should be similar to [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style). - In case of using getter and setter for defining a property it's preferred to use method in extension code rather than property. -- All classes, methods and properties should be documented using phpdoc. Note that you can use markdown and like to API -documents using `[[name()]]`. +- All classes, methods and properties should be documented using phpdoc. Note that you can use markdown and link to properties and methods +using the following syntax: e.g. `[[name()]]`, `[[name\space\MyClass::name()]]`. - If you're displaying errors to developers do not translate these (i.e. do not use `\Yii::t()`). Errors should be translated only if they're displayed to end users. From ac3967cab72763defe5e6f4a22ed1a6a50cf9ab7 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 16:47:30 +0100 Subject: [PATCH 14/55] removed unused property from Session cleanup after #1479 --- framework/yii/web/Session.php | 44 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php index e957040..903e9d9 100644 --- a/framework/yii/web/Session.php +++ b/framework/yii/web/Session.php @@ -112,43 +112,36 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co return false; } - private $_opened = false; - /** * Starts the session. */ public function open() { if (session_status() == PHP_SESSION_ACTIVE) { - $this->_opened = true; return; } - if (!$this->_opened) { - if ($this->getUseCustomStorage()) { - @session_set_save_handler( - [$this, 'openSession'], - [$this, 'closeSession'], - [$this, 'readSession'], - [$this, 'writeSession'], - [$this, 'destroySession'], - [$this, 'gcSession'] - ); - } + if ($this->getUseCustomStorage()) { + @session_set_save_handler( + [$this, 'openSession'], + [$this, 'closeSession'], + [$this, 'readSession'], + [$this, 'writeSession'], + [$this, 'destroySession'], + [$this, 'gcSession'] + ); + } - $this->setCookieParamsInternal(); + $this->setCookieParamsInternal(); - @session_start(); + @session_start(); - if (session_id() == '') { - $this->_opened = false; - $error = error_get_last(); - $message = isset($error['message']) ? $error['message'] : 'Failed to start session.'; - Yii::error($message, __METHOD__); - } else { - $this->_opened = true; - $this->updateFlashCounters(); - } + if (session_id() == '') { + $error = error_get_last(); + $message = isset($error['message']) ? $error['message'] : 'Failed to start session.'; + Yii::error($message, __METHOD__); + } else { + $this->updateFlashCounters(); } } @@ -157,7 +150,6 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co */ public function close() { - $this->_opened = false; if (session_id() !== '') { @session_write_close(); } From d2308eda8d6a102e1d177ae022b22d6526b26adc Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 18:04:58 +0100 Subject: [PATCH 15/55] added CHANGELOGs for all the extensions also filled framework CHANGELOG with relevant changes since alpha --- extensions/yii/bootstrap/CHANGELOG.md | 12 ++++++++++++ extensions/yii/composer/CHANGELOG.md | 13 +++++++++++++ extensions/yii/debug/CHANGELOG.md | 12 ++++++++++++ extensions/yii/elasticsearch/CHANGELOG.md | 12 ++++++++++++ extensions/yii/gii/CHANGELOG.md | 12 ++++++++++++ extensions/yii/jui/CHANGELOG.md | 12 ++++++++++++ extensions/yii/mongodb/CHANGELOG.md | 7 +++++++ extensions/yii/redis/CHANGELOG.md | 12 ++++++++++++ extensions/yii/smarty/CHANGELOG.md | 12 ++++++++++++ extensions/yii/sphinx/CHANGELOG.md | 12 ++++++++++++ extensions/yii/swiftmailer/CHANGELOG.md | 12 ++++++++++++ extensions/yii/twig/CHANGELOG.md | 12 ++++++++++++ framework/CHANGELOG.md | 19 +++++++++++++++++++ 13 files changed, 159 insertions(+) create mode 100644 extensions/yii/bootstrap/CHANGELOG.md create mode 100644 extensions/yii/composer/CHANGELOG.md create mode 100644 extensions/yii/debug/CHANGELOG.md create mode 100644 extensions/yii/elasticsearch/CHANGELOG.md create mode 100644 extensions/yii/gii/CHANGELOG.md create mode 100644 extensions/yii/jui/CHANGELOG.md create mode 100644 extensions/yii/mongodb/CHANGELOG.md create mode 100644 extensions/yii/redis/CHANGELOG.md create mode 100644 extensions/yii/smarty/CHANGELOG.md create mode 100644 extensions/yii/sphinx/CHANGELOG.md create mode 100644 extensions/yii/swiftmailer/CHANGELOG.md create mode 100644 extensions/yii/twig/CHANGELOG.md diff --git a/extensions/yii/bootstrap/CHANGELOG.md b/extensions/yii/bootstrap/CHANGELOG.md new file mode 100644 index 0000000..40974e7 --- /dev/null +++ b/extensions/yii/bootstrap/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 bootstrap extension Change Log +============================================== + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/composer/CHANGELOG.md b/extensions/yii/composer/CHANGELOG.md new file mode 100644 index 0000000..8c49892 --- /dev/null +++ b/extensions/yii/composer/CHANGELOG.md @@ -0,0 +1,13 @@ +Yii Framework 2 composer extension Change Log +============================================= + +2.0.0 beta under development +---------------------------- + +- Bug #1480: Fixed issue with creating extensions.php when php opcache is enabled (cebe) + + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/debug/CHANGELOG.md b/extensions/yii/debug/CHANGELOG.md new file mode 100644 index 0000000..1f83ca4 --- /dev/null +++ b/extensions/yii/debug/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 debug extension Change Log +========================================== + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/elasticsearch/CHANGELOG.md b/extensions/yii/elasticsearch/CHANGELOG.md new file mode 100644 index 0000000..1a84ed3 --- /dev/null +++ b/extensions/yii/elasticsearch/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 elasticsearch extension Change Log +================================================== + +2.0.0 beta under development +---------------------------- + +- Enh #1382: Added a debug toolbar panel for elasticsearch (cebe) + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/gii/CHANGELOG.md b/extensions/yii/gii/CHANGELOG.md new file mode 100644 index 0000000..baa33d0 --- /dev/null +++ b/extensions/yii/gii/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 gii extension Change Log +======================================== + +2.0.0 beta under development +---------------------------- + +- Bug #1405: fixed disambiguation of relation names generated by gii (qiangxue) + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/jui/CHANGELOG.md b/extensions/yii/jui/CHANGELOG.md new file mode 100644 index 0000000..eb30e09 --- /dev/null +++ b/extensions/yii/jui/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 jui extension Change Log +======================================== + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/mongodb/CHANGELOG.md b/extensions/yii/mongodb/CHANGELOG.md new file mode 100644 index 0000000..ab31546 --- /dev/null +++ b/extensions/yii/mongodb/CHANGELOG.md @@ -0,0 +1,7 @@ +Yii Framework 2 mongodb extension Change Log +============================================ + +2.0.0 beta under development +---------------------------- + +- Initial release. diff --git a/extensions/yii/redis/CHANGELOG.md b/extensions/yii/redis/CHANGELOG.md new file mode 100644 index 0000000..5cd966a --- /dev/null +++ b/extensions/yii/redis/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 redis extension Change Log +========================================== + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/smarty/CHANGELOG.md b/extensions/yii/smarty/CHANGELOG.md new file mode 100644 index 0000000..6037962 --- /dev/null +++ b/extensions/yii/smarty/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 smarty extension Change Log +=========================================== + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/sphinx/CHANGELOG.md b/extensions/yii/sphinx/CHANGELOG.md new file mode 100644 index 0000000..58509de --- /dev/null +++ b/extensions/yii/sphinx/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 sphinx extension Change Log +=========================================== + +2.0.0 beta under development +---------------------------- + +- Enh #1398: Refactor ActiveRecord to use BaseActiveRecord class of the framework (klimov-paul) + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/swiftmailer/CHANGELOG.md b/extensions/yii/swiftmailer/CHANGELOG.md new file mode 100644 index 0000000..359fb29 --- /dev/null +++ b/extensions/yii/swiftmailer/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 swiftmailer extension Change Log +================================================ + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/extensions/yii/twig/CHANGELOG.md b/extensions/yii/twig/CHANGELOG.md new file mode 100644 index 0000000..85b09d5 --- /dev/null +++ b/extensions/yii/twig/CHANGELOG.md @@ -0,0 +1,12 @@ +Yii Framework 2 twig extension Change Log +========================================= + +2.0.0 beta under development +---------------------------- + +- no changes in this release. + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index c460706..a4cfd53 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,8 +4,27 @@ Yii Framework 2 Change Log 2.0.0 beta under development ---------------------------- +- Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) +- Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) +- Enh #1437: Added ListView::viewParams (qiangxue) +- New extension #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 --------------------------- - Initial release. +- Official extensions released in this version: + - [Twitter bootstrap 3.0](https://github.com/yiisoft/yii2-bootstrap) + - [Jquery UI](https://github.com/yiisoft/yii2-jui) + + - [Debug Toolbar](https://github.com/yiisoft/yii2-debug) + - [Gii code generator](https://github.com/yiisoft/yii2-gii) + + - [Elasticsearch integration](https://github.com/yiisoft/yii2-elasticsearch): ActiveRecord and Query + - [Redis integration](https://github.com/yiisoft/yii2-redis): ActiveRecord, Cache and Session + - [Sphinx integration](https://github.com/yiisoft/yii2-redis): ActiveRecord and Query + + - [Swiftmailer](https://github.com/yiisoft/yii2-swiftmailer) + + - [Smarty View Renderer](https://github.com/yiisoft/yii2-smarty) + - [Twig View Renderer](https://github.com/yiisoft/yii2-twig) From cd3949b13be06c054c7cfd8ecb6a6e542a1ecee7 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 18:08:28 +0100 Subject: [PATCH 16/55] fixed link in CHANGELOG --- framework/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index a4cfd53..097fd99 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -22,7 +22,7 @@ Yii Framework 2 Change Log - [Elasticsearch integration](https://github.com/yiisoft/yii2-elasticsearch): ActiveRecord and Query - [Redis integration](https://github.com/yiisoft/yii2-redis): ActiveRecord, Cache and Session - - [Sphinx integration](https://github.com/yiisoft/yii2-redis): ActiveRecord and Query + - [Sphinx integration](https://github.com/yiisoft/yii2-sphinx): ActiveRecord and Query - [Swiftmailer](https://github.com/yiisoft/yii2-swiftmailer) From 41fbfcbd80bf6915345b269ca042f80cdd197361 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 11 Dec 2013 14:28:36 -0500 Subject: [PATCH 17/55] doc fix. --- docs/guide/active-record.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/guide/active-record.md b/docs/guide/active-record.md index dc304ed..601dfb5 100644 --- a/docs/guide/active-record.md +++ b/docs/guide/active-record.md @@ -220,8 +220,7 @@ are used to model the many-one relationship and one-one relationship in a relati For example, a customer has many orders, and an order has one customer. Both methods take two parameters and return an [[ActiveRelation]] object: - - `$class`: the name of the class of the related model(s). If specified without - a namespace, the namespace of the related model class will be taken from the declaring class. + - `$class`: the name of the class of the related model(s). This should be a fully qualified class name. - `$link`: the association between columns from the two tables. This should be given as an array. The keys of the array are the names of the columns from the table associated with `$class`, while the values of the array are the names of the columns from the declaring class. From be911e199a088fa7574a069b3af9cce3e468c6e7 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 21:14:57 +0100 Subject: [PATCH 18/55] created proper progress bar fixes #1293 --- framework/CHANGELOG.md | 1 + framework/yii/helpers/BaseConsole.php | 171 +++++++++++++++++++++++++--------- 2 files changed, 130 insertions(+), 42 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 097fd99..e1f3899 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -5,6 +5,7 @@ Yii Framework 2 Change Log ---------------------------- - Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) +- Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) - New extension #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) diff --git a/framework/yii/helpers/BaseConsole.php b/framework/yii/helpers/BaseConsole.php index 92f7c46..0b8e6be 100644 --- a/framework/yii/helpers/BaseConsole.php +++ b/framework/yii/helpers/BaseConsole.php @@ -618,7 +618,7 @@ class BaseConsole * Gets input from STDIN and returns a string right-trimmed for EOLs. * * @param bool $raw If set to true, returns the raw string without trimming - * @return string + * @return string the string read from stdin */ public static function stdin($raw = false) { @@ -651,7 +651,7 @@ class BaseConsole * Asks the user for input. Ends when the user types a carriage return (PHP_EOL). Optionally, It also provides a * prompt. * - * @param string $prompt the prompt (optional) + * @param string $prompt the prompt to display before waiting for input (optional) * @return string the user's input */ public static function input($prompt = null) @@ -776,60 +776,147 @@ class BaseConsole return $input; } + private static $_progressStart; + private static $_progressWidth; + private static $_progressPrefix; + /** - * Displays and updates a simple progress bar on screen. + * Starts display of a progress bar on screen. + * + * This bar will be updated by [[updateProgress()]] and my be ended by [[endProgress()]]. + * + * The following example shows a simple usage of a progress bar: + * + * ```php + * Console::startProgress(0, 1000); + * for ($n = 1; $n <= 1000; $n++) { + * usleep(1000); + * Console::updateProgress($n, 1000); + * } + * Console::endProgress(); + * ``` + * + * Git clone like progress (showing only status information): + * ```php + * Console::startProgress(0, 1000, 'Counting objects: ', false); + * for ($n = 1; $n <= 1000; $n++) { + * usleep(1000); + * Console::updateProgress($n, 1000); + * } + * Console::endProgress("done." . PHP_EOL); + * ``` * - * @param integer $done the number of items that are completed - * @param integer $total the total value of items that are to be done - * @param integer $size the size of the status bar (optional) - * @see http://snipplr.com/view/29548/ + * @param integer $done the number of items that are completed. + * @param integer $total the total value of items that are to be done. + * @param string $prefix an optional string to display before the progress bar. + * Default to empty string which results in no prefix to be displayed. + * @param integer|boolean $width optional width of the progressbar. This can be an integer representing + * the number of characters to display for the progress bar or a float between 0 and 1 representing the + * percentage of screen with the progress bar may take. It can also be set to false to disable the + * bar and only show progress information like percent, number of items and ETA. + * If not set, the bar will be as wide as the screen. Screen size will be detected using [[getScreenSize()]]. + * @see startProgress + * @see updateProgress + * @see endProgress */ - public static function showProgress($done, $total, $size = 30) + public static function startProgress($done, $total, $prefix = '', $width = null) { - static $start; + self::$_progressStart = time(); + self::$_progressWidth = $width; + self::$_progressPrefix = $prefix; - // if we go over our bound, just ignore it - if ($done > $total) { - return; - } + static::updateProgress($done, $total); + } - if (empty($start)) { - $start = time(); + /** + * Updates a progress bar that has been started by [[startProgress()]]. + * + * @param integer $done the number of items that are completed. + * @param integer $total the total value of items that are to be done. + * @param string $prefix an optional string to display before the progress bar. + * Defaults to null meaning the prefix specified by [[startProgress()]] will be used. + * If prefix is specified it will update the prefix that will be used by later calls. + * @see startProgress + * @see endProgress + */ + public static function updateProgress($done, $total, $prefix = null) + { + $width = self::$_progressWidth; + if ($width === false) { + $width = 0; + } else { + $screenSize = static::getScreenSize(true); + if ($screenSize === false && $width < 1) { + $width = 0; + } elseif ($width === null) { + $width = $screenSize[0]; + } elseif ($width > 0 && $width < 1) { + $width = floor($screenSize[0] * $width); + } } - - $now = time(); - - $percent = (double)($done / $total); - $bar = floor($percent * $size); - - $status = "\r["; - $status .= str_repeat("=", $bar); - if ($bar < $size) { - $status .= ">"; - $status .= str_repeat(" ", $size - $bar); + if ($prefix === null) { + $prefix = self::$_progressPrefix; } else { - $status .= "="; + self::$_progressPrefix = $prefix; } + $width -= mb_strlen($prefix); - $display = number_format($percent * 100, 0); - - $status .= "] $display% $done/$total"; - - $rate = ($now - $start) / $done; - $left = $total - $done; - $eta = round($rate * $left, 2); - - $elapsed = $now - $start; - - $status .= " remaining: " . number_format($eta) . " sec. elapsed: " . number_format($elapsed) . " sec."; + $percent = $done / $total; + $info = sprintf("%d%% (%d/%d)", $percent * 100, $done, $total); - static::stdout("$status "); + if ($done > $total || $done == 0) { + $info .= ' ETA: n/a'; + } elseif ($done < $total) { + $rate = (time() - self::$_progressStart) / $done; + $info .= sprintf(' ETA: %d sec.', $rate * ($total - $done)); + } + $width -= 3 + mb_strlen($info); + // skipping progress bar on very small display or if forced to skip + if ($width < 5) { + static::stdout("\r$prefix$info "); + } else { + if ($percent < 0) { + $percent = 0; + } elseif ($percent > 1) { + $percent = 1; + } + $bar = floor($percent * $width); + $status = str_repeat("=", $bar); + if ($bar < $width) { + $status .= ">"; + $status .= str_repeat(" ", $width - $bar - 1); + } + static::stdout("\r$prefix" . "[$status] $info"); + } flush(); + } - // when done, send a newline - if ($done == $total) { - echo "\n"; + /** + * Ends a progress bar that has been started by [[startProgress()]]. + * + * @param string|boolean $remove This can be `false` to leave the progress bar on screen and just print a newline. + * If set to `true`, the line of the progress bar will be cleared. This may also be a string to be displayed instead + * of the progress bar. + * @param bool $keepPrefix whether to keep the prefix that has been specified for the progressbar when progressbar + * gets removed. Defaults to true. + * @see startProgress + * @see updateProgress + */ + public static function endProgress($remove = false, $keepPrefix = true) + { + if ($remove === false) { + static::stdout(PHP_EOL); + } else { + if (static::streamSupportsAnsiColors(STDOUT)) { + static::clearLine(); + } + static::stdout("\r" . ($keepPrefix ? self::$_progressPrefix : '') . (is_string($remove) ? $remove : '')); } + flush(); + + self::$_progressStart = null; + self::$_progressWidth = null; + self::$_progressPrefix = ''; } } From 839650a6bdca72b9d928b4609d32b8115a068772 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 11 Dec 2013 21:17:37 +0100 Subject: [PATCH 19/55] fixed output in Console::select() --- framework/yii/helpers/BaseConsole.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/helpers/BaseConsole.php b/framework/yii/helpers/BaseConsole.php index 0b8e6be..c78ed67 100644 --- a/framework/yii/helpers/BaseConsole.php +++ b/framework/yii/helpers/BaseConsole.php @@ -766,9 +766,9 @@ class BaseConsole $input = static::stdin(); if ($input === '?') { foreach ($options as $key => $value) { - echo " $key - $value\n"; + static::output(" $key - $value"); } - echo " ? - Show help\n"; + static::output(" ? - Show help"); goto top; } elseif (!in_array($input, array_keys($options))) { goto top; From 8b7136320c2047d3021cbccddb5e804325203a0f Mon Sep 17 00:00:00 2001 From: nergal Date: Thu, 12 Dec 2013 06:47:41 +0200 Subject: [PATCH 20/55] Add extension support to yii\twig\ViewRenderer --- extensions/yii/twig/ViewRenderer.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extensions/yii/twig/ViewRenderer.php b/extensions/yii/twig/ViewRenderer.php index b1598cf..7483f04 100644 --- a/extensions/yii/twig/ViewRenderer.php +++ b/extensions/yii/twig/ViewRenderer.php @@ -28,6 +28,11 @@ class ViewRenderer extends BaseViewRenderer public $cachePath = '@runtime/Twig/cache'; /** + * @var array extentions list. + */ + public $extensions = []; + + /** * @var array Twig options * @see http://twig.sensiolabs.org/doc/api.html#environment-options */ @@ -45,6 +50,12 @@ class ViewRenderer extends BaseViewRenderer $this->twig = new \Twig_Environment($loader, array_merge([ 'cache' => Yii::getAlias($this->cachePath), ], $this->options)); + + if (!empty($this->extensions)) { + foreach ($this->extensions as $extension) { + $this->twig->addExtension(new $extension()); + } + } $this->twig->addFunction('path', new \Twig_Function_Function(function ($path, $args = []) { return Html::url(array_merge([$path], $args)); From 87291bd34b295c136601e0993760cf7b24357661 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 08:29:22 +0100 Subject: [PATCH 21/55] a note about how to not use gii related to #1482 --- docs/guide/gii.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/guide/gii.md b/docs/guide/gii.md index 525c567..b4b460e 100644 --- a/docs/guide/gii.md +++ b/docs/guide/gii.md @@ -18,8 +18,16 @@ Add these lines to your config file: How to use it ------------- +TBD + +> Note: The code generated by gii is only a template that has to be adjusted to your needs. It is there + to help you create new things quickly but it is not something that creates ready to use code. + We often see people using the models generated by gii without change and just extend them to adjust + some parts of it. This is not how it is ment to be used. Code generated by gii may be incomplete or incorrect + and has to be changed to fit your needs before you can use it. + Creating your own templates --------------------------- -TDB +TBD From ed0e76b7c0d7fce4bdec6b47a14a47c94446ca05 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 11:04:19 +0100 Subject: [PATCH 22/55] gii docs --- docs/guide/gii.md | 81 ++++++++++++++++++++++++++++++++++++-- docs/guide/images/gii-entry.png | Bin 0 -> 70592 bytes docs/guide/images/gii-preview.png | Bin 0 -> 41620 bytes 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 docs/guide/images/gii-entry.png create mode 100644 docs/guide/images/gii-preview.png diff --git a/docs/guide/gii.md b/docs/guide/gii.md index b4b460e..a95b787 100644 --- a/docs/guide/gii.md +++ b/docs/guide/gii.md @@ -7,18 +7,80 @@ as well as complete CRUD controllers. Installing and configuring -------------------------- -Add these lines to your config file: +Gii comes as an offical extension and the preferred way to install this extension is through [composer](http://getcomposer.org/download/). + +Either run + +``` +php composer.phar require yiisoft/yii2-gii "*" +``` + +or add + +``` +"yiisoft/yii2-gii": "*" +``` + +to the require section of your `composer.json` file. + +Once the extension is installed, simply add these lines to your application configuration file: ```php 'modules' => [ - 'gii' => ['yii\gii\Module'] + 'gii' => [ + 'class' => 'yii\gii\Module', + ], ] ``` +You can then access Gii through the following URL: + +``` +http://localhost/path/to/index.php?r=gii +``` + +> Note: if you are accessing gii from another IP than localhost, access will be denied by default. + You have to add allowed IPs to the configuration in this case: + ```php + 'gii' => [ + 'class' => 'yii\gii\Module', + 'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs + ], + ``` + + How to use it ------------- -TBD +When you open Gii you first see the entry page that lets you choose a generator. + +![Gii entry page](images/gii-entry.png) + +By default there are the following generators available: + +- *Model Generator* - This generator generates an ActiveRecord class for the specified database table. +- *CRUD Generator* - This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete) + operations for the specified data model. +- *Controller Generator* - This generator helps you to quickly generate a new controller class, one or several + controller actions and their corresponding views. +- *Form Generator* - This generator generates a view script file that displays a form to collect input for the + specified model class. +- *Module Generator* - This generator helps you to generate the skeleton code needed by a Yii module. + +After choosing a generator by clicking on the "Start" button you will see a form that allows you to configure the +parameters of the generator. Fill out the form according to your needs and press the "Preview" button to get a +preview of the code that gii is about to generated. Dependend on the generator you chose and whether the files +already existed or not you will get an ouput similar to what you see in the following picuture: + +![Gii preview](images/gii-preview.png) + +Clicking on the file name you can view a preview of the code that will be generated for that file. +When the file already exists, gii also provides a diff view that shows what is different between the code that exists +and the one that will be generated. In this case you can also choose which files should be overridden and which not. + +After you have reviewed the code and selected the files to be generated you can click the "Generate" button to create +the files. If all went fine you are done. When you see errors that gii is not able to generate the files you have to +adjust directory permissions so that your webserver is able to write to the directories and create the files. > Note: The code generated by gii is only a template that has to be adjusted to your needs. It is there to help you create new things quickly but it is not something that creates ready to use code. @@ -26,8 +88,21 @@ TBD some parts of it. This is not how it is ment to be used. Code generated by gii may be incomplete or incorrect and has to be changed to fit your needs before you can use it. +> Tip: To update models after database change you can copy the code from gii preview and merge the changes with + your own code. You can use IDE features like PHPStorms "compare with clipboard" for this which allows you to + merge in relevant changes and leave out others that may revert your own code. + + Creating your own templates --------------------------- +Every generator has a form field that lets you choose a template to use for code generation. +By default gii only provides one template but you can create your own templates that are adjusted to your needs. + +TBD + +Creating your own generators +---------------------------- + TBD diff --git a/docs/guide/images/gii-entry.png b/docs/guide/images/gii-entry.png new file mode 100644 index 0000000000000000000000000000000000000000..6f19a7bde30920fecc69bf6ae34bc262d2d4a70a GIT binary patch literal 70592 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 literal 0 HcmV?d00001 diff --git a/docs/guide/images/gii-preview.png b/docs/guide/images/gii-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0a7b49a4d09ea6081809d27350ad234deedc72 GIT binary patch literal 41620 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 literal 0 HcmV?d00001 From 3fba6dc3144f6d38846667d0d5f69d7eefa8dc71 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 11:14:37 +0100 Subject: [PATCH 23/55] updated gii docs --- docs/guide/gii.md | 21 ++++++++++++--------- extensions/yii/gii/views/layouts/main.php | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/guide/gii.md b/docs/guide/gii.md index a95b787..9bc0cc8 100644 --- a/docs/guide/gii.md +++ b/docs/guide/gii.md @@ -4,6 +4,7 @@ The Gii code generation tool Yii2 includes a handy tool that allows rapid prototyping by generating commonly used code snippets as well as complete CRUD controllers. + Installing and configuring -------------------------- @@ -58,14 +59,14 @@ When you open Gii you first see the entry page that lets you choose a generator. By default there are the following generators available: -- *Model Generator* - This generator generates an ActiveRecord class for the specified database table. -- *CRUD Generator* - This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete) +- **Model Generator** - This generator generates an ActiveRecord class for the specified database table. +- **CRUD Generator** - This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete) operations for the specified data model. -- *Controller Generator* - This generator helps you to quickly generate a new controller class, one or several +- **Controller Generator** - This generator helps you to quickly generate a new controller class, one or several controller actions and their corresponding views. -- *Form Generator* - This generator generates a view script file that displays a form to collect input for the +- **Form Generator** - This generator generates a view script file that displays a form to collect input for the specified model class. -- *Module Generator* - This generator helps you to generate the skeleton code needed by a Yii module. +- **Module Generator** - This generator helps you to generate the skeleton code needed by a Yii module. After choosing a generator by clicking on the "Start" button you will see a form that allows you to configure the parameters of the generator. Fill out the form according to your needs and press the "Preview" button to get a @@ -78,6 +79,11 @@ Clicking on the file name you can view a preview of the code that will be genera When the file already exists, gii also provides a diff view that shows what is different between the code that exists and the one that will be generated. In this case you can also choose which files should be overridden and which not. +> Tip: When using the Model Generator to update models after database change, you can copy the code from gii preview + and merge the changes with your own code. You can use IDE features like PHPStorms + [compare with clipboard](http://www.jetbrains.com/phpstorm/webhelp/comparing-files.html) for this, + which allows you to merge in relevant changes and leave out others that may revert your own code. + After you have reviewed the code and selected the files to be generated you can click the "Generate" button to create the files. If all went fine you are done. When you see errors that gii is not able to generate the files you have to adjust directory permissions so that your webserver is able to write to the directories and create the files. @@ -88,10 +94,6 @@ adjust directory permissions so that your webserver is able to write to the dire some parts of it. This is not how it is ment to be used. Code generated by gii may be incomplete or incorrect and has to be changed to fit your needs before you can use it. -> Tip: To update models after database change you can copy the code from gii preview and merge the changes with - your own code. You can use IDE features like PHPStorms "compare with clipboard" for this which allows you to - merge in relevant changes and leave out others that may revert your own code. - Creating your own templates --------------------------- @@ -101,6 +103,7 @@ By default gii only provides one template but you can create your own templates TBD + Creating your own generators ---------------------------- diff --git a/extensions/yii/gii/views/layouts/main.php b/extensions/yii/gii/views/layouts/main.php index 788b10c..6950668 100644 --- a/extensions/yii/gii/views/layouts/main.php +++ b/extensions/yii/gii/views/layouts/main.php @@ -29,7 +29,7 @@ echo Nav::widget([ 'options' => ['class' => 'nav navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['default/index']], - ['label' => 'Help', 'url' => 'http://www.yiiframework.com/doc/guide/topics.gii'], + ['label' => 'Help', 'url' => 'https://github.com/yiisoft/yii2/blob/master/docs/guide/gii.md'], ['label' => 'Application', 'url' => Yii::$app->homeUrl], ], ]); From 43f19e8aee0fe3d10e90f7c34d46340606e979f0 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 12:07:28 +0100 Subject: [PATCH 24/55] use andWhere() in AR::find() to work properly with default scope fixes #1469 --- extensions/yii/elasticsearch/ActiveRecord.php | 4 ++-- framework/CHANGELOG.md | 1 + framework/yii/db/ActiveRecord.php | 14 ++++++++++++++ framework/yii/db/ActiveRecordInterface.php | 14 ++++++++++++++ framework/yii/db/BaseActiveRecord.php | 4 ++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/extensions/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php index 3c8b4a8..9cc6549 100644 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ b/extensions/yii/elasticsearch/ActiveRecord.php @@ -67,7 +67,7 @@ class ActiveRecord extends BaseActiveRecord { $query = static::createQuery(); if (is_array($q)) { - if (count($q) == 1 && (array_key_exists(ActiveRecord::PRIMARY_KEY_NAME, $q))) { + if (count($q) == 1 && (array_key_exists(ActiveRecord::PRIMARY_KEY_NAME, $q)) && $query->where === null) { $pk = $q[ActiveRecord::PRIMARY_KEY_NAME]; if (is_array($pk)) { return static::mget($pk); @@ -75,7 +75,7 @@ class ActiveRecord extends BaseActiveRecord return static::get($pk); } } - return $query->where($q)->one(); + return $query->andWhere($q)->one(); } elseif ($q !== null) { return static::get($q); } diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index e1f3899..53067a2 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -8,6 +8,7 @@ Yii Framework 2 Change Log - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) +- Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) - New extension #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php index 7f7e6f3..cc67224 100644 --- a/framework/yii/db/ActiveRecord.php +++ b/framework/yii/db/ActiveRecord.php @@ -150,9 +150,23 @@ class ActiveRecord extends BaseActiveRecord /** * Creates an [[ActiveQuery]] instance. + * * 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.) + * + * You may also define default conditions that should apply to all queries unless overridden: + * + * ```php + * public static function createQuery() + * { + * return parent::createQuery()->where(['deleted' => false]); + * } + * ``` + * + * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the + * default condition. Using [[Query::where()]] will override the default condition. + * * @return ActiveQuery the newly created [[ActiveQuery]] instance. */ public static function createQuery() diff --git a/framework/yii/db/ActiveRecordInterface.php b/framework/yii/db/ActiveRecordInterface.php index 4965a26..556384b 100644 --- a/framework/yii/db/ActiveRecordInterface.php +++ b/framework/yii/db/ActiveRecordInterface.php @@ -94,9 +94,23 @@ interface ActiveRecordInterface /** * Creates an [[ActiveQueryInterface|ActiveQuery]] instance. + * * This method is called by [[find()]] to start a SELECT query. * You may override this method to return a customized query (e.g. `CustomerQuery` specified * written for querying `Customer` purpose.) + * + * You may also define default conditions that should apply to all queries unless overridden: + * + * ```php + * public static function createQuery() + * { + * return parent::createQuery()->where(['deleted' => false]); + * } + * ``` + * + * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the + * default condition. Using [[Query::where()]] will override the default condition. + * * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance. */ public static function createQuery(); diff --git a/framework/yii/db/BaseActiveRecord.php b/framework/yii/db/BaseActiveRecord.php index 01e1925..dae7134 100644 --- a/framework/yii/db/BaseActiveRecord.php +++ b/framework/yii/db/BaseActiveRecord.php @@ -114,12 +114,12 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface { $query = static::createQuery(); if (is_array($q)) { - return $query->where($q)->one(); + return $query->andWhere($q)->one(); } elseif ($q !== null) { // query by primary key $primaryKey = static::primaryKey(); if (isset($primaryKey[0])) { - return $query->where([$primaryKey[0] => $q])->one(); + return $query->andWhere([$primaryKey[0] => $q])->one(); } else { throw new InvalidConfigException(get_called_class() . ' must have a primary key.'); } From 5156cc14ce3d6c35641bf7180f7b402732621a9b Mon Sep 17 00:00:00 2001 From: egorpromo Date: Thu, 12 Dec 2013 21:41:09 +0700 Subject: [PATCH 25/55] More docs --- framework/yii/base/Component.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php index 9af22a8..9e9e852 100644 --- a/framework/yii/base/Component.php +++ b/framework/yii/base/Component.php @@ -432,7 +432,7 @@ class Component extends Object /** * Triggers an event. * This method represents the happening of an event. It invokes - * all attached handlers for the event. + * all attached handlers for the event including 'class-level' handlers * @param string $name the event name * @param Event $event the event parameter. If not set, a default [[Event]] object will be created. */ @@ -457,6 +457,7 @@ class Component extends Object } } } + //invoke 'class-level' attached handlers Event::trigger($this, $name, $event); } From 2355c764a86c5e58c68133de00c4dc15d63d928e Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 18:39:40 +0100 Subject: [PATCH 26/55] Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle --- framework/CHANGELOG.md | 1 + framework/yii/web/View.php | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 53067a2..8ca5573 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -5,6 +5,7 @@ Yii Framework 2 Change Log ---------------------------- - Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) +- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) diff --git a/framework/yii/web/View.php b/framework/yii/web/View.php index db0c500..790e4fd 100644 --- a/framework/yii/web/View.php +++ b/framework/yii/web/View.php @@ -184,10 +184,12 @@ class View extends \yii\base\View return; } $bundle = $this->assetBundles[$name]; - foreach ($bundle->depends as $dep) { - $this->registerAssetFiles($dep); + if ($bundle) { + foreach ($bundle->depends as $dep) { + $this->registerAssetFiles($dep); + } + $bundle->registerAssetFiles($this); } - $bundle->registerAssetFiles($this); unset($this->assetBundles[$name]); } From 6f0ab24e574665f054a0d47a8f36aeb95d39fac7 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 19:55:59 +0100 Subject: [PATCH 27/55] Added docs about using yii2-dev package --- docs/internals/getting-started.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/internals/getting-started.md diff --git a/docs/internals/getting-started.md b/docs/internals/getting-started.md new file mode 100644 index 0000000..bcaac07 --- /dev/null +++ b/docs/internals/getting-started.md @@ -0,0 +1,25 @@ +Getting started with Yii2 development +===================================== + +The best way to have a locally runnable webapp that uses codebase cloned from main repository is to use `yii2-dev` +Composer package. Here's how to do it: + +1. `git clone git@github.com:yiisoft/yii2-app-basic.git`. +2. Remove `.git` directory from cloned directory. +3. Change `composer.json`. Instead of all stable requirements add just one `"yiisoft/yii2-dev": "*"`. +4. Execute `composer install`. +5. Now you have working playground that uses latest code. + +If you're core developer there's no extra step needed. You can change framework code under +`vendor/yiisoft/yii2-dev` and push it to main repository. + +If you're not core developer or want to use your own fork for pull requests: + +1. Fork `https://github.com/yiisoft/yii2` and get your own repository address such as + `git://github.com/username/yii2.git`. +2. Edit `vendor/yiisoft/yii2-dev/.git/config`. Change remote `origin` url to your own: + +``` +[remote "origin"] + url = git://github.com/username/yii2.git +``` From febefe43933fdfbc0ea420d8a8e89f11db405038 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 20:41:51 +0100 Subject: [PATCH 28/55] Linked to yii2-dev docs from README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0ab29ca..d7020d9 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,5 @@ You may participate in the following ways: - Before you start, please adopt an existing issue (labelled with "ready for adoption") or start a new one to avoid duplicated efforts. - Please submit a merge request after you finish development. +In order to make it easier we've prepared [special `yii2-dev` Composer package](https://github.com/yiisoft/yii2/blob/master/docs/internals/getting-started.md). + From 9590ed75ade31b83ba1fd7c10627629bd1c419c2 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 21:26:29 +0100 Subject: [PATCH 29/55] Adjusted exception template. Background of images now matches background color of the header. --- framework/yii/views/errorHandler/exception.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/views/errorHandler/exception.php b/framework/yii/views/errorHandler/exception.php index b0d86f0..1e37401 100644 --- a/framework/yii/views/errorHandler/exception.php +++ b/framework/yii/views/errorHandler/exception.php @@ -340,13 +340,13 @@ pre .diff .change{
- Gears + Error

htmlEncode($exception->getName()) ?>addTypeLinks(get_class($exception)) ?>

- Attention + Exception

' . $handler->createHttpStatusLink($exception->statusCode, $handler->htmlEncode($exception->getName())) . ''; From a7c0505e76f88c4061f601b548141ac2329263cb Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 21:55:40 +0100 Subject: [PATCH 30/55] removed composer.lock from gitignore we should not provide one in the package but developers should commit them when starting a new project so that all share the same versions and only explicit composer update command will change that. Escpecially important when deploying to production. --- apps/advanced/.gitignore | 1 - apps/basic/.gitignore | 1 - apps/benchmark/.gitignore | 1 - 3 files changed, 3 deletions(-) delete mode 100644 apps/basic/.gitignore delete mode 100644 apps/benchmark/.gitignore diff --git a/apps/advanced/.gitignore b/apps/advanced/.gitignore index 19dfc06..447bcd3 100644 --- a/apps/advanced/.gitignore +++ b/apps/advanced/.gitignore @@ -1,2 +1 @@ /yii -/composer.lock \ No newline at end of file diff --git a/apps/basic/.gitignore b/apps/basic/.gitignore deleted file mode 100644 index 9dce4ff..0000000 --- a/apps/basic/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/composer.lock \ No newline at end of file diff --git a/apps/benchmark/.gitignore b/apps/benchmark/.gitignore deleted file mode 100644 index 9dce4ff..0000000 --- a/apps/benchmark/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/composer.lock \ No newline at end of file From 85b5c75b61cf8979631093a12b386cd8f8f2b2bf Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 12 Dec 2013 22:01:41 +0100 Subject: [PATCH 31/55] doc style --- framework/yii/base/Component.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php index 9e9e852..4cea9d2 100644 --- a/framework/yii/base/Component.php +++ b/framework/yii/base/Component.php @@ -432,7 +432,7 @@ class Component extends Object /** * Triggers an event. * This method represents the happening of an event. It invokes - * all attached handlers for the event including 'class-level' handlers + * all attached handlers for the event including class-level handlers. * @param string $name the event name * @param Event $event the event parameter. If not set, a default [[Event]] object will be created. */ @@ -457,7 +457,7 @@ class Component extends Object } } } - //invoke 'class-level' attached handlers + // invoke class-level attached handlers Event::trigger($this, $name, $event); } From 05c67f43b8491167a9cf107a44bb9a1dc9440dcc Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 22:04:24 +0100 Subject: [PATCH 32/55] Added favicons to application templates --- apps/advanced/backend/web/favicon.ico | Bin 0 -> 1150 bytes apps/advanced/frontend/web/favicon.ico | Bin 0 -> 1150 bytes apps/basic/web/favicon.ico | Bin 0 -> 1150 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/advanced/backend/web/favicon.ico create mode 100644 apps/advanced/frontend/web/favicon.ico create mode 100644 apps/basic/web/favicon.ico diff --git a/apps/advanced/backend/web/favicon.ico b/apps/advanced/backend/web/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..49e61e33ca94362545346cb218c62dc7807e9c66 GIT binary patch literal 1150 zcma)6XH1hp7(Rmu{|GtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icjtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icjtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icj Date: Thu, 12 Dec 2013 22:55:10 +0100 Subject: [PATCH 33/55] Fixes #1497 (wrong file rendered if language != sourceLanguage) --- framework/yii/helpers/BaseFileHelper.php | 2 +- tests/unit/framework/helpers/FileHelperTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php index 90d6117..36591ae 100644 --- a/framework/yii/helpers/BaseFileHelper.php +++ b/framework/yii/helpers/BaseFileHelper.php @@ -68,7 +68,7 @@ class BaseFileHelper if ($language === $sourceLanguage) { return $file; } - $desiredFile = dirname($file) . DIRECTORY_SEPARATOR . $sourceLanguage . DIRECTORY_SEPARATOR . basename($file); + $desiredFile = dirname($file) . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . basename($file); return is_file($desiredFile) ? $desiredFile : $file; } diff --git a/tests/unit/framework/helpers/FileHelperTest.php b/tests/unit/framework/helpers/FileHelperTest.php index 3b5f49e..8ad977f 100644 --- a/tests/unit/framework/helpers/FileHelperTest.php +++ b/tests/unit/framework/helpers/FileHelperTest.php @@ -313,4 +313,29 @@ class FileHelperTest extends TestCase { $this->assertEquals(DIRECTORY_SEPARATOR.'home'.DIRECTORY_SEPARATOR.'demo', FileHelper::normalizePath('/home\demo/')); } + + public function testLocalizedDirectory() + { + $this->createFileStructure([ + 'views' => [ + 'faq.php' => 'English FAQ', + 'de-DE' => [ + 'faq.php' => 'German FAQ', + ], + ], + ]); + $viewFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'faq.php'; + $sourceLanguage = 'en-US'; + + // Source language and target language are same. The view path should be unchanged. + $currentLanguage = $sourceLanguage; + $this->assertSame($viewFile, FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage)); + + // Source language and target language are different. The view path should be changed. + $currentLanguage = 'de-DE'; + $this->assertSame( + $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentLanguage . DIRECTORY_SEPARATOR . 'faq.php', + FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage) + ); + } } From 92b7f94cf75da6609391aa2784a74edd387e9cec Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Thu, 12 Dec 2013 17:28:34 -0500 Subject: [PATCH 34/55] updated change log. --- framework/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 8ca5573..a7fe028 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -5,12 +5,13 @@ Yii Framework 2 Change Log ---------------------------- - Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) +- Bug #1497: Localized view files are not correctly returned (mintao) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) -- New extension #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) +- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 --------------------------- From cedee946084592e498056968be68b947a6f1df84 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 23:31:51 +0100 Subject: [PATCH 35/55] Added robots.txt to application templates --- apps/advanced/backend/web/robots.txt | 0 apps/advanced/frontend/web/robots.txt | 0 apps/basic/web/robots.txt | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/advanced/backend/web/robots.txt create mode 100644 apps/advanced/frontend/web/robots.txt create mode 100644 apps/basic/web/robots.txt diff --git a/apps/advanced/backend/web/robots.txt b/apps/advanced/backend/web/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/apps/advanced/frontend/web/robots.txt b/apps/advanced/frontend/web/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/apps/basic/web/robots.txt b/apps/basic/web/robots.txt new file mode 100644 index 0000000..e69de29 From 4d812d460fbd43c89ed80c1eb0bd59530fdf53ae Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 23:34:36 +0100 Subject: [PATCH 36/55] Updated changelog: added line about app template addition of favicon.ico and robots.txt --- framework/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index a7fe028..9810450 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -11,6 +11,7 @@ Yii Framework 2 Change Log - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) +- Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 From 66e5be7f7f42a5f8e7f12e6c90f807477018681d Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 12 Dec 2013 23:45:54 +0100 Subject: [PATCH 37/55] Widget IDs are now always unique no matter if it's the same request or new one --- framework/CHANGELOG.md | 1 + framework/yii/base/Widget.php | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 9810450..4a78c09 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -12,6 +12,7 @@ Yii Framework 2 Change Log - Enh #1437: Added ListView::viewParams (qiangxue) - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) +- Enh: Widget IDs are now always unique no matter if it's the same request or new one (samdark) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 diff --git a/framework/yii/base/Widget.php b/framework/yii/base/Widget.php index 5e3ce2b..a45dfaf 100644 --- a/framework/yii/base/Widget.php +++ b/framework/yii/base/Widget.php @@ -25,11 +25,6 @@ use ReflectionClass; class Widget extends Component implements ViewContextInterface { /** - * @var integer a counter used to generate [[id]] for widgets. - * @internal - */ - public static $counter = 0; - /** * @var Widget[] the widgets that are currently being rendered (not ended). This property * is maintained by [[begin()]] and [[end()]] methods. * @internal @@ -101,7 +96,7 @@ class Widget extends Component implements ViewContextInterface public function getId($autoGenerate = true) { if ($autoGenerate && $this->_id === null) { - $this->_id = 'w' . self::$counter++; + $this->_id = 'w-' . str_replace('.', '-', uniqid('', true)); } return $this->_id; } From d366a959a8699ab46c341a71ddb5af4673c76e94 Mon Sep 17 00:00:00 2001 From: Alexander Kozhevnikov Date: Fri, 13 Dec 2013 12:29:30 +0300 Subject: [PATCH 38/55] Disallow indexing backend by default Backend should be always totally closed for indexing by search engine robots --- apps/advanced/backend/web/robots.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/advanced/backend/web/robots.txt b/apps/advanced/backend/web/robots.txt index e69de29..c6742d8 100644 --- a/apps/advanced/backend/web/robots.txt +++ b/apps/advanced/backend/web/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +Disallow: / From 17840dfad11927ac18c713f3ffb8e5ab58f6175d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 14 Dec 2013 00:04:11 +0100 Subject: [PATCH 39/55] added hhvm hiphop php vm to travis to run test on it http://www.hhvm.com/blog/2393/hhvm-2-3-0-and-travis-ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 11c5e5f..64ae90c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: php php: - 5.4 - 5.5 + - hhvm services: - redis-server From 1ec148a7d902088a554742ecc80901c627a983a4 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 14 Dec 2013 00:31:40 +0100 Subject: [PATCH 40/55] fixed travis timezone config --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 64ae90c..fc69964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ services: - elasticsearch before_script: + - echo 'date.timezone = "UTC"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer self-update && composer --version - composer require satooshi/php-coveralls 0.6.* --dev --prefer-dist - mysql -e 'CREATE DATABASE yiitest;'; From 7ab7cb197efc1354d23021435572f1ebab17e5a4 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 14 Dec 2013 00:37:55 +0100 Subject: [PATCH 41/55] reverted travis php config fix --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fc69964..64ae90c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ services: - elasticsearch before_script: - - echo 'date.timezone = "UTC"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer self-update && composer --version - composer require satooshi/php-coveralls 0.6.* --dev --prefer-dist - mysql -e 'CREATE DATABASE yiitest;'; From 97025771f4b16435074d365d8560b40377cbdb01 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 14 Dec 2013 01:12:20 +0100 Subject: [PATCH 42/55] commented hhvm test on travis until bugs have been fixed --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 64ae90c..127e5a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: php php: - 5.4 - 5.5 - - hhvm +# - hhvm # commented until composer or hhvm get fixed: https://github.com/facebook/hhvm/issues/1347 services: - redis-server From 63640db65ca43f3829afe3ea8c28267277e82a51 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 13 Dec 2013 21:15:43 -0500 Subject: [PATCH 43/55] Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs --- framework/CHANGELOG.md | 2 +- framework/yii/base/Widget.php | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 4a78c09..b255482 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -12,7 +12,7 @@ Yii Framework 2 Change Log - Enh #1437: Added ListView::viewParams (qiangxue) - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) -- Enh: Widget IDs are now always unique no matter if it's the same request or new one (samdark) +- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 diff --git a/framework/yii/base/Widget.php b/framework/yii/base/Widget.php index a45dfaf..16c13f7 100644 --- a/framework/yii/base/Widget.php +++ b/framework/yii/base/Widget.php @@ -25,6 +25,17 @@ use ReflectionClass; class Widget extends Component implements ViewContextInterface { /** + * @var integer a counter used to generate [[id]] for widgets. + * @internal + */ + public static $counter = 0; + /** + * @var string the prefix to the automatically generated widget IDs. + * @see [[getId()]] + */ + public static $autoIdPrefix = 'w'; + + /** * @var Widget[] the widgets that are currently being rendered (not ended). This property * is maintained by [[begin()]] and [[end()]] methods. * @internal @@ -96,7 +107,7 @@ class Widget extends Component implements ViewContextInterface public function getId($autoGenerate = true) { if ($autoGenerate && $this->_id === null) { - $this->_id = 'w-' . str_replace('.', '-', uniqid('', true)); + $this->_id = self::$autoIdPrefix . self::$counter++; } return $this->_id; } From 35c931ed400d5f15719bae8ac1eb6048bd7b875c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 13 Dec 2013 21:37:00 -0500 Subject: [PATCH 44/55] Fixes #1509: The SQL for creating Postgres RBAC tables is incorrect --- framework/CHANGELOG.md | 1 + framework/yii/rbac/schema-pgsql.sql | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index b255482..22feb9e 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -6,6 +6,7 @@ Yii Framework 2 Change Log - Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) - Bug #1497: Localized view files are not correctly returned (mintao) +- Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) diff --git a/framework/yii/rbac/schema-pgsql.sql b/framework/yii/rbac/schema-pgsql.sql index 78dbb3d..bf9865f 100644 --- a/framework/yii/rbac/schema-pgsql.sql +++ b/framework/yii/rbac/schema-pgsql.sql @@ -20,10 +20,11 @@ create table "tbl_auth_item" "description" text, "biz_rule" text, "data" text, - primary key ("name"), - key "type" ("type") + primary key ("name") ); +create index tbl_auth_item_type_idx on "tbl_auth_item" ("type"); + create table "tbl_auth_item_child" ( "parent" varchar(64) not null, From 35df318e070577899b57f6741b4967352b58e379 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 13 Dec 2013 21:55:34 -0500 Subject: [PATCH 45/55] Fixes #1500: Log messages exported to files are not separated by newlines --- framework/CHANGELOG.md | 1 + framework/yii/log/FileTarget.php | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 22feb9e..ee38ade 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -6,6 +6,7 @@ Yii Framework 2 Change Log - Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) - Bug #1497: Localized view files are not correctly returned (mintao) +- Bug #1500: Log messages exported to files are not separated by newlines (omnilight, qiangxue) - Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) diff --git a/framework/yii/log/FileTarget.php b/framework/yii/log/FileTarget.php index 5aa4c12..4382aa5 100644 --- a/framework/yii/log/FileTarget.php +++ b/framework/yii/log/FileTarget.php @@ -83,10 +83,7 @@ class FileTarget extends Target */ public function export() { - $text = ''; - foreach ($this->messages as $message) { - $text .= $this->formatMessage($message); - } + $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n"; if (($fp = @fopen($this->logFile, 'a')) === false) { throw new InvalidConfigException("Unable to append to log file: {$this->logFile}"); } From 7488caacc374d3b6768a3f9f7248d080a6e9c64b Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 14 Dec 2013 14:37:10 +0100 Subject: [PATCH 46/55] fixes #1515 --- framework/yii/widgets/LinkSorter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/widgets/LinkSorter.php b/framework/yii/widgets/LinkSorter.php index 4ed8cc0..7104c18 100644 --- a/framework/yii/widgets/LinkSorter.php +++ b/framework/yii/widgets/LinkSorter.php @@ -63,7 +63,7 @@ class LinkSorter extends Widget */ protected function renderSortLinks() { - $attributes = empty($this->atttributes) ? array_keys($this->sort->attributes) : $this->attributes; + $attributes = empty($this->attributes) ? array_keys($this->sort->attributes) : $this->attributes; $links = []; foreach ($attributes as $name) { $links[] = $this->sort->link($name); From 92b9ae382fcc2c6ef65f0c6371a600383883deb8 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Sat, 14 Dec 2013 22:22:54 +0300 Subject: [PATCH 47/55] Update BaseSecurity.php prevent call strlen function twice --- framework/yii/helpers/BaseSecurity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php index a49dd78..58fec95 100644 --- a/framework/yii/helpers/BaseSecurity.php +++ b/framework/yii/helpers/BaseSecurity.php @@ -302,7 +302,7 @@ class BaseSecurity $test = crypt($password, $hash); $n = strlen($test); - if (strlen($test) < 32 || $n !== strlen($hash)) { + if ($n < 32 || $n !== strlen($hash)) { return false; } From 87d7ffafee324bf893a369ea68898bc8b458af09 Mon Sep 17 00:00:00 2001 From: Pavel Agalecky Date: Sun, 15 Dec 2013 00:30:05 +0400 Subject: [PATCH 48/55] Added support for aliases for config files in console command 'message' --- framework/CHANGELOG.md | 1 + framework/yii/console/controllers/MessageController.php | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index ee38ade..e40fe6d 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -15,6 +15,7 @@ Yii Framework 2 Change Log - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) +- Enh: Support for file aliases in console command 'message' (omnilight) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 diff --git a/framework/yii/console/controllers/MessageController.php b/framework/yii/console/controllers/MessageController.php index 7ac1558..c580b24 100644 --- a/framework/yii/console/controllers/MessageController.php +++ b/framework/yii/console/controllers/MessageController.php @@ -43,11 +43,12 @@ class MessageController extends Controller * how to customize it to fit for your needs. After customization, * you may use this configuration file with the "extract" command. * - * @param string $filePath output file name. + * @param string $filePath output file name or alias. * @throws Exception on failure. */ public function actionConfig($filePath) { + $filePath = Yii::getAlias($filePath); if (file_exists($filePath)) { if (!$this->confirm("File '{$filePath}' already exists. Do you wish to overwrite it?")) { return; @@ -63,13 +64,14 @@ class MessageController extends Controller * This command will search through source code files and extract * messages that need to be translated in different languages. * - * @param string $configFile the path of the configuration file. + * @param string $configFile the path or alias of the configuration file. * You may use the "yii message/config" command to generate * this file and then customize it for your needs. * @throws Exception on failure. */ public function actionExtract($configFile) { + $configFile = Yii::getAlias($configFile); if (!is_file($configFile)) { throw new Exception("The configuration file does not exist: $configFile"); } From 40d18557552abc78d6ad1243f672ffd86025eba3 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 15 Dec 2013 00:53:21 +0100 Subject: [PATCH 49/55] Fixed incorrect event name for yii\jui\Spinner --- extensions/yii/jui/Spinner.php | 4 ++++ framework/CHANGELOG.md | 1 + 2 files changed, 5 insertions(+) diff --git a/extensions/yii/jui/Spinner.php b/extensions/yii/jui/Spinner.php index caf73f3..d6a5026 100644 --- a/extensions/yii/jui/Spinner.php +++ b/extensions/yii/jui/Spinner.php @@ -38,6 +38,10 @@ use yii\helpers\Html; */ class Spinner extends InputWidget { + protected $clientEventsMap = [ + 'spin' => 'spin', + ]; + /** * Renders the widget. */ diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index e40fe6d..a09910e 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -9,6 +9,7 @@ Yii Framework 2 Change Log - Bug #1500: Log messages exported to files are not separated by newlines (omnilight, qiangxue) - Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) +- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue) From 7d1c46374ec3092bd5c9dbece51fcf44293f5f54 Mon Sep 17 00:00:00 2001 From: Larry Ullman Date: Sun, 15 Dec 2013 10:36:21 -0500 Subject: [PATCH 50/55] Edited "basics" and "widgets" --- docs/guide/view.md | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/guide/view.md b/docs/guide/view.md index fdfc061..f16c31c 100644 --- a/docs/guide/view.md +++ b/docs/guide/view.md @@ -1,17 +1,15 @@ View ==== -View is an important part of MVC and is responsible for presenting data to end users. +The view component is an important part of MVC. The view acts as the interface to the application, making it responsible for presenting data to end users, displaying forms, and so forth. Basics ------ -Yii uses PHP in view templates by default so in a web application a view typically contains some HTML, `echo`, `foreach` -and such basic constructs. It may also contain widget calls. Using complex code in views is considered a bad practice. -Such code should be moved to controller or widgets. +By default, Yii uses PHP in view templates to generate content and elements. A web application view typically contains some combination of HTML, along with PHP `echo`, `foreach`, `if`, and other basic constructs. Using complex PHP code in views is considered to be bad practice. When complex logic and functionality is needed, such code should either be moved to a controller or a widget. -View is typically called from controller action like the following: +The view is typically called from controller action using the `render()` method: ```php public function actionIndex() @@ -20,28 +18,35 @@ public function actionIndex() } ``` -First argument is the view name. In context of the controller Yii will search for its views in `views/site/` where `site` -is controller ID. For details on how view name is resolved please refer to [yii\base\Controller::render] method. -Second argument is data array that contains key-value pairs. Value is available in the view as a variable named the same -as the corresponding key. +The first argument to `render()` is the name of the view to display. In the context of the controller, Yii will search for its views in `views/site/` where `site` +is the controller ID. For details on how the view name is resolved, refer to the [yii\base\Controller::render] method. -So the view for the action above should be in `views/site/index.php` and can be something like: + +The second argument to `render()` is a data array of key-value pairs. Through this array, data can be passed to the view, making the value available in the view as a variable named the same as the corresponding key. + +The view for the action above would be `views/site/index.php` and can be something like: ```php

Hello, !

``` -Instead of just scalar values you can pass anything else such as arrays or objects. +Any data type can be passed to the view, including arrays or objects. Widgets ------- -Widgets are a self-contained building blocks for your views. A widget may contain advanced logic, typically takes some -configuration and data and returns HTML. There is a good number of widgets bundled with Yii such as [active form](form.md), -breadcrumbs, menu or [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are -extensions providing additional widgets such as official one for jQueryUI components. +Widgets are self-contained building blocks for your views, a way to combine complex logic, display, and functionality into a single component. A widget: + +* May contain advanced PHP programming +* Is typically configurable +* Is often provided data to be displayed +* Returns HTML to be shown within the context of the view + +There are a good number of widgets bundled with Yii, such as [active form](form.md), +breadcrumbs, dmenu, and [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are +extensions that provide more widgets, such as the official widget for [jQueryUI](http://www.jqueryui.com) components. -In order to use widget you need to do the following: +In order to use a widget, your view file would do the following: ```php // Note that you have to "echo" the result to display it @@ -56,7 +61,7 @@ $form = \yii\widgets\ActiveForm::begin([ \yii\widgets\ActiveForm::end(); ``` -In the code above `widget` method is used for a widget that just outputs content while `begin` and `end` are used for a +In the first example in the code above, the `widget` method is used to invoke a widget that just outputs content. In the second example, `begin` and `end` are used for a widget that wraps content between method calls with its own output. In case of the form this output is the `
` tag with some properties set. From c79965ce5fe6f15aec511fba50deb1a8fdaaa4cd Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 15 Dec 2013 13:54:58 -0500 Subject: [PATCH 51/55] Renamed yii\jui\Widget::clientEventsMap to clientEventMap --- extensions/yii/jui/Slider.php | 4 ++-- extensions/yii/jui/SliderInput.php | 4 ++-- extensions/yii/jui/Spinner.php | 2 +- extensions/yii/jui/Widget.php | 6 +++--- framework/CHANGELOG.md | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/extensions/yii/jui/Slider.php b/extensions/yii/jui/Slider.php index f051b9e..b1efcce 100644 --- a/extensions/yii/jui/Slider.php +++ b/extensions/yii/jui/Slider.php @@ -26,7 +26,7 @@ use yii\helpers\Html; */ class Slider extends Widget { - protected $clientEventsMap = [ + protected $clientEventMap = [ 'change' => 'slidechange', 'create' => 'slidecreate', 'slide' => 'slide', @@ -42,4 +42,4 @@ class Slider extends Widget echo Html::tag('div', '', $this->options); $this->registerWidget('slider', SliderAsset::className()); } -} \ No newline at end of file +} diff --git a/extensions/yii/jui/SliderInput.php b/extensions/yii/jui/SliderInput.php index cc77103..8ded4e8 100644 --- a/extensions/yii/jui/SliderInput.php +++ b/extensions/yii/jui/SliderInput.php @@ -43,7 +43,7 @@ use yii\helpers\Html; */ class SliderInput extends InputWidget { - protected $clientEventsMap = [ + protected $clientEventMap = [ 'change' => 'slidechange', 'create' => 'slidecreate', 'slide' => 'slide', @@ -76,4 +76,4 @@ class SliderInput extends InputWidget $this->registerWidget('slider', SliderAsset::className()); $this->getView()->registerJs('$("#'.$inputId.'").val($("#'.$this->id.'").slider("value"));'); } -} \ No newline at end of file +} diff --git a/extensions/yii/jui/Spinner.php b/extensions/yii/jui/Spinner.php index d6a5026..d53bd3a 100644 --- a/extensions/yii/jui/Spinner.php +++ b/extensions/yii/jui/Spinner.php @@ -38,7 +38,7 @@ use yii\helpers\Html; */ class Spinner extends InputWidget { - protected $clientEventsMap = [ + protected $clientEventMap = [ 'spin' => 'spin', ]; diff --git a/extensions/yii/jui/Widget.php b/extensions/yii/jui/Widget.php index ced00fb..90bad68 100644 --- a/extensions/yii/jui/Widget.php +++ b/extensions/yii/jui/Widget.php @@ -46,7 +46,7 @@ class Widget extends \yii\base\Widget * @var array event names mapped to what should be specified in .on( * If empty, it is assumed that event passed to clientEvents is prefixed with widget name. */ - protected $clientEventsMap = []; + protected $clientEventMap = []; /** * Initializes the widget. @@ -97,8 +97,8 @@ class Widget extends \yii\base\Widget $id = $this->options['id']; $js = []; foreach ($this->clientEvents as $event => $handler) { - if (isset($this->clientEventsMap[$event])) { - $eventName = $this->clientEventsMap[$event]; + if (isset($this->clientEventMap[$event])) { + $eventName = $this->clientEventMap[$event]; } else { $eventName = $name.$event; } diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index a09910e..978bb98 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -17,6 +17,7 @@ Yii Framework 2 Change Log - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - Enh: Support for file aliases in console command 'message' (omnilight) +- Chg: Renamed yii\jui\Widget::clientEventsMap to clientEventMap (qiangxue) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) 2.0.0 alpha, December 1, 2013 From d3a450f5fdd37966326eb5bd7c8cc3b21a3ea921 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 15 Dec 2013 13:55:11 -0500 Subject: [PATCH 52/55] doc fix. --- framework/yii/base/Module.php | 4 ++-- framework/yii/behaviors/AutoTimestamp.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index 1dd243e..dcb74d2 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -166,8 +166,8 @@ abstract class Module extends Component /** * Initializes the module. * This method is called after the module is created and initialized with property values - * given in configuration. The default implementation will create a path alias using the module [[id]] - * and then call [[preloadComponents()]] to load components that are declared in [[preload]]. + * given in configuration. The default implementation will call [[preloadComponents()]] to + * load components that are declared in [[preload]]. * * If you override this method, please make sure you call the parent implementation. */ diff --git a/framework/yii/behaviors/AutoTimestamp.php b/framework/yii/behaviors/AutoTimestamp.php index 0e0844a..432527a 100644 --- a/framework/yii/behaviors/AutoTimestamp.php +++ b/framework/yii/behaviors/AutoTimestamp.php @@ -39,7 +39,7 @@ class AutoTimestamp extends Behavior /** * @var array list of attributes that are to be automatically filled with timestamps. * The array keys are the ActiveRecord events upon which the attributes are to be filled with timestamps, - * and the array values are the corresponding attribute to be updated. You can use a string to represent + * and the array values are the corresponding attribute(s) to be updated. You can use a string to represent * a single attribute, or an array to represent a list of attributes. * The default setting is to update the `create_time` attribute upon AR insertion, * and update the `update_time` attribute upon AR updating. From b79f38215780d319a8d81c280c2a3ea68a83d8b8 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 15 Dec 2013 22:13:39 +0100 Subject: [PATCH 53/55] Started docs about logger --- docs/guide/logging.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/docs/guide/logging.md b/docs/guide/logging.md index ce14742..08175b8 100644 --- a/docs/guide/logging.md +++ b/docs/guide/logging.md @@ -1,5 +1,87 @@ Logging ======= +Yii provides flexible and extensible logger that is able to handle messages according to serverity level or their type. +You may filter messages by multiple criteria and forward them to files, email, debugger etc. + +Logging basics +-------------- + +Basic logging is as simple as calling one method: + +```php +\Yii::info('Hello, I am a test log message'); +``` + +### Message category + +Additionally to the message itself message category could be specified in order to allow filtering such messages and +handing these differently. Message category is passed as a second argument of logging methods and is `application` by +default. + +### Severity levels + +There are multiple severity levels and corresponding methods available: + +- `\Yii::trace` used maily for development purpose to indicate workflow of some code. Note that it only works in + development mode when `YII_DEBUG` is set to `true`. +- `\Yii::error` used when there's unrecoverable error. +- `\Yii::warning` used when an error occured but execution can be continued. +- `\Yii::info` used to keep record of important events such as administrator logins. + +Log targets +----------- + +When one of the logging methods is called, message is passed to `\yii\log\Logger` component also accessible as +`Yii::$app->log`. Logger accumulates messages in memory and then when there are enough messages or when current +request finishes, sends them to different log targets, such as file or email. + +You may configure the targets in application configuration, like the following: + +```php +[ + 'components' => [ + 'log' => [ + 'targets' => [ + 'file' => [ + 'class' => 'yii\log\FileTarget', + 'levels' => ['trace', 'info'], + 'categories' => ['yii\*'], + ], + 'email' => [ + 'class' => 'yii\log\EmailTarget', + 'levels' => ['error', 'warning'], + 'emails' => ['admin@example.com'], + ], + ], + ], + ], +] +``` + +In the config above we are defining two log targets: file and email. In both cases we are filtering messages handles by +these targets by severity. In case of file target we're additionally filter by category. `yii\*` means all categories +starting with `yii\`. + +Each log target can have a name and can be referenced via the [[targets]] property as follows: + +```php +Yii::$app->log->targets['file']->enabled = false; +``` + +When the application ends or [[flushInterval]] is reached, Logger will call [[flush()]] to send logged messages to +different log targets, such as file, email, Web. + + +Configuring context information +------------------------------- + +Profiling +--------- + +TBD + +- [[Yii::beginProfile()]] +- [[Yii::endProfile()]] + -TDB \ No newline at end of file From 6ed8d1767cf9d00dc4efae3ee3c52e8c386a9d87 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 16 Dec 2013 10:04:32 +0100 Subject: [PATCH 54/55] Adjusted logging guide, fixed examples for email target --- docs/guide/logging.md | 11 +++++++---- framework/yii/log/Logger.php | 4 +++- framework/yii/mail/MessageInterface.php | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/guide/logging.md b/docs/guide/logging.md index 08175b8..8df457e 100644 --- a/docs/guide/logging.md +++ b/docs/guide/logging.md @@ -51,7 +51,10 @@ You may configure the targets in application configuration, like the following: 'email' => [ 'class' => 'yii\log\EmailTarget', 'levels' => ['error', 'warning'], - 'emails' => ['admin@example.com'], + 'message' => [ + 'to' => ['admin@example.com', 'developer@example.com'], + 'subject' => 'New example.com log message', + ], ], ], ], @@ -59,9 +62,9 @@ You may configure the targets in application configuration, like the following: ] ``` -In the config above we are defining two log targets: file and email. In both cases we are filtering messages handles by -these targets by severity. In case of file target we're additionally filter by category. `yii\*` means all categories -starting with `yii\`. +In the config above we are defining two log targets: [[\yii\log\FileTarget|file]] and [[\yii\log\EmailTarget|email]]. +In both cases we are filtering messages handles by these targets by severity. In case of file target we're +additionally filter by category. `yii\*` means all categories starting with `yii\`. Each log target can have a name and can be referenced via the [[targets]] property as follows: diff --git a/framework/yii/log/Logger.php b/framework/yii/log/Logger.php index f79c40f..1629b9b 100644 --- a/framework/yii/log/Logger.php +++ b/framework/yii/log/Logger.php @@ -43,7 +43,9 @@ use yii\base\InvalidConfigException; * 'email' => [ * 'class' => 'yii\log\EmailTarget', * 'levels' => ['error', 'warning'], - * 'emails' => ['admin@example.com'], + * 'message' => [ + * 'to' => 'admin@example.com', + * ], * ], * ], * ], diff --git a/framework/yii/mail/MessageInterface.php b/framework/yii/mail/MessageInterface.php index d70d40f..94cfd18 100644 --- a/framework/yii/mail/MessageInterface.php +++ b/framework/yii/mail/MessageInterface.php @@ -13,7 +13,7 @@ namespace yii\mail; * A message represents the settings and content of an email, such as the sender, recipient, * subject, body, etc. * - * Messages are sent by a [[MailerInterface||mailer]], like the following, + * Messages are sent by a [[\yii\mail\MailerInterface|mailer]], like the following, * * ~~~ * Yii::$app->mail->compose() From d3a181c6742a135469c627928872901725e3d0c4 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Mon, 16 Dec 2013 11:03:30 +0100 Subject: [PATCH 55/55] fixed controllerMap docs in Module fixes #1541 --- framework/yii/base/Module.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index dcb74d2..126791b 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -62,16 +62,16 @@ abstract class Module extends Component * @var array mapping from controller ID to controller configurations. * Each name-value pair specifies the configuration of a single controller. * A controller configuration can be either a string or an array. - * If the former, the string should be the class name or path alias of the controller. + * If the former, the string should be the fully qualified class name of the controller. * If the latter, the array must contain a 'class' element which specifies - * the controller's class name or path alias, and the rest of the name-value pairs + * the controller's fully qualified class name, and the rest of the name-value pairs * in the array are used to initialize the corresponding controller properties. For example, * * ~~~ * [ - * 'account' => '@app/controllers/UserController', + * 'account' => 'app\controllers\UserController', * 'article' => [ - * 'class' => '@app/controllers/PostController', + * 'class' => 'app\controllers\PostController', * 'pageTitle' => 'something new', * ], * ]