Browse Source

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

tags/2.0.0-beta
Paul Klimov 11 years ago
parent
commit
34f9c924b9
  1. 1
      .travis.yml
  2. 2
      README.md
  3. 1
      apps/advanced/.gitignore
  4. 5
      apps/advanced/backend/web/css/site.css
  5. BIN
      apps/advanced/backend/web/favicon.ico
  6. 2
      apps/advanced/backend/web/robots.txt
  7. 5
      apps/advanced/frontend/web/css/site.css
  8. BIN
      apps/advanced/frontend/web/favicon.ico
  9. 0
      apps/advanced/frontend/web/robots.txt
  10. 1
      apps/basic/.gitignore
  11. 5
      apps/basic/web/css/site.css
  12. BIN
      apps/basic/web/favicon.ico
  13. 0
      apps/basic/web/robots.txt
  14. 1
      apps/benchmark/.gitignore
  15. 3
      docs/guide/active-record.md
  16. 52
      docs/guide/extensions.md
  17. 92
      docs/guide/gii.md
  18. BIN
      docs/guide/images/gii-entry.png
  19. BIN
      docs/guide/images/gii-preview.png
  20. 87
      docs/guide/logging.md
  21. 39
      docs/guide/view.md
  22. 25
      docs/internals/getting-started.md
  23. 175
      docs/internals/git-workflow.md
  24. 13
      docs/internals/git.md
  25. 12
      extensions/yii/bootstrap/CHANGELOG.md
  26. 13
      extensions/yii/composer/CHANGELOG.md
  27. 8
      extensions/yii/composer/Installer.php
  28. 12
      extensions/yii/debug/CHANGELOG.md
  29. 4
      extensions/yii/elasticsearch/ActiveRecord.php
  30. 12
      extensions/yii/elasticsearch/CHANGELOG.md
  31. 12
      extensions/yii/gii/CHANGELOG.md
  32. 4
      extensions/yii/gii/generators/crud/Generator.php
  33. 2
      extensions/yii/gii/views/layouts/main.php
  34. 12
      extensions/yii/jui/CHANGELOG.md
  35. 2
      extensions/yii/jui/Slider.php
  36. 2
      extensions/yii/jui/SliderInput.php
  37. 4
      extensions/yii/jui/Spinner.php
  38. 6
      extensions/yii/jui/Widget.php
  39. 7
      extensions/yii/mongodb/CHANGELOG.md
  40. 12
      extensions/yii/redis/CHANGELOG.md
  41. 4
      extensions/yii/redis/Connection.php
  42. 12
      extensions/yii/smarty/CHANGELOG.md
  43. 12
      extensions/yii/sphinx/CHANGELOG.md
  44. 12
      extensions/yii/swiftmailer/CHANGELOG.md
  45. 12
      extensions/yii/twig/CHANGELOG.md
  46. 11
      extensions/yii/twig/ViewRenderer.php
  47. 30
      framework/CHANGELOG.md
  48. 3
      framework/yii/base/Component.php
  49. 3
      framework/yii/base/Event.php
  50. 4
      framework/yii/base/Formatter.php
  51. 6
      framework/yii/base/Model.php
  52. 12
      framework/yii/base/Module.php
  53. 8
      framework/yii/base/Widget.php
  54. 2
      framework/yii/behaviors/AutoTimestamp.php
  55. 6
      framework/yii/console/controllers/MessageController.php
  56. 14
      framework/yii/db/ActiveRecord.php
  57. 14
      framework/yii/db/ActiveRecordInterface.php
  58. 4
      framework/yii/db/BaseActiveRecord.php
  59. 1
      framework/yii/grid/DataColumn.php
  60. 175
      framework/yii/helpers/BaseConsole.php
  61. 2
      framework/yii/helpers/BaseFileHelper.php
  62. 2
      framework/yii/helpers/BaseSecurity.php
  63. 5
      framework/yii/log/FileTarget.php
  64. 4
      framework/yii/log/Logger.php
  65. 2
      framework/yii/mail/MessageInterface.php
  66. 5
      framework/yii/rbac/schema-pgsql.sql
  67. 4
      framework/yii/views/errorHandler/exception.php
  68. 52
      framework/yii/web/Session.php
  69. 12
      framework/yii/web/UrlRule.php
  70. 8
      framework/yii/web/View.php
  71. 2
      framework/yii/widgets/LinkSorter.php
  72. 25
      tests/unit/framework/helpers/FileHelperTest.php

1
.travis.yml

@ -3,6 +3,7 @@ language: php
php: php:
- 5.4 - 5.4
- 5.5 - 5.5
# - hhvm # commented until composer or hhvm get fixed: https://github.com/facebook/hhvm/issues/1347
services: services:
- redis-server - redis-server

2
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. - 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. - 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).

1
apps/advanced/.gitignore vendored

@ -1,2 +1 @@
/yii /yii
/composer.lock

5
apps/advanced/backend/web/css/site.css

@ -18,6 +18,11 @@ body {
padding: 14px 24px; padding: 14px 24px;
} }
.not-set {
color: #c55;
font-style: italic;
}
/* add sorting icons to gridview sort links */ /* add sorting icons to gridview sort links */
a.asc:after, a.desc:after { a.asc:after, a.desc:after {
position: relative; position: relative;

BIN
apps/advanced/backend/web/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

2
apps/advanced/backend/web/robots.txt

@ -0,0 +1,2 @@
User-Agent: *
Disallow: /

5
apps/advanced/frontend/web/css/site.css

@ -18,6 +18,11 @@ body {
padding: 14px 24px; padding: 14px 24px;
} }
.not-set {
color: #c55;
font-style: italic;
}
/* add sorting icons to gridview sort links */ /* add sorting icons to gridview sort links */
a.asc:after, a.desc:after { a.asc:after, a.desc:after {
position: relative; position: relative;

BIN
apps/advanced/frontend/web/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

0
apps/advanced/frontend/web/robots.txt

1
apps/basic/.gitignore vendored

@ -1 +0,0 @@
/composer.lock

5
apps/basic/web/css/site.css

@ -19,6 +19,11 @@ body {
padding: 14px 24px; padding: 14px 24px;
} }
.not-set {
color: #c55;
font-style: italic;
}
/* add sorting icons to gridview sort links */ /* add sorting icons to gridview sort links */
a.asc:after, a.desc:after { a.asc:after, a.desc:after {
position: relative; position: relative;

BIN
apps/basic/web/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

0
apps/basic/web/robots.txt

1
apps/benchmark/.gitignore vendored

@ -1 +0,0 @@
/composer.lock

3
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. For example, a customer has many orders, and an order has one customer.
Both methods take two parameters and return an [[ActiveRelation]] object: Both methods take two parameters and return an [[ActiveRelation]] object:
- `$class`: the name of the class of the related model(s). If specified without - `$class`: the name of the class of the related model(s). This should be a fully qualified class name.
a namespace, the namespace of the related model class will be taken from the declaring class.
- `$link`: the association between columns from the two tables. This should be given as an array. - `$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`, 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. while the values of the array are the names of the columns from the declaring class.

52
docs/guide/extensions.md

@ -1,4 +1,54 @@
Extending Yii Extending Yii
============= =============
TDB 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 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.
### 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
------------
- 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. 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
---------------------
- 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

92
docs/guide/gii.md

@ -4,22 +4,108 @@ The Gii code generation tool
Yii2 includes a handy tool that allows rapid prototyping by generating commonly used code snippets Yii2 includes a handy tool that allows rapid prototyping by generating commonly used code snippets
as well as complete CRUD controllers. as well as complete CRUD controllers.
Installing and configuring 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 ```php
'modules' => [ '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 How to use it
------------- -------------
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.
> 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.
> 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 Creating your own templates
--------------------------- ---------------------------
TDB 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

BIN
docs/guide/images/gii-entry.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/guide/images/gii-preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

87
docs/guide/logging.md

@ -1,5 +1,90 @@
Logging 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'],
'message' => [
'to' => ['admin@example.com', 'developer@example.com'],
'subject' => 'New example.com log message',
],
],
],
],
],
]
```
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:
```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

39
docs/guide/view.md

@ -1,17 +1,15 @@
View 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 Basics
------ ------
Yii uses PHP in view templates by default so in a web application a view typically contains some HTML, `echo`, `foreach` 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.
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.
View is typically called from controller action like the following: The view is typically called from controller action using the `render()` method:
```php ```php
public function actionIndex() 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` 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 controller ID. For details on how view name is resolved please refer to [yii\base\Controller::render] method. is the controller ID. For details on how the view name is resolved, refer to the [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.
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 ```php
<p>Hello, <?= $username ?>!</p> <p>Hello, <?= $username ?>!</p>
``` ```
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
------- -------
Widgets are a self-contained building blocks for your views. A widget may contain advanced logic, typically takes some Widgets are self-contained building blocks for your views, a way to combine complex logic, display, and functionality into a single component. A widget:
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 * May contain advanced PHP programming
extensions providing additional widgets such as official one for jQueryUI components. * 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 ```php
// Note that you have to "echo" the result to display it // Note that you have to "echo" the result to display it
@ -56,7 +61,7 @@ $form = \yii\widgets\ActiveForm::begin([
\yii\widgets\ActiveForm::end(); \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 `<form>` tag widget that wraps content between method calls with its own output. In case of the form this output is the `<form>` tag
with some properties set. with some properties set.

25
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
```

175
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
```

13
docs/internals/git.md

@ -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?

12
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.

13
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.

8
extensions/yii/composer/Installer.php

@ -135,6 +135,10 @@ class Installer extends LibraryInstaller
if (!is_file($file)) { if (!is_file($file)) {
return []; return [];
} }
// invalidate opcache of extensions.php if exists
if (function_exists('opcache_invalidate')) {
opcache_invalidate($file, true);
}
$extensions = require($file); $extensions = require($file);
$vendorDir = str_replace('\\', '/', $this->vendorDir); $vendorDir = str_replace('\\', '/', $this->vendorDir);
@ -159,6 +163,10 @@ class Installer extends LibraryInstaller
$file = $this->vendorDir . '/' . self::EXTENSION_FILE; $file = $this->vendorDir . '/' . self::EXTENSION_FILE;
$array = str_replace("'<vendor-dir>", '$vendorDir . \'', var_export($extensions, true)); $array = str_replace("'<vendor-dir>", '$vendorDir . \'', var_export($extensions, true));
file_put_contents($file, "<?php\n\n\$vendorDir = dirname(__DIR__);\n\nreturn $array;\n"); file_put_contents($file, "<?php\n\n\$vendorDir = dirname(__DIR__);\n\nreturn $array;\n");
// invalidate opcache of extensions.php if exists
if (function_exists('opcache_invalidate')) {
opcache_invalidate($file, true);
}
} }
protected function linkYiiBaseFiles() protected function linkYiiBaseFiles()

12
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.

4
extensions/yii/elasticsearch/ActiveRecord.php

@ -67,7 +67,7 @@ class ActiveRecord extends BaseActiveRecord
{ {
$query = static::createQuery(); $query = static::createQuery();
if (is_array($q)) { 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]; $pk = $q[ActiveRecord::PRIMARY_KEY_NAME];
if (is_array($pk)) { if (is_array($pk)) {
return static::mget($pk); return static::mget($pk);
@ -75,7 +75,7 @@ class ActiveRecord extends BaseActiveRecord
return static::get($pk); return static::get($pk);
} }
} }
return $query->where($q)->one(); return $query->andWhere($q)->one();
} elseif ($q !== null) { } elseif ($q !== null) {
return static::get($q); return static::get($q);
} }

12
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.

12
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.

4
extensions/yii/gii/generators/crud/Generator.php

@ -188,9 +188,9 @@ class Generator extends \yii\gii\Generator
$tableSchema = $this->getTableSchema(); $tableSchema = $this->getTableSchema();
if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) { if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) {
if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) { if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) {
return "\$form->field(\$model, '$attribute')->passwordInput();"; return "\$form->field(\$model, '$attribute')->passwordInput()";
} else { } else {
return "\$form->field(\$model, '$attribute');"; return "\$form->field(\$model, '$attribute')";
} }
} }
$column = $tableSchema->columns[$attribute]; $column = $tableSchema->columns[$attribute];

2
extensions/yii/gii/views/layouts/main.php

@ -29,7 +29,7 @@ echo Nav::widget([
'options' => ['class' => 'nav navbar-nav navbar-right'], 'options' => ['class' => 'nav navbar-nav navbar-right'],
'items' => [ 'items' => [
['label' => 'Home', 'url' => ['default/index']], ['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], ['label' => 'Application', 'url' => Yii::$app->homeUrl],
], ],
]); ]);

12
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.

2
extensions/yii/jui/Slider.php

@ -26,7 +26,7 @@ use yii\helpers\Html;
*/ */
class Slider extends Widget class Slider extends Widget
{ {
protected $clientEventsMap = [ protected $clientEventMap = [
'change' => 'slidechange', 'change' => 'slidechange',
'create' => 'slidecreate', 'create' => 'slidecreate',
'slide' => 'slide', 'slide' => 'slide',

2
extensions/yii/jui/SliderInput.php

@ -43,7 +43,7 @@ use yii\helpers\Html;
*/ */
class SliderInput extends InputWidget class SliderInput extends InputWidget
{ {
protected $clientEventsMap = [ protected $clientEventMap = [
'change' => 'slidechange', 'change' => 'slidechange',
'create' => 'slidecreate', 'create' => 'slidecreate',
'slide' => 'slide', 'slide' => 'slide',

4
extensions/yii/jui/Spinner.php

@ -38,6 +38,10 @@ use yii\helpers\Html;
*/ */
class Spinner extends InputWidget class Spinner extends InputWidget
{ {
protected $clientEventMap = [
'spin' => 'spin',
];
/** /**
* Renders the widget. * Renders the widget.
*/ */

6
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( * @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. * If empty, it is assumed that event passed to clientEvents is prefixed with widget name.
*/ */
protected $clientEventsMap = []; protected $clientEventMap = [];
/** /**
* Initializes the widget. * Initializes the widget.
@ -97,8 +97,8 @@ class Widget extends \yii\base\Widget
$id = $this->options['id']; $id = $this->options['id'];
$js = []; $js = [];
foreach ($this->clientEvents as $event => $handler) { foreach ($this->clientEvents as $event => $handler) {
if (isset($this->clientEventsMap[$event])) { if (isset($this->clientEventMap[$event])) {
$eventName = $this->clientEventsMap[$event]; $eventName = $this->clientEventMap[$event];
} else { } else {
$eventName = $name.$event; $eventName = $name.$event;
} }

7
extensions/yii/mongodb/CHANGELOG.md

@ -0,0 +1,7 @@
Yii Framework 2 mongodb extension Change Log
============================================
2.0.0 beta under development
----------------------------
- Initial release.

12
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.

4
extensions/yii/redis/Connection.php

@ -263,8 +263,8 @@ class Connection extends Component
$this->executeCommand('SELECT', [$this->database]); $this->executeCommand('SELECT', [$this->database]);
$this->initConnection(); $this->initConnection();
} else { } else {
\Yii::error("Failed to open DB connection ($connection): " . $errorNumber . ' - ' . $errorDescription, __CLASS__); \Yii::error("Failed to open redis DB connection ($connection): $errorNumber - $errorDescription", __CLASS__);
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $errorNumber . ' - ' . $errorDescription : 'Failed to open DB connection.'; $message = YII_DEBUG ? "Failed to open redis DB connection ($connection): $errorNumber - $errorDescription" : 'Failed to open DB connection.';
throw new Exception($message, $errorDescription, (int)$errorNumber); throw new Exception($message, $errorDescription, (int)$errorNumber);
} }
} }

12
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.

12
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.

12
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.

12
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.

11
extensions/yii/twig/ViewRenderer.php

@ -28,6 +28,11 @@ class ViewRenderer extends BaseViewRenderer
public $cachePath = '@runtime/Twig/cache'; public $cachePath = '@runtime/Twig/cache';
/** /**
* @var array extentions list.
*/
public $extensions = [];
/**
* @var array Twig options * @var array Twig options
* @see http://twig.sensiolabs.org/doc/api.html#environment-options * @see http://twig.sensiolabs.org/doc/api.html#environment-options
*/ */
@ -46,6 +51,12 @@ class ViewRenderer extends BaseViewRenderer
'cache' => Yii::getAlias($this->cachePath), 'cache' => Yii::getAlias($this->cachePath),
], $this->options)); ], $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 = []) { $this->twig->addFunction('path', new \Twig_Function_Function(function ($path, $args = []) {
return Html::url(array_merge([$path], $args)); return Html::url(array_merge([$path], $args));
})); }));

30
framework/CHANGELOG.md

@ -4,8 +4,38 @@ Yii Framework 2 Change Log
2.0.0 beta under development 2.0.0 beta under development
---------------------------- ----------------------------
- 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)
- 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)
- 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)
- 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 2.0.0 alpha, December 1, 2013
--------------------------- ---------------------------
- Initial release. - 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-sphinx): 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)

3
framework/yii/base/Component.php

@ -432,7 +432,7 @@ class Component extends Object
/** /**
* Triggers an event. * Triggers an event.
* This method represents the happening of an event. It invokes * 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 string $name the event name
* @param Event $event the event parameter. If not set, a default [[Event]] object will be created. * @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); Event::trigger($this, $name, $event);
} }

3
framework/yii/base/Event.php

@ -161,6 +161,9 @@ class Event extends Object
$event->name = $name; $event->name = $name;
if (is_object($class)) { if (is_object($class)) {
if ($event->sender === null) {
$event->sender = $class;
}
$class = get_class($class); $class = get_class($class);
} else { } else {
$class = ltrim($class, '\\'); $class = ltrim($class, '\\');

4
framework/yii/base/Formatter.php

@ -40,7 +40,7 @@ class Formatter extends Component
*/ */
public $datetimeFormat = 'Y/m/d h:i:s A'; 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 '<span class="not-set">(not set)</span>'.
*/ */
public $nullDisplay; public $nullDisplay;
/** /**
@ -69,7 +69,7 @@ class Formatter extends Component
$this->booleanFormat = [Yii::t('yii', 'No'), Yii::t('yii', 'Yes')]; $this->booleanFormat = [Yii::t('yii', 'No'), Yii::t('yii', 'Yes')];
} }
if ($this->nullDisplay === null) { if ($this->nullDisplay === null) {
$this->nullDisplay = Yii::t('yii', '(not set)'); $this->nullDisplay = '<span class="not-set">' . Yii::t('yii', '(not set)') . '</span>';
} }
} }

6
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()]]. * 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 * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array
* supplied by end user. * 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. * @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 == '') { if ($scope == '') {
$this->setAttributes($data); $this->setAttributes($data);
return true; return true;

12
framework/yii/base/Module.php

@ -62,16 +62,16 @@ abstract class Module extends Component
* @var array mapping from controller ID to controller configurations. * @var array mapping from controller ID to controller configurations.
* Each name-value pair specifies the configuration of a single controller. * Each name-value pair specifies the configuration of a single controller.
* A controller configuration can be either a string or an array. * 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 * 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, * in the array are used to initialize the corresponding controller properties. For example,
* *
* ~~~ * ~~~
* [ * [
* 'account' => '@app/controllers/UserController', * 'account' => 'app\controllers\UserController',
* 'article' => [ * 'article' => [
* 'class' => '@app/controllers/PostController', * 'class' => 'app\controllers\PostController',
* 'pageTitle' => 'something new', * 'pageTitle' => 'something new',
* ], * ],
* ] * ]
@ -166,8 +166,8 @@ abstract class Module extends Component
/** /**
* Initializes the module. * Initializes the module.
* This method is called after the module is created and initialized with property values * 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]] * given in configuration. The default implementation will call [[preloadComponents()]] to
* and then call [[preloadComponents()]] to load components that are declared in [[preload]]. * load components that are declared in [[preload]].
* *
* If you override this method, please make sure you call the parent implementation. * If you override this method, please make sure you call the parent implementation.
*/ */

8
framework/yii/base/Widget.php

@ -30,6 +30,12 @@ class Widget extends Component implements ViewContextInterface
*/ */
public static $counter = 0; 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 * @var Widget[] the widgets that are currently being rendered (not ended). This property
* is maintained by [[begin()]] and [[end()]] methods. * is maintained by [[begin()]] and [[end()]] methods.
* @internal * @internal
@ -101,7 +107,7 @@ class Widget extends Component implements ViewContextInterface
public function getId($autoGenerate = true) public function getId($autoGenerate = true)
{ {
if ($autoGenerate && $this->_id === null) { if ($autoGenerate && $this->_id === null) {
$this->_id = 'w' . self::$counter++; $this->_id = self::$autoIdPrefix . self::$counter++;
} }
return $this->_id; return $this->_id;
} }

2
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. * @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, * 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. * 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, * The default setting is to update the `create_time` attribute upon AR insertion,
* and update the `update_time` attribute upon AR updating. * and update the `update_time` attribute upon AR updating.

6
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, * how to customize it to fit for your needs. After customization,
* you may use this configuration file with the "extract" command. * 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. * @throws Exception on failure.
*/ */
public function actionConfig($filePath) public function actionConfig($filePath)
{ {
$filePath = Yii::getAlias($filePath);
if (file_exists($filePath)) { if (file_exists($filePath)) {
if (!$this->confirm("File '{$filePath}' already exists. Do you wish to overwrite it?")) { if (!$this->confirm("File '{$filePath}' already exists. Do you wish to overwrite it?")) {
return; return;
@ -63,13 +64,14 @@ class MessageController extends Controller
* This command will search through source code files and extract * This command will search through source code files and extract
* messages that need to be translated in different languages. * 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 * You may use the "yii message/config" command to generate
* this file and then customize it for your needs. * this file and then customize it for your needs.
* @throws Exception on failure. * @throws Exception on failure.
*/ */
public function actionExtract($configFile) public function actionExtract($configFile)
{ {
$configFile = Yii::getAlias($configFile);
if (!is_file($configFile)) { if (!is_file($configFile)) {
throw new Exception("The configuration file does not exist: $configFile"); throw new Exception("The configuration file does not exist: $configFile");
} }

14
framework/yii/db/ActiveRecord.php

@ -150,9 +150,23 @@ class ActiveRecord extends BaseActiveRecord
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
*
* This method is called by [[find()]], [[findBySql()]] to start a SELECT query. * This method is called by [[find()]], [[findBySql()]] to start a SELECT query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified * You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.) * 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. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createQuery() public static function createQuery()

14
framework/yii/db/ActiveRecordInterface.php

@ -94,9 +94,23 @@ interface ActiveRecordInterface
/** /**
* Creates an [[ActiveQueryInterface|ActiveQuery]] instance. * Creates an [[ActiveQueryInterface|ActiveQuery]] instance.
*
* This method is called by [[find()]] to start a SELECT query. * 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 * You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.) * 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. * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance.
*/ */
public static function createQuery(); public static function createQuery();

4
framework/yii/db/BaseActiveRecord.php

@ -114,12 +114,12 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
{ {
$query = static::createQuery(); $query = static::createQuery();
if (is_array($q)) { if (is_array($q)) {
return $query->where($q)->one(); return $query->andWhere($q)->one();
} elseif ($q !== null) { } elseif ($q !== null) {
// query by primary key // query by primary key
$primaryKey = static::primaryKey(); $primaryKey = static::primaryKey();
if (isset($primaryKey[0])) { if (isset($primaryKey[0])) {
return $query->where([$primaryKey[0] => $q])->one(); return $query->andWhere([$primaryKey[0] => $q])->one();
} else { } else {
throw new InvalidConfigException(get_called_class() . ' must have a primary key.'); throw new InvalidConfigException(get_called_class() . ' must have a primary key.');
} }

1
framework/yii/grid/DataColumn.php

@ -41,6 +41,7 @@ class DataColumn extends Column
public $label; public $label;
/** /**
* @var \Closure an anonymous function that returns the value to be displayed for every data model. * @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. * If this is not set, `$model[$attribute]` will be used to obtain the value.
*/ */
public $value; public $value;

175
framework/yii/helpers/BaseConsole.php

@ -618,7 +618,7 @@ class BaseConsole
* Gets input from STDIN and returns a string right-trimmed for EOLs. * 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 * @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) 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 * Asks the user for input. Ends when the user types a carriage return (PHP_EOL). Optionally, It also provides a
* prompt. * 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 * @return string the user's input
*/ */
public static function input($prompt = null) public static function input($prompt = null)
@ -766,9 +766,9 @@ class BaseConsole
$input = static::stdin(); $input = static::stdin();
if ($input === '?') { if ($input === '?') {
foreach ($options as $key => $value) { foreach ($options as $key => $value) {
echo " $key - $value\n"; static::output(" $key - $value");
} }
echo " ? - Show help\n"; static::output(" ? - Show help");
goto top; goto top;
} elseif (!in_array($input, array_keys($options))) { } elseif (!in_array($input, array_keys($options))) {
goto top; goto top;
@ -776,60 +776,147 @@ class BaseConsole
return $input; 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 $done the number of items that are completed.
* @param integer $total the total value of items that are to be done * @param integer $total the total value of items that are to be done.
* @param integer $size the size of the status bar (optional) * @param string $prefix an optional string to display before the progress bar.
* @see http://snipplr.com/view/29548/ * 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 static::updateProgress($done, $total);
if ($done > $total) { }
return;
}
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);
}
} }
if ($prefix === null) {
$now = time(); $prefix = self::$_progressPrefix;
$percent = (double)($done / $total);
$bar = floor($percent * $size);
$status = "\r[";
$status .= str_repeat("=", $bar);
if ($bar < $size) {
$status .= ">";
$status .= str_repeat(" ", $size - $bar);
} else { } else {
$status .= "="; self::$_progressPrefix = $prefix;
} }
$width -= mb_strlen($prefix);
$display = number_format($percent * 100, 0); $percent = $done / $total;
$info = sprintf("%d%% (%d/%d)", $percent * 100, $done, $total);
$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.";
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(); flush();
}
// when done, send a newline /**
if ($done == $total) { * Ends a progress bar that has been started by [[startProgress()]].
echo "\n"; *
* @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 = '';
} }
} }

2
framework/yii/helpers/BaseFileHelper.php

@ -68,7 +68,7 @@ class BaseFileHelper
if ($language === $sourceLanguage) { if ($language === $sourceLanguage) {
return $file; 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; return is_file($desiredFile) ? $desiredFile : $file;
} }

2
framework/yii/helpers/BaseSecurity.php

@ -302,7 +302,7 @@ class BaseSecurity
$test = crypt($password, $hash); $test = crypt($password, $hash);
$n = strlen($test); $n = strlen($test);
if (strlen($test) < 32 || $n !== strlen($hash)) { if ($n < 32 || $n !== strlen($hash)) {
return false; return false;
} }

5
framework/yii/log/FileTarget.php

@ -83,10 +83,7 @@ class FileTarget extends Target
*/ */
public function export() public function export()
{ {
$text = ''; $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n";
foreach ($this->messages as $message) {
$text .= $this->formatMessage($message);
}
if (($fp = @fopen($this->logFile, 'a')) === false) { if (($fp = @fopen($this->logFile, 'a')) === false) {
throw new InvalidConfigException("Unable to append to log file: {$this->logFile}"); throw new InvalidConfigException("Unable to append to log file: {$this->logFile}");
} }

4
framework/yii/log/Logger.php

@ -43,7 +43,9 @@ use yii\base\InvalidConfigException;
* 'email' => [ * 'email' => [
* 'class' => 'yii\log\EmailTarget', * 'class' => 'yii\log\EmailTarget',
* 'levels' => ['error', 'warning'], * 'levels' => ['error', 'warning'],
* 'emails' => ['admin@example.com'], * 'message' => [
* 'to' => 'admin@example.com',
* ],
* ], * ],
* ], * ],
* ], * ],

2
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, * A message represents the settings and content of an email, such as the sender, recipient,
* subject, body, etc. * 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() * Yii::$app->mail->compose()

5
framework/yii/rbac/schema-pgsql.sql

@ -20,10 +20,11 @@ create table "tbl_auth_item"
"description" text, "description" text,
"biz_rule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("name"), primary key ("name")
key "type" ("type")
); );
create index tbl_auth_item_type_idx on "tbl_auth_item" ("type");
create table "tbl_auth_item_child" create table "tbl_auth_item_child"
( (
"parent" varchar(64) not null, "parent" varchar(64) not null,

4
framework/yii/views/errorHandler/exception.php

File diff suppressed because one or more lines are too long

52
framework/yii/web/Session.php

@ -112,43 +112,36 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
return false; return false;
} }
private $_opened = false;
/** /**
* Starts the session. * Starts the session.
*/ */
public function open() public function open()
{ {
if (session_status() == PHP_SESSION_ACTIVE) { if (session_status() == PHP_SESSION_ACTIVE) {
$this->_opened = true;
return; return;
} }
if (!$this->_opened) { if ($this->getUseCustomStorage()) {
if ($this->getUseCustomStorage()) { @session_set_save_handler(
@session_set_save_handler( [$this, 'openSession'],
[$this, 'openSession'], [$this, 'closeSession'],
[$this, 'closeSession'], [$this, 'readSession'],
[$this, 'readSession'], [$this, 'writeSession'],
[$this, 'writeSession'], [$this, 'destroySession'],
[$this, 'destroySession'], [$this, 'gcSession']
[$this, 'gcSession'] );
); }
}
$this->setCookieParamsInternal(); $this->setCookieParamsInternal();
@session_start(); @session_start();
if (session_id() == '') { if (session_id() == '') {
$this->_opened = false; $error = error_get_last();
$error = error_get_last(); $message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
$message = isset($error['message']) ? $error['message'] : 'Failed to start session.'; Yii::error($message, __METHOD__);
Yii::error($message, __METHOD__); } else {
} else { $this->updateFlashCounters();
$this->_opened = true;
$this->updateFlashCounters();
}
} }
} }
@ -157,7 +150,6 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
*/ */
public function close() public function close()
{ {
$this->_opened = false;
if (session_id() !== '') { if (session_id() !== '') {
@session_write_close(); @session_write_close();
} }
@ -179,13 +171,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
*/ */
public function getIsActive() public function getIsActive()
{ {
if (function_exists('session_status')) { return session_status() == PHP_SESSION_ACTIVE;
// available in PHP 5.4.0+
return session_status() == PHP_SESSION_ACTIVE;
} else {
// this is not very reliable
return $this->_opened && session_id() !== '';
}
} }
/** /**

12
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)) { if (preg_match_all('/<(\w+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) { foreach ($matches as $match) {
$name = $match[1][0]; $name = $match[1][0];
@ -166,7 +175,6 @@ class UrlRule extends Object
} }
} }
} }
$tr['.'] = '\\.';
$this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern); $this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern);
$this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u'; $this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u';

8
framework/yii/web/View.php

@ -184,10 +184,12 @@ class View extends \yii\base\View
return; return;
} }
$bundle = $this->assetBundles[$name]; $bundle = $this->assetBundles[$name];
foreach ($bundle->depends as $dep) { if ($bundle) {
$this->registerAssetFiles($dep); foreach ($bundle->depends as $dep) {
$this->registerAssetFiles($dep);
}
$bundle->registerAssetFiles($this);
} }
$bundle->registerAssetFiles($this);
unset($this->assetBundles[$name]); unset($this->assetBundles[$name]);
} }

2
framework/yii/widgets/LinkSorter.php

@ -63,7 +63,7 @@ class LinkSorter extends Widget
*/ */
protected function renderSortLinks() 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 = []; $links = [];
foreach ($attributes as $name) { foreach ($attributes as $name) {
$links[] = $this->sort->link($name); $links[] = $this->sort->link($name);

25
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/')); $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)
);
}
} }

Loading…
Cancel
Save