Commit 433ffb2e by Paul Klimov

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

parents 18af6984 22439d33
...@@ -7,42 +7,60 @@ ...@@ -7,42 +7,60 @@
namespace frontend\widgets; namespace frontend\widgets;
use yii\helpers\Html;
/** /**
* Alert widget renders a message from session flash. You can set message as following: * Alert widget renders a message from session flash. All flash messages are displayed
* in the sequence they were assigned using setFlash. You can set message as following:
* *
* - \Yii::$app->getSession()->setFlash('error', 'This is the message'); * - \Yii::$app->getSession()->setFlash('error', 'This is the message');
* - \Yii::$app->getSession()->setFlash('success', 'This is the message'); * - \Yii::$app->getSession()->setFlash('success', 'This is the message');
* - \Yii::$app->getSession()->setFlash('info', 'This is the message'); * - \Yii::$app->getSession()->setFlash('info', 'This is the message');
* *
* @author Kartik Visweswaran <kartikv2@gmail.com>
* @author Alexander Makarov <sam@rmcerative.ru> * @author Alexander Makarov <sam@rmcerative.ru>
*/ */
class Alert extends \yii\bootstrap\Alert class Alert extends \yii\bootstrap\Widget
{ {
private $_doNotRender = false; /**
* @var array the alert types configuration for the flash messages.
* This array is setup as $key => $value, where:
* - $key is the name of the session flash variable
* - $value is the bootstrap alert type (i.e. danger, success, info, warning)
*/
public $alertTypes = [
'error' => 'danger',
'danger' => 'danger',
'success' => 'success',
'info' => 'info',
'warning' => 'warning'
];
/**
* @var array the options for rendering the close button tag.
*/
public $closeButton = [];
public function init() public function init()
{ {
if ($this->body = \Yii::$app->getSession()->getFlash('error', null, true)) {
Html::addCssClass($this->options, 'alert-danger');
} elseif ($this->body = \Yii::$app->getSession()->getFlash('success', null, true)) {
Html::addCssClass($this->options, 'alert-success');
} elseif ($this->body = \Yii::$app->getSession()->getFlash('info', null, true)) {
Html::addCssClass($this->options, 'alert-info');
} elseif ($this->body = \Yii::$app->getSession()->getFlash('warning', null, true)) {
Html::addCssClass($this->options, 'alert-warning');
} else {
$this->_doNotRender = true;
return;
}
parent::init(); parent::init();
}
public function run() $session = \Yii::$app->getSession();
{ $flashes = $session->getAllFlashes();
if (!$this->_doNotRender) { $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
parent::run();
foreach ($flashes as $type => $message) {
/* initialize css class for each alert box */
$this->options['class'] = 'alert-' . $this->alertTypes[$type] . $appendCss;
/* assign unique id to each alert box */
$this->options['id'] = $this->getId() . '-' . $type;
echo \yii\bootstrap\Alert::widget([
'body' => $message,
'closeButton' => $this->closeButton,
'options' => $this->options
]);
$session->removeFlash($type);
} }
} }
} }
...@@ -26,14 +26,14 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface ...@@ -26,14 +26,14 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
public static function findIdentity($id) public static function findIdentity($id)
{ {
return isset(self::$users[$id]) ? new self(self::$users[$id]) : null; return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
} }
public static function findByUsername($username) public static function findByUsername($username)
{ {
foreach (self::$users as $user) { foreach (self::$users as $user) {
if (strcasecmp($user['username'], $username) === 0) { if (strcasecmp($user['username'], $username) === 0) {
return new self($user); return new static($user);
} }
} }
return null; return null;
......
...@@ -121,7 +121,7 @@ Configuring Composer ...@@ -121,7 +121,7 @@ Configuring Composer
After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root
directory: directory:
```javascript ```json
{ {
"name": "yiisoft/yii2-app-advanced", "name": "yiisoft/yii2-app-advanced",
"description": "Yii 2 Advanced Application Template", "description": "Yii 2 Advanced Application Template",
...@@ -140,7 +140,10 @@ directory: ...@@ -140,7 +140,10 @@ directory:
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"yiisoft/yii2": "dev-master", "yiisoft/yii2": "dev-master",
"yiisoft/yii2-composer": "dev-master" "yiisoft/yii2-swiftmailer": "dev-master",
"yiisoft/yii2-bootstrap": "dev-master",
"yiisoft/yii2-debug": "dev-master",
"yiisoft/yii2-gii": "dev-master"
}, },
"scripts": { "scripts": {
"post-create-project-cmd": [ "post-create-project-cmd": [
...@@ -160,15 +163,13 @@ directory: ...@@ -160,15 +163,13 @@ directory:
] ]
} }
} }
``` ```
First we're updating basic information. Change `name`, `description`, `keywords`, `homepage` and `support` to match First we're updating basic information. Change `name`, `description`, `keywords`, `homepage` and `support` to match
your project. your project.
Now the interesting part. You can add more packages your application needs to `require` section. Now the interesting part. You can add more packages your application needs to `require` section.
For example, to use markdown helper you need to add `michelf/php-markdown`. All these packages are coming from All these packages are coming from [packagist.org](https://packagist.org/) so feel free to browse the website for useful code.
[packagist.org](https://packagist.org/) so feel free to browse the website for useful code.
After your `composer.json` is changed you can run `php composer.phar update`, wait till packages are downloaded and After your `composer.json` is changed you can run `php composer.phar update`, wait till packages are downloaded and
installed and then just use them. Autoloading of classes will be handled automatically. installed and then just use them. Autoloading of classes will be handled automatically.
...@@ -30,6 +30,9 @@ Directory structure ...@@ -30,6 +30,9 @@ Directory structure
The basic application does not divide application directories much. Here's the basic structure: The basic application does not divide application directories much. Here's the basic structure:
- `assets` - application asset files.
- `AppAsset.php` - definition of application assets such as CSS, JavaScript etc. Check [Managing assets](assets.md) for
details.
- `commands` - console controllers. - `commands` - console controllers.
- `config` - configuration. - `config` - configuration.
- `controllers` - web controllers. - `controllers` - web controllers.
...@@ -56,14 +59,12 @@ code repository, add it there. ...@@ -56,14 +59,12 @@ code repository, add it there.
This directory contains configuration files: This directory contains configuration files:
- `AppAsset.php` - definition of application assets such as CSS, JavaScript etc. Check [Managing assets](assets.md) for
details.
- `console.php` - console application configuration. - `console.php` - console application configuration.
- `params.php` - common application parameters. - `params.php` - common application parameters.
- `web.php` - web application configuration. - `web.php` - web application configuration.
- `web-test.php` - web application configuration used when running functional tests. - `web-test.php` - web application configuration used when running functional tests.
All these files except `AppAsset.php` are returning arrays used to configure corresponding application properties. Check All these files are returning arrays used to configure corresponding application properties. Check
[Configuration](configuration.md) guide section for details. [Configuration](configuration.md) guide section for details.
### views ### views
...@@ -111,7 +112,7 @@ Configuring Composer ...@@ -111,7 +112,7 @@ Configuring Composer
After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root
directory: directory:
```javascript ```json
{ {
"name": "yiisoft/yii2-app-basic", "name": "yiisoft/yii2-app-basic",
"description": "Yii 2 Basic Application Template", "description": "Yii 2 Basic Application Template",
...@@ -130,7 +131,10 @@ directory: ...@@ -130,7 +131,10 @@ directory:
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"yiisoft/yii2": "dev-master", "yiisoft/yii2": "dev-master",
"yiisoft/yii2-composer": "dev-master" "yiisoft/yii2-swiftmailer": "dev-master",
"yiisoft/yii2-bootstrap": "dev-master",
"yiisoft/yii2-debug": "dev-master",
"yiisoft/yii2-gii": "dev-master"
}, },
"scripts": { "scripts": {
"post-create-project-cmd": [ "post-create-project-cmd": [
...@@ -153,8 +157,7 @@ First we're updating basic information. Change `name`, `description`, `keywords` ...@@ -153,8 +157,7 @@ First we're updating basic information. Change `name`, `description`, `keywords`
your project. your project.
Now the interesting part. You can add more packages your application needs to `require` section. Now the interesting part. You can add more packages your application needs to `require` section.
For example, to use markdown helper you need to add `michelf/php-markdown`. All these packages are coming from All these packages are coming from [packagist.org](https://packagist.org/) so feel free to browse the website for useful code.
[packagist.org](https://packagist.org/) so feel free to browse the website for useful code.
After your `composer.json` is changed you can run `php composer.phar update`, wait till packages are downloaded and After your `composer.json` is changed you can run `php composer.phar update`, wait till packages are downloaded and
installed and then just use them. Autoloading of classes will be handled automatically. installed and then just use them. Autoloading of classes will be handled automatically.
Creating your own Application structure
=======================================
TDB
\ No newline at end of file
Managing assets
===============
An asset in Yii is a file that is included into the page. It could be CSS, JavaScript or
any other file. Framework provides many ways to work with assets from basics such as adding `<script src="` tag
for a file that is [handled by View](view.md) section to advanced usage such as pusblishing files that are not
under webserve document root, resolving JavaScript dependencies or minifying CSS.
Declaring asset bundle
----------------------
In order to publish some assets you should declare an asset bundle first. The bundle defines a set of asset files or
directories to be published and their dependencies on other asset bundles.
Both basic and advanced application templates contain `AppAsset` asset bundle class that defines assets required
applicationwide. Let's review basic application asset bundle class:
```php
class AppAsset extends AssetBundle
{
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.css',
];
public $js = [
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
```
In the above `$basePath` specifies web-accessible directory assets are served from. It is a base for relative
`$css` and `$js` paths i.e. `@webroot/css/site.css` for `css/site.css`. Here `@webroot` is an alias that points to
application's `web` directory.
`$baseUrl` is used to specify base URL for the same relative `$css` and `$js` i.e. `@web/css/site.css` where `@web`
is an alias that corresponds to your website base URL such as `http://example.com/`.
In case you have asset files under non web accessible directory, that is the case for any extension, you need
to additionally specify `$sourcePath`. Files will be copied or symlinked from source bath to base path prior to being
registered. In case source path is used `baseUrl` is generated automatically at the time of publising asset bundle.
Dependencies on other asset bundles are specified via `$depends` property. It is an array that contains fully qualified
names of bundle classes that should be published in order for this bundle to work properly.
Here `yii\web\YiiAsset` adds Yii's JavaScript library while `yii\bootstrap\BootstrapAsset` includes
[Bootstrap](http://getbootstrap.com) frontend framework.
Asset bundles are regular classes so if you need to define another one, just create alike class with unique name. This
class can be placed anywhere but the convention for it is to be under `assets` directory of the applicaiton.
Registering asset bundle
------------------------
Asset bundle classes are typically registered in views or, if it's main application asset, in layout. Doing it is
as simple as:
```php
use app\assets\AppAsset;
AppAsset::register($this);
```
Since we're in a view context `$this` refers to `View` class.
Overriding asset bundles
------------------------
Sometimes you need to override some asset bundles application wide. A good example is loading jQuery from CDN instead
of your own server. In order to do it we need to configure `assetManager` application component via config file. In case
of basic application it is `config/web.php`:
```php
return [
// ...
'components' => [
'assetManager' => [
'bundles' => [
'yii\web\JqueryAsset' => [
'sourcePath' => null,
'js' => ['//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js']
],
],
],
],
];
```
In the above we're adding asset bundle definitions to `bunldes` property of asset manager. Keys there are fully
qualified class paths to asset bundle classes we want to override while values are key-value arrays of class properties
and corresponding values to set.
Setting `sourcePath` to `null` tells asset manager not to copy anything while `js` overrides local files with a link
to CDN.
Enabling symlinks
-----------------
Asset manager is able to use symlinks instead of copying files. It is turned off by default since symlinks are often
disabled on shared hosting. If your hosting environment supports symlinks you certainly should enable the feature via
application config:
```php
return [
// ...
'components' => [
'assetManager' => [
'linkAssets' => true,
],
],
];
```
There are two main benefits in enabling it. First it is faster since no copying is required and second is that assets
will always be up to date with source files.
\ No newline at end of file
Basic concepts of Yii
=====================
Component and Object
--------------------
Classes of the Yii framework usually extend from one of the two base classes [[Object]] and [[Component]].
These classes provide useful features that are added automatically to all classes extending from them.
The `Object` class provides the [configuration and property feature](../api/base/Object.md).
The `Component` class extends from `Object` and adds [event handling](events.md) and [behaviors](behaviors.md).
`Object` is usually used for classes that represent basic data structures while `Component` is used for
application components and other classes that implement higher logic.
Object Configuration
--------------------
The [[Object]] class introduces a uniform way of configuring objects. Any descendant class
of [[Object]] should declare its constructor (if needed) in the following way so that
it can be properly configured:
```php
class MyClass extends \yii\base\Object
{
public function __construct($param1, $param2, $config = [])
{
// ... initialization before configuration is applied
parent::__construct($config);
}
public function init()
{
parent::init();
// ... initialization after configuration is applied
}
}
```
In the above, the last parameter of the constructor must take a configuration array
which contains name-value pairs for initializing the properties at the end of the constructor.
You can override the `init()` method to do initialization work that should be done after
the configuration is applied.
By following this convention, you will be able to create and configure a new object
using a configuration array like the following:
```php
$object = Yii::createObject([
'class' => 'MyClass',
'property1' => 'abc',
'property2' => 'cde',
], $param1, $param2);
```
Path Aliases
------------
Yii 2.0 expands the usage of path aliases to both file/directory paths and URLs. An alias
must start with a `@` character so that it can be differentiated from file/directory paths and URLs.
For example, the alias `@yii` refers to the Yii installation directory. Path aliases are
supported in most places in the Yii core code. For example, `FileCache::cachePath` can take
both a path alias and a normal directory path.
Path alias is also closely related with class namespaces. It is recommended that a path
alias be defined for each root namespace so that you can use Yii the class autoloader without
any further configuration. For example, because `@yii` refers to the Yii installation directory,
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation
directory and Yii will be able to autoload any class in this library.
Autoloading
-----------
TBD
Helper classes
--------------
TDB
\ No newline at end of file
Behaviors
=========
TDB
\ No newline at end of file
...@@ -45,3 +45,22 @@ framework features. All widgets belong to `\yii\bootstrap` namespace: ...@@ -45,3 +45,22 @@ framework features. All widgets belong to `\yii\bootstrap` namespace:
- NavBar - NavBar
- Progress - Progress
- Tabs - Tabs
Using the .less files of Bootstrap directly
-------------------------------------------
If you want to include the [Bootstrap css directly in your less files](http://getbootstrap.com/getting-started/#customizing)
you may need to disable the original bootstrap css files to be loaded.
You can do this by setting the css property of the `BootstrapAsset` to be empty.
For this you need to configure the `assetManagner` application component as follows:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap\BootstrapAsset' => [
'css' => [],
]
]
]
```
...@@ -21,8 +21,8 @@ curl -s http://getcomposer.org/installer | php ...@@ -21,8 +21,8 @@ curl -s http://getcomposer.org/installer | php
Adding more packages to your project Adding more packages to your project
------------------------------------ ------------------------------------
The act of [installing a Yii application](installing.md) creates the `composer.json` file in the root directory of your project. The act of [installing a Yii application](installation.md) creates the `composer.json` file in the root directory of your project.
In this file you list the packages that your application requires. For Yii sites, the most important part of the file is `require` the section: In this file you list the packages that your application requires. For Yii sites, the most important part of the file is the `require` section:
``` ```
{ {
...@@ -33,19 +33,23 @@ In this file you list the packages that your application requires. For Yii sites ...@@ -33,19 +33,23 @@ In this file you list the packages that your application requires. For Yii sites
} }
``` ```
Within the `require` section, you specify the name and version of each required package. The above example says that a version greater than or equal to 1.3 of Michaelf's PHP-Markdown package is required, as is version 4.5 or greater of Ezyang's HTMLPurifier. For details of this syntax, see the [official Composer documentation](http://getcomposer.org). Within the `require` section, you specify the name and version of each required package.
The above example says that a version greater than or equal to 1.3 of Michaelf's PHP-Markdown package is required,
as is version 4.5 or greater of Ezyang's HTMLPurifier.
For details of this syntax, see the [official Composer documentation](http://getcomposer.org).
The full list of available Composer-supported PHP packages can be found at [packagist](http://packagist.org/). Any Yii extension can also be explicitly named using the syntax: The full list of available Composer-supported PHP packages can be found at [packagist](http://packagist.org/).
??? Once you have edited the `composer.json`, you can invoke Composer to install the identified dependencies.
For the first installation of the dependencies, use this command:
Once you have edited the `composer.json`, you can invoke Composer to install the identified dependencies. For the first installation of the dependencies, use this command:
``` ```
php composer.phar install php composer.phar install
``` ```
This must be executed within your Yii project's directory, where the `composer.json` file can be found. Depending upon your operating system and setup, you may need to provide paths to the PHP executable and to the `composer.phar` script. This must be executed within your Yii project's directory, where the `composer.json` file can be found.
Depending upon your operating system and setup, you may need to provide paths to the PHP executable and
to the `composer.phar` script.
For an existing installation, you can have Composer update the dependencies using: For an existing installation, you can have Composer update the dependencies using:
...@@ -55,7 +59,8 @@ php composer.phar update ...@@ -55,7 +59,8 @@ php composer.phar update
Again, you may need to provide specific path references. Again, you may need to provide specific path references.
In both cases, after some waiting, the required packages will be installed and ready to use in your Yii application. No additional configuration of those packages will be required. In both cases, after some waiting, the required packages will be installed and ready to use in your Yii application.
No additional configuration of those packages will be required.
FAQ FAQ
......
Configuration Configuration
============= =============
Yii applications rely upon components to perform most of the common tasks, such as connecting to a database, routing browser requests, and handling sessions. How these stock components behave can be adjusted by *configuring* your Yii application. The majority of components have sensible defaults, so it's unlikely that you'll spend a lot of time configuring Yii applications rely upon components to perform most of the common tasks, such as connecting to a database, routing browser
requests, and handling sessions. How these stock components behave can be adjusted by *configuring* your Yii application.
The majority of components have sensible defaults, so it's unlikely that you'll spend a lot of time configuring
them. Still there are some mandatory settings, such as the database connection, that you will have to establish. them. Still there are some mandatory settings, such as the database connection, that you will have to establish.
How application is configured depends on application template but there are some general principles applying in any case. How an application is configured depends on application template but there are some general principles applying in any case.
Configuring options in bootstrap file Configuring options in bootstrap file
------------------------------------- -------------------------------------
...@@ -14,18 +16,18 @@ console applications it's `yii`. Both are doing nearly the same job: ...@@ -14,18 +16,18 @@ console applications it's `yii`. Both are doing nearly the same job:
1. Setting common constants. 1. Setting common constants.
2. Including Yii itself. 2. Including Yii itself.
3. Including Composer autoloader. 3. Including [Composer autoloader](http://getcomposer.org/doc/01-basic-usage.md#autoloading).
4. Reading config file into `$config`. 4. Reading config file into `$config`.
5. Creating new application instance using `$config` and running it. 5. Creating new application instance using `$config` and running it.
Bootstrap file is not the part of framework but your application so it's OK to adjust it to fit your application. Typical The Bootstrap file is not the part of framework but your application so it's OK to adjust it to fit your application. Typical
adjustments are the value of `YII_DEBUG` that should never be `true` on production and the way config is read. adjustments are the value of `YII_DEBUG` that should never be `true` on production and the way config is read.
Configuring application instance Configuring application instance
-------------------------------- --------------------------------
It was mentioned above that application is configured in bootstrap file when its instance is created. Config is typically It was mentioned above that application is configured in bootstrap file when its instance is created. Config is typically
stored in a PHP file in `/config` directory of the application and looks like the following: stored in a PHP file in the `/config` directory of the application and looks like the following:
```php ```php
<?php <?php
...@@ -33,18 +35,19 @@ return [ ...@@ -33,18 +35,19 @@ return [
'id' => 'applicationId', 'id' => 'applicationId',
'basePath' => dirname(__DIR__), 'basePath' => dirname(__DIR__),
'components' => [ 'components' => [
// ... // configuration of application components goes here...
], ],
'params' => require(__DIR__ . '/params.php'), 'params' => require(__DIR__ . '/params.php'),
]; ];
``` ```
In the above array keys are names of application properties. Depending on application type you can check properties of In the above array keys are names of application properties. Depending on application type you can check properties of
either `\yii\web\Application` or `\yii\console\Application`. Both are extended from `\yii\base\Application`. either [[yii\web\Application]] or [[yii\console\Application]]. Both are extended from [[yii\base\Application]].
> Note that you can configure not only public class properties but anything accessible via setter. For example, to > Note that you can configure not only public class properties but anything accessible via setter. For example, to
configure runtime path you can use key named `runtimePath`. There's no such property in the application class but configure runtime path you can use key named `runtimePath`. There's no such property in the application class but
since there's a corresponding setter named `setRuntimePath` it will be properly configured. since there's a corresponding setter named `setRuntimePath` it will be properly configured.
This feature is added to any class that extends from [[yii\base\Object]] which is nearly any class of the Yii framework.
Configuring application components Configuring application components
---------------------------------- ----------------------------------
...@@ -76,11 +79,11 @@ return [ ...@@ -76,11 +79,11 @@ return [
In the above four components are configured: `cache`, `user`, `errorHandler`, `log`. Each entry key is a component ID In the above four components are configured: `cache`, `user`, `errorHandler`, `log`. Each entry key is a component ID
and the value is the configuration array. ID is used to access the component like `\Yii::$app->myComponent`. and the value is the configuration array. ID is used to access the component like `\Yii::$app->myComponent`.
Configuration array has one special key named `class` that sets component class. The rest of the keys and values are used Configuration array has one special key named `class` that sets the component class. The rest of the keys and values are used
to configure component properties in the same way as top-level keys are used to configure application properties. to configure component properties in the same way as top-level keys are used to configure application properties.
Each application has predefined set of the components. In case of configuring one of these `class` key is omitted and Each application has a predefined set of components. In case of configuring one of these, the `class` key is omitted and
application default class is used instead. You can check `registerCoreComponents` method of the application you are using application default class is used instead. You can check `registerCoreComponents()` method of the application you are using
to get a list of component IDs and corresponding classes. to get a list of component IDs and corresponding classes.
Note that Yii is smart enough to configure the component when it's actually used i.e. if `cache` is never used it will Note that Yii is smart enough to configure the component when it's actually used i.e. if `cache` is never used it will
......
Building console applications
=============================
TDB
\ No newline at end of file
...@@ -177,12 +177,36 @@ public SiteController extends \yii\web\Controller ...@@ -177,12 +177,36 @@ public SiteController extends \yii\web\Controller
After doing so you can access your action as `http://example.com/?r=site/about`. After doing so you can access your action as `http://example.com/?r=site/about`.
Filters
------- Action Filters
--------------
Action filters are implemented via behaviors. You should extend from `ActionFilter` to
define a new filter. To use a filter, you should attach the filter class to the controller
as a behavior. For example, to use the `AccessControl` filter, you should have the following
code in a controller:
```php
public function behaviors()
{
return [
'access' => [
'class' => 'yii\web\AccessControl',
'rules' => [
['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
),
),
);
}
```
more TDB
Catching all incoming requests Catching all incoming requests
------------------------------ ------------------------------
TDB
See also See also
-------- --------
......
...@@ -5,6 +5,7 @@ Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/m ...@@ -5,6 +5,7 @@ Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/m
uniform API and solves some inconsistencies between different DBMS. By default Yii supports the following DBMS: uniform API and solves some inconsistencies between different DBMS. By default Yii supports the following DBMS:
- [MySQL](http://www.mysql.com/) - [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/) - [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/) - [PostgreSQL](http://www.postgresql.org/)
- [CUBRID](http://www.cubrid.org/) (version 9.1.0 and higher). - [CUBRID](http://www.cubrid.org/) (version 9.1.0 and higher).
......
...@@ -5,3 +5,52 @@ Error handling in Yii is different from plain PHP. First of all, all non-fatal e ...@@ -5,3 +5,52 @@ Error handling in Yii is different from plain PHP. First of all, all non-fatal e
you can use `try`-`catch` to work with these. Second, even fatal errors are rendered in a nice way. In debug mode that you can use `try`-`catch` to work with these. Second, even fatal errors are rendered in a nice way. In debug mode that
means you have a trace and a piece of code where it happened so it takes less time to analyze and fix it. means you have a trace and a piece of code where it happened so it takes less time to analyze and fix it.
Using controller action to render errors
----------------------------------------
Default Yii error page is great for development mode and is OK for production if `YII_DEBUG` is turned off but you may
have an idea how to make it more suitable for your project. An easiest way to customize it is to use controller action
for error rendering. In order to do so you need to configure `errorHandler` component via application config:
```php
return [
// ...
'components' => [
// ...
'errorHandler' => [
'errorAction' => 'site/error',
],
```
After it is done in case of error Yii will launch `SiteController::actionError()`. Since errors are converted to
exceptions we can get exception from error handler:
```php
public function actionError()
{
$exception = \Yii::$app->getErrorHandler()->exception;
$this->render('myerror', ['message' => $exception->getMessage()]);
}
```
Since most of the time you need to adjust look and feel only, Yii provides `ErrorAction` class that can be used in
controller instead of implementing action yourself:
```php
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
];
}
```
After defining `actions` in `SiteController` as shown above you can create `views/site/error.php`. In the view there
are three varialbes available:
- `$name`: the error name
- `$message`: the error message
- `$exception`: the exception being handled
Events
======
TBD, see also [Component.md](../api/base/Component.md).
There is no longer the need to define an `on`-method in order to define an event in Yii 2.0.
Instead, you can use whatever event names. To attach a handler to an event, you should
use the `on` method now:
```php
$component->on($eventName, $handler);
// To detach the handler, use:
// $component->off($eventName, $handler);
```
When you attach a handler, you can now associate it with some parameters which can be later
accessed via the event parameter by the handler:
```php
$component->on($eventName, $handler, $params);
```
Because of this change, you can now use "global" events. Simply trigger and attach handlers to
an event of the application instance:
```php
Yii::$app->on($eventName, $handler);
....
// this will trigger the event and cause $handler to be invoked.
Yii::$app->trigger($eventName);
```
If you need to handle all instances of a class instead of the object you can attach a handler like the following:
```php
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted.');
});
```
The code above defines a handler that will be triggered for every Active Record object's `EVENT_AFTER_INSERT` event.
Extending Yii
=============
TDB
\ No newline at end of file
Working with forms Working with forms
================== ==================
The primary way of using forms in Yii is through [[\yii\widgets\ActiveForm]]. This approach should be preferred when the form is based upon a model. Additionally, there are some useful methods in [[\yii\helpers\Html]] that are typically used for adding buttons and help text to any form. The primary way of using forms in Yii is through [[yii\widgets\ActiveForm]]. This approach should be preferred when the form is based upon a model. Additionally, there are some useful methods in [[\yii\helpers\Html]] that are typically used for adding buttons and help text to any form.
When creating model-based forms, the first step is to define the model itself. The model can be either based upon the Active Record class, or the more generic Model class. For this login example, a generic model will be used: When creating model-based forms, the first step is to define the model itself. The model can be either based upon the Active Record class, or the more generic Model class. For this login example, a generic model will be used:
......
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
--------------------------
How to use it
-------------
Add these lines to your config file:
```php
'modules' => [
'gii' => ['yii\gii\Module']
]
```
Creating your own templates
---------------------------
TDB
Introduction Introduction
============ ============
- [Overview](overview.md) - [Overview](overview.md) - What is Yii and what is it good for?
Getting started Getting started
=============== ===============
- [Installation](installation.md) - [Upgrading from 1.1 to 2.0](upgrade-from-v1.md)
- [Configuration](configuration.md) - [Installation](installation.md) - How to download Yii and configure the Webserver?
- [Configuration](configuration.md) - Configuration of a Yii application
Application templates - [Basic Application Template](apps-basic.md) - A template to start a basic frontend application.
===================== - [Advanced Application Template](apps-advanced.md) - The basis for more advanced applications.
- [Basic](apps-basic.md) - [Creating your own Application structure](apps-own.md) - Learn how to start from scratch.
- [Advanced](apps-advanced.md)
- [Creating your own application template](apps-own.md)
Base concepts Base concepts
============= =============
- [MVC Overview](mvc.md) - [Basic concepts of Yii](basics.md) - The Object and Component class, Path aliases and autoloading
- [Model](model.md) - [MVC](mvc.md) - Implementation of MVC in Yii and a typical MVC application flow
- [View](view.md) - [Model](model.md) - The Yii Model provides Attributes, Scenarios and data Validation
- [Controller](controller.md) - [View](view.md) - Rendering Views applying layouts, using Widgets and asset management
- [Application](application.md) - [Controller](controller.md) - controller actions, routing and action filters
- [Event Handling](events.md) - The Yii event handling mechanism
- [Behaviors](behaviors.md)
Database Database
======== ========
- [Basics](database-basics.md) - [Basics](database-basics.md) - Connecting to a database, basic queries, transactions and schema manipulation
- [Query Builder](query-builder.md) - [Query Builder](query-builder.md) - Querying the database using a simple abstraction layer
- [ActiveRecord](active-record.md) - [ActiveRecord](active-record.md) - The active record ORM, retrieving and manipulatings records and defining relations
- [Database Migration](migration.md) - [Database Migration](migration.md) - Versioning your database with database migrations
Extensions Developers Toolbox
========== ==================
- [Extending Yii](extension.md) - [Automatic Code Generation](gii.md)
- [Using template engines](template.md) - [Debug toolbar and debugger](debugger.md)
- [Error Handling](error.md)
- [Logging](logging.md)
Extensions and 3rd party libraries
==================================
- [Composer](composer.md) - How to manage applications dependencies via composer
- [Extending Yii](extensions.md)
- [Template engines](template.md) - Using template engines such as Smary or Twig
Security and access control Security and access control
=========================== ===========================
- [Authentication](authentication.md) - [Authentication](authentication.md) - Identifying Users
- [Authorization](authorization.md) - [Authorization](authorization.md) - Access control and RBAC
- [Security](security.md) - [Security](security.md) - Hashing and verifying passwords, encryption
- [Views security](view.md#security) - how to prevent XSS
- Role based access control - Role based access control
Data providers, lists and grids Data providers, lists and grids
...@@ -55,27 +66,22 @@ Data providers, lists and grids ...@@ -55,27 +66,22 @@ Data providers, lists and grids
- Grids - Grids
- Lists - Lists
Toolbox Advanced Topics
======= ===============
- [Automatic Code Generation](gii.md)
- [Debug toolbar and debugger](debugger.md)
- [Error Handling](error.md)
- [Logging](logging.md)
More
====
- [Bootstrap widgets](bootstrap-widgets.md) - [Asset Management](assets.md)
- [Working with forms](form.md) - [Working with forms](form.md)
- [Model validation reference](validation.md) - [Bootstrap widgets](bootstrap-widgets.md) - Using [twitter bootstrap](http://getbootstrap.com/)
- [Caching](caching.md)
- [Internationalization](i18n.md)
- [URL Management](url.md)
- [Theming](theming.md) - [Theming](theming.md)
- [Caching](caching.md) - Caching data, page fragments and http requests
- [Internationalization](i18n.md) - Message translation and formatting
- [URL Management](url.md) - routing, customized urls and SEO
- [Console Application](console.md) - [Console Application](console.md)
- [Performance Tuning](performance.md) - [Performance Tuning](performance.md)
- [Managing assets](assets.md)
- [Testing](testing.md) - [Testing](testing.md)
- [Composer](composer.md)
- [Upgrading from 1.1 to 2.0](upgrade-from-v1.md) References
==========
- [Model validation reference](validation.md)
- [Official Composer documentation](http://getcomposer.org)
\ No newline at end of file
...@@ -3,8 +3,9 @@ Installation ...@@ -3,8 +3,9 @@ Installation
There are two ways you can install the Yii framework: There are two ways you can install the Yii framework:
* Using [Composer](http://getcomposer.org/) * Installation via [Composer](http://getcomposer.org/) (recommended)
* Via manual download * Download an application template packed with all requirements including the Yii Framework
Installing via Composer Installing via Composer
----------------------- -----------------------
...@@ -21,48 +22,81 @@ For problems or more information, see the official Composer guide: ...@@ -21,48 +22,81 @@ For problems or more information, see the official Composer guide:
* [Linux](http://getcomposer.org/doc/00-intro.md#installation-nix) * [Linux](http://getcomposer.org/doc/00-intro.md#installation-nix)
* [Windows](http://getcomposer.org/doc/00-intro.md#installation-windows) * [Windows](http://getcomposer.org/doc/00-intro.md#installation-windows)
With Composer installed, you can create a new Yii site using one of Yii's ready-to-use application templates. Based on your needs, choosing the right template can help bootstrap your project. With Composer installed, you can create a new Yii site using one of Yii's ready-to-use application templates.
Based on your needs, choosing the right template can help bootstrap your project.
Currently, there are two application templates available: Currently, there are two application templates available:
- [basic](https://github.com/yiisoft/yii2-app-basic), just a basic frontend application template. - The [Basic Application Template](https://github.com/yiisoft/yii2-app-basic) - just a basic frontend application template.
- [advanced](https://github.com/yiisoft/yii2-app-advanced), consisting of a frontend, a backend, console resources, common (shared code), and support for environments. - The [Advanced Application Template](https://github.com/yiisoft/yii2-app-advanced) - consisting of a frontend, a backend,
console resources, common (shared code), and support for environments.
For installation instructions for these templates, see the above linked pages.
To read more about the ideas behind these application templates and proposed usage,
refer to the [basic application template](apps-basic.md) and [advanced application template](apps-advanced.md) documents.
If you do not want to use a template and want to start from scratch you'll find information in the document about
[creating your own application structure](apps-own.md). This is only recommended for advanced users.
For installation instructions for these templates, see the above linked pages. To read more about ideas behind these application templates and
proposed usage, refer to the [basic application template](apps-basic.md) and [advanced application template](apps-advanced.md) documents.
Installing from zip Installing from zip
------------------- -------------------
Installation from a zip file involves two steps: Installation from a zip file involves two steps:
1. Downloading the Yii Framework from [yiiframework.com](http://www.yiiframework.com/). 1. Downloading an application template from [yiiframework.com](http://www.yiiframework.com/download/).
2. Unpacking the downloaded file. 2. Unpacking the downloaded file.
If you only want the Yii Framework files you can download a ZIP file directly from [github](https://github.com/yiisoft/yii2-framework/releases).
To create your application you might want to follow the steps described in [creating your own application structure](apps-own.md).
This is only recommended for advanced users.
> Tip: The Yii framework itself does not need to be installed under a web-accessible directory. > Tip: The Yii framework itself does not need to be installed under a web-accessible directory.
A Yii application has one entry script which is usually the only file that absolutely must be exposed to web users (i.e., placed within the web directory). Other PHP scripts, including those part of the A Yii application has one entry script which is usually the only file that absolutely must be
Yii framework, should be protected from web access to prevent possible exploitation by hackers. exposed to web users (i.e., placed within the web directory). Other PHP scripts, including those
part of the Yii Framework, should be protected from web access to prevent possible exploitation by hackers.
Requirements Requirements
------------ ------------
After installing Yii, you may want to verify that your server satisfies After installing Yii, you may want to verify that your server satisfies
Yii's requirements. You can do so by running the requirement checker Yii's requirements. You can do so by running the requirement checker
script in a web browser. script in a web browser or from the command line.
1. Copy the `requirements` folder from the downloaded Yii directory to your web directory. If you have installed a Yii application template via zip or composer you'll find a `requirements.php` file in the
2. Access `http://hostname/path/to/yii/requirements/index.php` in your browser. base directory of your application.
In order to run this script on the command line use the following command:
```
php requirements.php
```
In order to run this script in your browser, you should ensure it is accessable by the webserver and
access `http://hostname/path/to/yii-app/requirements.php` in your browser.
If you are using Linux you can create a hard link to make it accessable, using the following command:
```
ln requirements.php ../requirements.php
```
Yii 2 requires PHP 5.4.0 or higher. Yii has been tested with the [Apache HTTP server](http://httpd.apache.org/) and
[Nginx HTTP server](http://nginx.org/) on Windows and Linux.
Yii may also be usable on other web servers and platforms, provided that PHP 5.4 or higher is supported.
Yii 2 requires PHP 5.4.0 or higher. Yii has been tested with the [Apache HTTP server](http://httpd.apache.org/) on Windows and Linux. Yii may also be usable on other web servers and platforms, provided that PHP 5.4 or higher is supported.
Recommended Apache Configuration Recommended Apache Configuration
-------------------------------- --------------------------------
Yii is ready to work with a default Apache web server configuration. As a security measure, Yii comes with `.htaccess` files in the Yii framework and application folders to deny access to thoe restricted resources. Yii is ready to work with a default Apache web server configuration. As a security measure, Yii comes with `.htaccess`
files in the Yii framework folder to deny access to those restricted resources.
By default, requests for pages in a Yii-based site go through the boostrap file, usually named `index.php`, and placed in the application's root directory. The result will be URLs in the format `http://hostname/index.php/controller/action/param/value`. By default, requests for pages in a Yii-based site go through the bootstrap file, usually named `index.php`, and placed
in the application's `web` directory. The result will be URLs in the format `http://hostname/index.php/controller/action/param/value`.
To hide the bootstrap file in your URLs, add `mod_rewrite` instructions to the `.htaccess` file found in your web document root (or add the instructions to the virtual host configuration in Apache's `httpd.conf` file). The applicable instructions are: To hide the bootstrap file in your URLs, add `mod_rewrite` instructions to the `.htaccess` file in your web document root
(or add the instructions to the virtual host configuration in Apache's `httpd.conf` file). The applicable instructions are:
~~~ ~~~
RewriteEngine on RewriteEngine on
...@@ -74,25 +108,42 @@ RewriteCond %{REQUEST_FILENAME} !-d ...@@ -74,25 +108,42 @@ RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php RewriteRule . index.php
~~~ ~~~
Recommended Nginx Configuration Recommended Nginx Configuration
------------------------------- -------------------------------
Yii can also be used with the popular [Nginx](http://wiki.nginx.org/) web server, so long it has PHP installed as an [FPM SAPI](http://php.net/install.fpm). Below is a sample host configuration for a Yii-based site on Nginx. The configuration identifies tells the server to send all requests for non-existent resources through the bootstrap file, resulting in "prettier" URLs without the need for `index.php` references. Yii can also be used with the popular [Nginx](http://wiki.nginx.org/) web server, so long it has PHP installed as
an [FPM SAPI](http://php.net/install.fpm). Below is a sample host configuration for a Yii-based site on Nginx.
The configuration tells the server to send all requests for non-existent resources through the bootstrap file,
resulting in "prettier" URLs without the need for `index.php` references.
~~~ ~~~
server { server {
set $yii_bootstrap "index.php";
charset utf-8; charset utf-8;
client_max_body_size 128M;
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6
listen 80;
server_name mysite.local; server_name mysite.local;
root /path/to/project/webroot/directory root /path/to/project/web;
index $yii_bootstrap;
access_log /path/to/project/log/access.log main; access_log /path/to/project/log/access.log main;
error_log /path/to/project/log/error.log;
location / { location / {
try_files $uri $uri/ /index.php?$args; # Redirect everything that isn't real file to index.php including arguments. # Redirect everything that isn't real file to yii bootstrap file including arguments.
try_files $uri $uri/ /$yii_bootstrap?$args;
} }
# uncomment to avoid processing of calls to unexisting static files by yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
#error_page 404 /404.html;
location ~ \.php$ { location ~ \.php$ {
include fastcgi.conf; include fastcgi.conf;
fastcgi_pass 127.0.0.1:9000; fastcgi_pass 127.0.0.1:9000;
......
Logging
=======
TDB
\ No newline at end of file
...@@ -11,12 +11,12 @@ of the user interface, such as text, images, and form elements. The *controller* ...@@ -11,12 +11,12 @@ of the user interface, such as text, images, and form elements. The *controller*
the communication between the model and the view, acting as an agent. the communication between the model and the view, acting as an agent.
Besides implementing the MVC design pattern, Yii also introduces a *front-controller*, called Besides implementing the MVC design pattern, Yii also introduces a *front-controller*, called
`application`. The front-controller encapsulates the *execution context* for the processing of a request. This means that the front-controller collects information about a user request, and *application*. The front-controller encapsulates the *execution context* for the processing of a request. This means that the front-controller collects information about a user request, and
then dispatches it to an appropriate controller for actual handling of that request. In other words, the front-controller is the primary application manager, handling all requests and delegating action accordingly. then dispatches it to an appropriate controller for actual handling of that request. In other words, the front-controller is the primary application manager, handling all requests and delegating action accordingly.
The following diagram shows the static structure of a Yii application: The following diagram shows the static structure of a Yii application:
![Static structure of Yii application](structure.png) ![Static structure of Yii application](images/structure.png)
A Typical Workflow A Typical Workflow
...@@ -24,18 +24,23 @@ A Typical Workflow ...@@ -24,18 +24,23 @@ A Typical Workflow
The following diagram shows a typical workflow of a Yii application handling a user request: The following diagram shows a typical workflow of a Yii application handling a user request:
![Typical workflow of a Yii application](flow.png) ![Typical workflow of a Yii application](images/flow.png)
1. A user makes a request of the URL `http://www.example.com/index.php?r=post/show&id=1`. The Web server handles the request by executing the bootstrap script `index.php`. 1. A user makes a request of the URL `http://www.example.com/index.php?r=post/show&id=1`.
2. The bootstrap script creates an [Application](/doc/guide/basics.application) instance and runs it. The Web server handles the request by executing the bootstrap script `index.php`.
3. The Application instance obtains the detailed user request information from an [application component](/doc/guide/basics.application#application-component) named `request`. 2. The bootstrap script creates an [[Application|yii\web\Application]] instance and runs it.
4. The application determines which [controller](/doc/guide/basics.controller) and which [action](/doc/guide/basics.controller#action) of that controller was requested. This is accomplished with the help 3. The Application instance obtains the detailed user request information from an application component named `request`.
of an application component named `urlManager`. For this example, the controller is `post`, which refers to the `PostController` class; and the action is `show`, whose actual meaning is determined by the controller. 4. The application determines which [controller](controller.md) and which action of that controller was requested.
5. The application creates an instance of the requested controller This is accomplished with the help of an application component named `urlManager`.
to further handle the user request. The controller determines that the action `show` refers to a method named `actionShow` in the controller class. It then creates and executes filters (e.g. access control, benchmarking) associated with this action. The action is then executed, if execution is allowed by the filters (e.g., if the user has permission to execute that action). For this example, the controller is `post`, which refers to the `PostController` class; and the action is `show`,
6. The action creates a `Post` [model](/doc/guide/basics.model) instance, using the underlying database table, where the ID value of the corresponding record `1`. whose actual meaning is determined by the controller.
7. The action renders a [view](/doc/guide/basics.view) named `show`, providing to the view the `Post` model instance. 5. The application creates an instance of the requested controller to further handle the users request.
The controller determines that the action `show` refers to a method named `actionShow` in the controller class.
It then creates and executes filters (e.g. access control, benchmarking) associated with this action.
The action is then executed, if execution is allowed by the filters (e.g., if the user has permission to execute that action).
6. The action creates a `Post` [model](model.md) instance, using the underlying database table, where the ID value of the corresponding record is `1`.
7. The action renders a [view](view.md) named `show`, providing to the view the `Post` model instance.
8. The view reads the attributes of the `Post` model instance and displays the values of those attributes. 8. The view reads the attributes of the `Post` model instance and displays the values of those attributes.
9. The view executes some [widgets](/doc/guide/basics.view#widget). 9. The view executes some [widgets](view.md#widgets).
10. The view rendering result--the output from the previous steps--is embedded in a [layout](/doc/guide/basics.view#layout) to create a complete page. 10. The view rendering result -the output from the previous steps- is embedded in a [layout](view.md#layout) to create a complete page.
11. The action completes the view rendering and displays the result to the user. 11. The action completes the view rendering and displays the result to the user.
\ No newline at end of file
...@@ -15,6 +15,8 @@ PHP 5.4.0 or greater. ...@@ -15,6 +15,8 @@ PHP 5.4.0 or greater.
For developers who want to use Yii, understanding object-oriented For developers who want to use Yii, understanding object-oriented
programming (OOP) is very helpful, because Yii is a pure OOP framework. programming (OOP) is very helpful, because Yii is a pure OOP framework.
Yii 2.0 also makes use of the latest features of PHP such as [namespaces](http://www.php.net/manual/en/language.namespaces.php)
so you should be familiar with how they work.
What is Yii Best for? What is Yii Best for?
...@@ -35,4 +37,7 @@ How does Yii Compare with Other Frameworks? ...@@ -35,4 +37,7 @@ How does Yii Compare with Other Frameworks?
- Yii strikes a good balance between simplicity and features. - Yii strikes a good balance between simplicity and features.
- Syntax and overall development usability are taken seriously by the Yii development team. - Syntax and overall development usability are taken seriously by the Yii development team.
- Performance is one of the key goals for the Yii framework. - Performance is one of the key goals for the Yii framework.
- The Yii development team is constantly watching what other Web frameworks are doing to see what best practices and features should be incorporated into Yii. The initial Yii release was heavily influenced by Ruby on Rails. Still, no framework or feature is being blindly copied into Yii; all decisions are based upon what's best for Web developers and in keeping with Yii's philosophy. - The Yii development team is constantly watching what other Web frameworks are doing to see what best practices and
features should be incorporated into Yii. The initial Yii release was heavily influenced by Ruby on Rails.
Still, no framework or feature is being blindly copied into Yii; all decisions are based upon what's best
for Web developers and in keeping with Yii's philosophy.
...@@ -4,7 +4,7 @@ Security ...@@ -4,7 +4,7 @@ Security
Good security is vital to the health and success of many websites. Unfortunately, many developers may cut corners when it comes to security due to a lack of understanding or too large of an implementation hurdle. To make your Yii-based site as secure as possible, the Yii framework has baked in several excellent, and easy to use, security features. Good security is vital to the health and success of many websites. Unfortunately, many developers may cut corners when it comes to security due to a lack of understanding or too large of an implementation hurdle. To make your Yii-based site as secure as possible, the Yii framework has baked in several excellent, and easy to use, security features.
Hashing and verifying passwords Hashing and verifying passwords
------------------------------ -------------------------------
Most developers know that you cannot store passwords in plain text, but many believe it's safe to hash passwords using `md5` or `sha1`. There was a time when those hashing algorithms were sufficient, but modern hardware makes it possible to break those hashes very quickly using a brute force attack. Most developers know that you cannot store passwords in plain text, but many believe it's safe to hash passwords using `md5` or `sha1`. There was a time when those hashing algorithms were sufficient, but modern hardware makes it possible to break those hashes very quickly using a brute force attack.
......
Testing
=======
TDB
\ No newline at end of file
Theming
=======
TDB
\ No newline at end of file
...@@ -29,6 +29,8 @@ If your class does not need the event or behavior feature, you should consider u ...@@ -29,6 +29,8 @@ If your class does not need the event or behavior feature, you should consider u
`Object` as the base class. This is usually the case for classes that represent basic `Object` as the base class. This is usually the case for classes that represent basic
data structures. data structures.
More details about Object and component can be found in the [Basic concepts section](basics.md).
Object Configuration Object Configuration
-------------------- --------------------
...@@ -72,6 +74,7 @@ $object = Yii::createObject([ ...@@ -72,6 +74,7 @@ $object = Yii::createObject([
], $param1, $param2); ], $param1, $param2);
``` ```
More on configuration can be found in the [Basic concepts section](basics.md).
Events Events
...@@ -116,6 +119,9 @@ Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ...@@ -116,6 +119,9 @@ Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function
The code above defines a handler that will be triggered for every Active Record object's `EVENT_AFTER_INSERT` event. The code above defines a handler that will be triggered for every Active Record object's `EVENT_AFTER_INSERT` event.
See [Event handling section](events.md) for more details.
Path Alias Path Alias
---------- ----------
...@@ -132,6 +138,8 @@ a class like `yii\web\Request` can be autoloaded by Yii. If you use a third part ...@@ -132,6 +138,8 @@ a class like `yii\web\Request` can be autoloaded by Yii. If you use a third part
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation such as Zend Framework, you may define a path alias `@Zend` which refers to its installation
directory and Yii will be able to autoload any class in this library. directory and Yii will be able to autoload any class in this library.
More on path aliases can be found in the [Basic concepts section](basics.md).
View View
---- ----
...@@ -165,6 +173,8 @@ extension for your Smarty views, or `twig` for Twig views. You may also configur ...@@ -165,6 +173,8 @@ extension for your Smarty views, or `twig` for Twig views. You may also configur
`View::renderers` property to use other template engines. See [Using template engines](template.md) section `View::renderers` property to use other template engines. See [Using template engines](template.md) section
of the guide for more details. of the guide for more details.
See [View section](view.md) for more details.
Models Models
------ ------
...@@ -230,6 +240,7 @@ sending them out. You have to `echo` them explicitly, e.g., `echo $this->render( ...@@ -230,6 +240,7 @@ sending them out. You have to `echo` them explicitly, e.g., `echo $this->render(
To learn more about Yii 2.0 controllers refer to [Controller](controller.md) section of the guide. To learn more about Yii 2.0 controllers refer to [Controller](controller.md) section of the guide.
Widgets Widgets
------- -------
...@@ -252,6 +263,8 @@ $form = \yii\widgets\ActiveForm::begin([ ...@@ -252,6 +263,8 @@ $form = \yii\widgets\ActiveForm::begin([
Previously in 1.1, you would have to enter the widget class names as strings via the `beginWidget()`, Previously in 1.1, you would have to enter the widget class names as strings via the `beginWidget()`,
`endWidget()` and `widget()` methods of `CBaseController`. The approach above gets better IDE support. `endWidget()` and `widget()` methods of `CBaseController`. The approach above gets better IDE support.
For more on widgets see the [View section](view.md#widgets).
Themes Themes
------ ------
...@@ -267,6 +280,8 @@ of the context of a controller or a widget. ...@@ -267,6 +280,8 @@ of the context of a controller or a widget.
There is no more `CThemeManager`. Instead, `theme` is a configurable property of the "view" There is no more `CThemeManager`. Instead, `theme` is a configurable property of the "view"
application component. application component.
For more on themes see the [Theming section](theming.md).
Console Applications Console Applications
-------------------- --------------------
...@@ -282,6 +297,8 @@ are treated as global options declared in `globalOptions()`. ...@@ -282,6 +297,8 @@ are treated as global options declared in `globalOptions()`.
Yii 2.0 supports automatic generation of command help information from comment blocks. Yii 2.0 supports automatic generation of command help information from comment blocks.
For more on console applications see the [Console section](console.md).
I18N I18N
---- ----
...@@ -290,7 +307,7 @@ Yii 2.0 removes date formatter and number formatter in favor of the PECL intl PH ...@@ -290,7 +307,7 @@ Yii 2.0 removes date formatter and number formatter in favor of the PECL intl PH
Message translation is still supported, but managed via the "i18n" application component. Message translation is still supported, but managed via the "i18n" application component.
The component manages a set of message sources, which allows you to use different message The component manages a set of message sources, which allows you to use different message
sources based on message categories. For more information, see the class documentation for `I18N`. sources based on message categories. For more information, see the class documentation for [I18N](i18n.md).
Action Filters Action Filters
...@@ -315,6 +332,7 @@ public function behaviors() ...@@ -315,6 +332,7 @@ public function behaviors()
} }
``` ```
For more on action filters see the [Controller section](controller.md#action-filters).
Assets Assets
...@@ -329,7 +347,7 @@ By registering an asset bundle via `AssetBundle::register()`, you will be able t ...@@ -329,7 +347,7 @@ By registering an asset bundle via `AssetBundle::register()`, you will be able t
the assets in that bundle accessible via Web, and the current page will automatically the assets in that bundle accessible via Web, and the current page will automatically
contain the references to the JavaScript and CSS files specified in that bundle. contain the references to the JavaScript and CSS files specified in that bundle.
To learn more about assets see the [asset manager documentation](assets.md).
Static Helpers Static Helpers
-------------- --------------
...@@ -441,6 +459,8 @@ By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes ...@@ -441,6 +459,8 @@ By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes
are saved to database when you call `save()`, regardless of having changed or not, are saved to database when you call `save()`, regardless of having changed or not,
unless you explicitly list the attributes to save. unless you explicitly list the attributes to save.
See [active record docs](active-record.md) for more details.
Auto-quoting Table and Column Names Auto-quoting Table and Column Names
------------------------------------ ------------------------------------
...@@ -483,14 +503,18 @@ the same goal. ...@@ -483,14 +503,18 @@ the same goal.
] ]
``` ```
More details in the [Url manager docs](url.md).
Response Response
-------- --------
TBD
Extensions Extensions
---------- ----------
TBD
Integration with Composer Integration with Composer
------------------------- -------------------------
......
...@@ -28,21 +28,21 @@ use yii\helpers\Html; ...@@ -28,21 +28,21 @@ use yii\helpers\Html;
* [ * [
* 'label' => 'Dropdown', * 'label' => 'Dropdown',
* 'items' => [ * 'items' => [
* [ * ['label' => 'Level 1 - Dropdown A', 'url' => '#'],
* 'label' => 'Level 1 -DropdownA', * '<li class="divider"></li>',
* 'url' => '#', * '<li class="dropdown-header">Dropdown Header</li>',
* 'items' => [ * ['label' => 'Level 1 - Dropdown B', 'url' => '#'],
* ['label' => 'Level 2 -DropdownA', 'url' => '#'],
* ],
* ],
* ['label' => 'Level 1 -DropdownB', 'url' => '#'],
* ], * ],
* ], * ],
* ], * ],
* ]); * ]);
* ``` * ```
* *
* @see http://twitter.github.io/bootstrap/components.html#nav * Note: Multilevel dropdowns beyond Level 1 are not supported in Bootstrap 3.
*
* @see http://getbootstrap.com/components.html#dropdowns
* @see http://getbootstrap.com/components/#nav
*
* @author Antonio Ramirez <amigo.cobos@gmail.com> * @author Antonio Ramirez <amigo.cobos@gmail.com>
* @since 2.0 * @since 2.0
*/ */
......
...@@ -106,6 +106,7 @@ class Module extends \yii\base\Module ...@@ -106,6 +106,7 @@ class Module extends \yii\base\Module
return true; return true;
} }
} }
Yii::warning('Access to debugger is denied due to IP address restriction. The requested IP is ' . $ip, __METHOD__);
return false; return false;
} }
......
...@@ -125,6 +125,7 @@ class Module extends \yii\base\Module ...@@ -125,6 +125,7 @@ class Module extends \yii\base\Module
return true; return true;
} }
} }
Yii::warning('Access to Gii is denied due to IP address restriction. The requested IP is ' . $ip, __METHOD__);
return false; return false;
} }
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
use Yii;
use yii\helpers\Html;
/**
* Slider renders a slider jQuery UI widget.
*
* For example:
*
* ```php
* echo Slider::widget([
* 'model' => $model,
* 'attribute' => 'amount',
* 'clientOptions' => [
* 'min' => 1,
* 'max' => 10,
* ],
* ]);
* ```
*
* The following example will use the name property instead:
*
* ```php
* echo Slider::widget([
* 'name' => 'amount',
* 'clientOptions' => [
* 'min' => 1,
* 'max' => 10,
* ],
* ]);
*```
*
* @see http://api.jqueryui.com/slider/
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class Slider extends InputWidget
{
/**
* Renders the widget.
*/
public function run()
{
echo $this->renderWidget();
$this->registerWidget('slider', SliderAsset::className());
}
/**
* Renders the Slider widget.
* @return string the rendering result.
*/
public function renderWidget()
{
if ($this->hasModel()) {
return Html::activeTextInput($this->model, $this->attribute, $this->options);
} else {
return Html::textInput($this->name, $this->value, $this->options);
}
}
}
...@@ -66,7 +66,7 @@ class Widget extends \yii\base\Widget ...@@ -66,7 +66,7 @@ class Widget extends \yii\base\Widget
/** @var \yii\web\AssetBundle $assetBundle */ /** @var \yii\web\AssetBundle $assetBundle */
$assetBundle::register($view); $assetBundle::register($view);
/** @var \yii\web\AssetBundle $themeAsset */ /** @var \yii\web\AssetBundle $themeAsset */
$themeAsset = self::$theme; $themeAsset = static::$theme;
$themeAsset::register($view); $themeAsset::register($view);
$id = $this->options['id']; $id = $this->options['id'];
......
...@@ -37,6 +37,23 @@ use yii\mail\BaseMailer; ...@@ -37,6 +37,23 @@ use yii\mail\BaseMailer;
* You may also skip the configuration of the [[transport]] property. In that case, the default * You may also skip the configuration of the [[transport]] property. In that case, the default
* PHP `mail()` function will be used to send emails. * PHP `mail()` function will be used to send emails.
* *
* You specify the transport constructor arguments using 'constructArgs' key in the config.
* You can also specify the list of plugins, which should be registered to the transport using
* 'plugins' key. For example:
*
* ~~~
* 'transport' => [
* 'class' => 'Swift_SmtpTransport',
* 'constructArgs' => ['localhost', 25]
* 'plugins' => [
* [
* 'class' => 'Swift_Plugins_ThrottlerPlugin',
* 'constructArgs' => [20],
* ],
* ],
* ],
* ~~~
*
* To send an email, you may use the following code: * To send an email, you may use the following code:
* *
* ~~~ * ~~~
...@@ -131,28 +148,69 @@ class Mailer extends BaseMailer ...@@ -131,28 +148,69 @@ class Mailer extends BaseMailer
*/ */
protected function createTransport(array $config) protected function createTransport(array $config)
{ {
if (!isset($config['class'])) {
$config['class'] = 'Swift_MailTransport';
}
if (isset($config['plugins'])) {
$plugins = $config['plugins'];
unset($config['plugins']);
}
/** @var \Swift_MailTransport $transport */
$transport = $this->createSwiftObject($config);
if (isset($plugins)) {
foreach ($plugins as $plugin) {
if (is_array($plugin) && isset($plugin['class'])) {
$plugin = $this->createSwiftObject($plugin);
}
$transport->registerPlugin($plugin);
}
}
return $transport;
}
/**
* Creates Swift library object, from given array configuration.
* @param array $config object configuration
* @return Object created object
* @throws \yii\base\InvalidConfigException on invalid configuration.
*/
protected function createSwiftObject(array $config)
{
if (isset($config['class'])) { if (isset($config['class'])) {
$className = $config['class']; $className = $config['class'];
unset($config['class']); unset($config['class']);
} else { } else {
$className = 'Swift_MailTransport'; throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
}
if (isset($config['constructArgs'])) {
$args = [];
foreach ($config['constructArgs'] as $arg) {
if (is_array($arg) && isset($arg['class'])) {
$args[] = $this->createSwiftObject($arg);
} else {
$args[] = $arg;
}
}
unset($config['constructArgs']);
array_unshift($args, ['class' => $className]);
$object = call_user_func_array(['Yii', 'createObject'], $args);
} else {
$object = new $className;
} }
/** @var \Swift_MailTransport $transport */
$transport = $className::newInstance();
if (!empty($config)) { if (!empty($config)) {
foreach ($config as $name => $value) { foreach ($config as $name => $value) {
if (property_exists($transport, $name)) { if (property_exists($object, $name)) {
$transport->$name = $value; $object->$name = $value;
} else { } else {
$setter = 'set' . $name; $setter = 'set' . $name;
if (method_exists($transport, $setter) || method_exists($transport, '__call')) { if (method_exists($object, $setter) || method_exists($object, '__call')) {
$transport->$setter($value); $object->$setter($value);
} else { } else {
throw new InvalidConfigException('Setting unknown property: ' . get_class($transport) . '::' . $name); throw new InvalidConfigException('Setting unknown property: ' . $className . '::' . $name);
} }
} }
} }
} }
return $transport; return $object;
} }
} }
...@@ -147,11 +147,11 @@ class BaseYii ...@@ -147,11 +147,11 @@ class BaseYii
$pos = strpos($alias, '/'); $pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos); $root = $pos === false ? $alias : substr($alias, 0, $pos);
if (isset(self::$aliases[$root])) { if (isset(static::$aliases[$root])) {
if (is_string(self::$aliases[$root])) { if (is_string(static::$aliases[$root])) {
return $pos === false ? self::$aliases[$root] : self::$aliases[$root] . substr($alias, $pos); return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
} else { } else {
foreach (self::$aliases[$root] as $name => $path) { foreach (static::$aliases[$root] as $name => $path) {
if (strpos($alias . '/', $name . '/') === 0) { if (strpos($alias . '/', $name . '/') === 0) {
return $path . substr($alias, strlen($name)); return $path . substr($alias, strlen($name));
} }
...@@ -178,11 +178,11 @@ class BaseYii ...@@ -178,11 +178,11 @@ class BaseYii
$pos = strpos($alias, '/'); $pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos); $root = $pos === false ? $alias : substr($alias, 0, $pos);
if (isset(self::$aliases[$root])) { if (isset(static::$aliases[$root])) {
if (is_string(self::$aliases[$root])) { if (is_string(static::$aliases[$root])) {
return $root; return $root;
} else { } else {
foreach (self::$aliases[$root] as $name => $path) { foreach (static::$aliases[$root] as $name => $path) {
if (strpos($alias . '/', $name . '/') === 0) { if (strpos($alias . '/', $name . '/') === 0) {
return $name; return $name;
} }
...@@ -229,30 +229,30 @@ class BaseYii ...@@ -229,30 +229,30 @@ class BaseYii
$root = $pos === false ? $alias : substr($alias, 0, $pos); $root = $pos === false ? $alias : substr($alias, 0, $pos);
if ($path !== null) { if ($path !== null) {
$path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path); $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
if (!isset(self::$aliases[$root])) { if (!isset(static::$aliases[$root])) {
if ($pos === false) { if ($pos === false) {
self::$aliases[$root] = $path; static::$aliases[$root] = $path;
} else { } else {
self::$aliases[$root] = [$alias => $path]; static::$aliases[$root] = [$alias => $path];
} }
} elseif (is_string(self::$aliases[$root])) { } elseif (is_string(static::$aliases[$root])) {
if ($pos === false) { if ($pos === false) {
self::$aliases[$root] = $path; static::$aliases[$root] = $path;
} else { } else {
self::$aliases[$root] = [ static::$aliases[$root] = [
$alias => $path, $alias => $path,
$root => self::$aliases[$root], $root => static::$aliases[$root],
]; ];
} }
} else { } else {
self::$aliases[$root][$alias] = $path; static::$aliases[$root][$alias] = $path;
krsort(self::$aliases[$root]); krsort(static::$aliases[$root]);
} }
} elseif (isset(self::$aliases[$root])) { } elseif (isset(static::$aliases[$root])) {
if (is_array(self::$aliases[$root])) { if (is_array(static::$aliases[$root])) {
unset(self::$aliases[$root][$alias]); unset(static::$aliases[$root][$alias]);
} elseif ($pos === false) { } elseif ($pos === false) {
unset(self::$aliases[$root]); unset(static::$aliases[$root]);
} }
} }
} }
...@@ -278,8 +278,8 @@ class BaseYii ...@@ -278,8 +278,8 @@ class BaseYii
*/ */
public static function autoload($className) public static function autoload($className)
{ {
if (isset(self::$classMap[$className])) { if (isset(static::$classMap[$className])) {
$classFile = self::$classMap[$className]; $classFile = static::$classMap[$className];
if ($classFile[0] === '@') { if ($classFile[0] === '@') {
$classFile = static::getAlias($classFile); $classFile = static::getAlias($classFile);
} }
...@@ -362,8 +362,8 @@ class BaseYii ...@@ -362,8 +362,8 @@ class BaseYii
$class = ltrim($class, '\\'); $class = ltrim($class, '\\');
if (isset(self::$objectConfig[$class])) { if (isset(static::$objectConfig[$class])) {
$config = array_merge(self::$objectConfig[$class], $config); $config = array_merge(static::$objectConfig[$class], $config);
} }
if (($n = func_num_args()) > 1) { if (($n = func_num_args()) > 1) {
...@@ -394,7 +394,7 @@ class BaseYii ...@@ -394,7 +394,7 @@ class BaseYii
public static function trace($message, $category = 'application') public static function trace($message, $category = 'application')
{ {
if (YII_DEBUG) { if (YII_DEBUG) {
self::$app->getLog()->log($message, Logger::LEVEL_TRACE, $category); static::$app->getLog()->log($message, Logger::LEVEL_TRACE, $category);
} }
} }
...@@ -407,7 +407,7 @@ class BaseYii ...@@ -407,7 +407,7 @@ class BaseYii
*/ */
public static function error($message, $category = 'application') public static function error($message, $category = 'application')
{ {
self::$app->getLog()->log($message, Logger::LEVEL_ERROR, $category); static::$app->getLog()->log($message, Logger::LEVEL_ERROR, $category);
} }
/** /**
...@@ -419,7 +419,7 @@ class BaseYii ...@@ -419,7 +419,7 @@ class BaseYii
*/ */
public static function warning($message, $category = 'application') public static function warning($message, $category = 'application')
{ {
self::$app->getLog()->log($message, Logger::LEVEL_WARNING, $category); static::$app->getLog()->log($message, Logger::LEVEL_WARNING, $category);
} }
/** /**
...@@ -431,7 +431,7 @@ class BaseYii ...@@ -431,7 +431,7 @@ class BaseYii
*/ */
public static function info($message, $category = 'application') public static function info($message, $category = 'application')
{ {
self::$app->getLog()->log($message, Logger::LEVEL_INFO, $category); static::$app->getLog()->log($message, Logger::LEVEL_INFO, $category);
} }
/** /**
...@@ -453,7 +453,7 @@ class BaseYii ...@@ -453,7 +453,7 @@ class BaseYii
*/ */
public static function beginProfile($token, $category = 'application') public static function beginProfile($token, $category = 'application')
{ {
self::$app->getLog()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category); static::$app->getLog()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category);
} }
/** /**
...@@ -465,7 +465,7 @@ class BaseYii ...@@ -465,7 +465,7 @@ class BaseYii
*/ */
public static function endProfile($token, $category = 'application') public static function endProfile($token, $category = 'application')
{ {
self::$app->getLog()->log($token, Logger::LEVEL_PROFILE_END, $category); static::$app->getLog()->log($token, Logger::LEVEL_PROFILE_END, $category);
} }
/** /**
...@@ -504,8 +504,8 @@ class BaseYii ...@@ -504,8 +504,8 @@ class BaseYii
*/ */
public static function t($category, $message, $params = [], $language = null) public static function t($category, $message, $params = [], $language = null)
{ {
if (self::$app !== null) { if (static::$app !== null) {
return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language); return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
} else { } else {
$p = []; $p = [];
foreach ((array) $params as $name => $value) { foreach ((array) $params as $name => $value) {
......
...@@ -190,7 +190,7 @@ class Formatter extends Component ...@@ -190,7 +190,7 @@ class Formatter extends Component
if ($value === null) { if ($value === null) {
return $this->nullDisplay; return $this->nullDisplay;
} }
return Html::mailto($value); return Html::mailto(Html::encode($value), $value);
} }
/** /**
......
...@@ -356,10 +356,10 @@ class View extends Component ...@@ -356,10 +356,10 @@ class View extends Component
/** /**
* Begins the rendering of content that is to be decorated by the specified view. * Begins the rendering of content that is to be decorated by the specified view.
* This method can be used to implement nested layout. For example, a layout can be embedded * This method can be used to implement nested layout. For example, a layout can be embedded
* in another layout file specified as '@app/view/layouts/base.php' like the following: * in another layout file specified as '@app/views/layouts/base.php' like the following:
* *
* ~~~ * ~~~
* <?php $this->beginContent('@app/view/layouts/base.php'); ?> * <?php $this->beginContent('@app/views/layouts/base.php'); ?>
* ...layout content here... * ...layout content here...
* <?php $this->endContent(); ?> * <?php $this->endContent(); ?>
* ~~~ * ~~~
......
...@@ -27,13 +27,13 @@ class Widget extends Component implements ViewContextInterface ...@@ -27,13 +27,13 @@ class Widget extends Component implements ViewContextInterface
* @var integer a counter used to generate [[id]] for widgets. * @var integer a counter used to generate [[id]] for widgets.
* @internal * @internal
*/ */
public static $_counter = 0; public static $counter = 0;
/** /**
* @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
*/ */
public static $_stack = []; public static $stack = [];
/** /**
...@@ -48,7 +48,7 @@ class Widget extends Component implements ViewContextInterface ...@@ -48,7 +48,7 @@ class Widget extends Component implements ViewContextInterface
$config['class'] = get_called_class(); $config['class'] = get_called_class();
/** @var Widget $widget */ /** @var Widget $widget */
$widget = Yii::createObject($config); $widget = Yii::createObject($config);
self::$_stack[] = $widget; self::$stack[] = $widget;
return $widget; return $widget;
} }
...@@ -60,8 +60,8 @@ class Widget extends Component implements ViewContextInterface ...@@ -60,8 +60,8 @@ class Widget extends Component implements ViewContextInterface
*/ */
public static function end() public static function end()
{ {
if (!empty(self::$_stack)) { if (!empty(self::$stack)) {
$widget = array_pop(self::$_stack); $widget = array_pop(self::$stack);
if (get_class($widget) === get_called_class()) { if (get_class($widget) === get_called_class()) {
$widget->run(); $widget->run();
return $widget; return $widget;
...@@ -100,7 +100,7 @@ class Widget extends Component implements ViewContextInterface ...@@ -100,7 +100,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 = 'w' . self::$counter++;
} }
return $this->_id; return $this->_id;
} }
......
...@@ -87,12 +87,12 @@ class ColumnSchema extends Object ...@@ -87,12 +87,12 @@ class ColumnSchema extends Object
*/ */
public function typecast($value) public function typecast($value)
{ {
if ($value === '' && $this->type !== Schema::TYPE_TEXT && $this->type !== Schema::TYPE_STRING && $this->type !== Schema::TYPE_BINARY) {
return null;
}
if ($value === null || gettype($value) === $this->phpType || $value instanceof Expression) { if ($value === null || gettype($value) === $this->phpType || $value instanceof Expression) {
return $value; return $value;
} }
if ($value === '' && $this->type !== Schema::TYPE_TEXT && $this->type !== Schema::TYPE_STRING) {
return null;
}
switch ($this->phpType) { switch ($this->phpType) {
case 'string': case 'string':
return (string)$value; return (string)$value;
......
...@@ -727,7 +727,7 @@ class BaseHtml ...@@ -727,7 +727,7 @@ class BaseHtml
* @param string $name the name attribute of each checkbox. * @param string $name the name attribute of each checkbox.
* @param string|array $selection the selected value(s). * @param string|array $selection the selected value(s).
* @param array $items the data item used to generate the checkboxes. * @param array $items the data item used to generate the checkboxes.
* The array keys are the labels, while the array values are the corresponding checkbox values. * The array values are the labels, while the array keys are the corresponding checkbox values.
* @param array $options options (name => config) for the checkbox list container tag. * @param array $options options (name => config) for the checkbox list container tag.
* The following options are specially handled: * The following options are specially handled:
* *
...@@ -1253,7 +1253,7 @@ class BaseHtml ...@@ -1253,7 +1253,7 @@ class BaseHtml
* @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
* about attribute expression. * about attribute expression.
* @param array $items the data item used to generate the checkboxes. * @param array $items the data item used to generate the checkboxes.
* The array keys are the labels, while the array values are the corresponding checkbox values. * The array values are the labels, while the array keys are the corresponding checkbox values.
* Note that the labels will NOT be HTML-encoded, while the values will. * Note that the labels will NOT be HTML-encoded, while the values will.
* @param array $options options (name => config) for the checkbox list. The following options are specially handled: * @param array $options options (name => config) for the checkbox list. The following options are specially handled:
* *
......
...@@ -280,8 +280,8 @@ class BaseInflector ...@@ -280,8 +280,8 @@ class BaseInflector
*/ */
public static function pluralize($word) public static function pluralize($word)
{ {
if (isset(self::$specials[$word])) { if (isset(static::$specials[$word])) {
return self::$specials[$word]; return static::$specials[$word];
} }
foreach (static::$plurals as $rule => $replacement) { foreach (static::$plurals as $rule => $replacement) {
if (preg_match($rule, $word)) { if (preg_match($rule, $word)) {
...@@ -298,7 +298,7 @@ class BaseInflector ...@@ -298,7 +298,7 @@ class BaseInflector
*/ */
public static function singularize($word) public static function singularize($word)
{ {
$result = array_search($word, self::$specials, true); $result = array_search($word, static::$specials, true);
if ($result !== false) { if ($result !== false) {
return $result; return $result;
} }
......
...@@ -392,7 +392,7 @@ class DbManager extends Manager ...@@ -392,7 +392,7 @@ class DbManager extends Manager
->where(['user_id' => $userId, 'name' => new Expression('item_name')]) ->where(['user_id' => $userId, 'name' => new Expression('item_name')])
->createCommand($this->db); ->createCommand($this->db);
} else { } else {
$command = $query->select('name', 'type', 'description', 't1.biz_rule', 't1.data') $command = $query->select(['name', 'type', 'description', 't1.biz_rule', 't1.data'])
->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2']) ->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2'])
->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')]) ->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')])
->createCommand($this->db); ->createCommand($this->db);
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
echo "<?php\n"; echo "<?php\n";
?> ?>
use yii\db\Schema;
class <?= $className ?> extends \yii\db\Migration class <?= $className ?> extends \yii\db\Migration
{ {
public function up() public function up()
......
...@@ -41,9 +41,18 @@ use yii\helpers\FileHelper; ...@@ -41,9 +41,18 @@ use yii\helpers\FileHelper;
class AssetManager extends Component class AssetManager extends Component
{ {
/** /**
* @var array list of available asset bundles. The keys are the class names of the asset bundles, * @var array list of available asset bundles. The keys are the class names (without leading backslash)
* and the values are either the configuration arrays for creating the [[AssetBundle]] objects * of the asset bundles, and the values are either the configuration arrays for creating the [[AssetBundle]]
* or the corresponding asset bundle instances. * objects or the corresponding asset bundle instances. For example, the following code disables
* the bootstrap css file used by Bootstrap widgets (because you want to use your own styles):
*
* ~~~
* [
* 'yii\bootstrap\BootstrapAsset' => [
* 'css' => [],
* ],
* ]
* ~~~
*/ */
public $bundles = []; public $bundles = [];
/** /**
......
...@@ -92,8 +92,6 @@ class Controller extends \yii\base\Controller ...@@ -92,8 +92,6 @@ class Controller extends \yii\base\Controller
{ {
if (parent::beforeAction($action)) { if (parent::beforeAction($action)) {
if ($this->enableCsrfValidation && !Yii::$app->getRequest()->validateCsrfToken()) { if ($this->enableCsrfValidation && !Yii::$app->getRequest()->validateCsrfToken()) {
// avoid checking again if errorAction is called to display exception
Yii::$app->getRequest()->enableCsrfValidation = false;
throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.')); throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.'));
} }
return true; return true;
...@@ -169,12 +167,12 @@ class Controller extends \yii\base\Controller ...@@ -169,12 +167,12 @@ class Controller extends \yii\base\Controller
* Any relative URL will be converted into an absolute one by prepending it with the host info * Any relative URL will be converted into an absolute one by prepending it with the host info
* of the current request. * of the current request.
* *
* @param integer $statusCode the HTTP status code. If null, it will use 302. * @param integer $statusCode the HTTP status code. Defaults to 302.
* See [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html]] * See [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html]]
* for details about HTTP status code * for details about HTTP status code
* @return Response the current response object * @return Response the current response object
*/ */
public function redirect($url, $statusCode = null) public function redirect($url, $statusCode = 302)
{ {
return Yii::$app->getResponse()->redirect(Html::url($url), $statusCode); return Yii::$app->getResponse()->redirect(Html::url($url), $statusCode);
} }
......
...@@ -249,12 +249,15 @@ class Response extends \yii\base\Response ...@@ -249,12 +249,15 @@ class Response extends \yii\base\Response
*/ */
public function setStatusCode($value, $text = null) public function setStatusCode($value, $text = null)
{ {
if ($value === null) {
$value = 200;
}
$this->_statusCode = (int)$value; $this->_statusCode = (int)$value;
if ($this->getIsInvalid()) { if ($this->getIsInvalid()) {
throw new InvalidParamException("The HTTP status code is invalid: $value"); throw new InvalidParamException("The HTTP status code is invalid: $value");
} }
if ($text === null) { if ($text === null) {
$this->statusText = isset(self::$httpStatuses[$this->_statusCode]) ? self::$httpStatuses[$this->_statusCode] : ''; $this->statusText = isset(static::$httpStatuses[$this->_statusCode]) ? static::$httpStatuses[$this->_statusCode] : '';
} else { } else {
$this->statusText = $text; $this->statusText = $text;
} }
......
...@@ -197,6 +197,8 @@ class UrlManager extends Component ...@@ -197,6 +197,8 @@ class UrlManager extends Component
return false; return false;
} }
Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);
$suffix = (string)$this->suffix; $suffix = (string)$this->suffix;
if ($suffix !== '' && $pathInfo !== '') { if ($suffix !== '' && $pathInfo !== '') {
$n = strlen($this->suffix); $n = strlen($this->suffix);
...@@ -212,14 +214,13 @@ class UrlManager extends Component ...@@ -212,14 +214,13 @@ class UrlManager extends Component
} }
} }
Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);
return [$pathInfo, []]; return [$pathInfo, []];
} else { } else {
Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
$route = $request->get($this->routeVar); $route = $request->get($this->routeVar);
if (is_array($route)) { if (is_array($route)) {
$route = ''; $route = '';
} }
Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
return [(string)$route, []]; return [(string)$route, []];
} }
} }
......
...@@ -503,7 +503,7 @@ class ActiveField extends Component ...@@ -503,7 +503,7 @@ class ActiveField extends Component
* As a result, the corresponding submitted value is an array. * As a result, the corresponding submitted value is an array.
* The selection of the checkbox list is taken from the value of the model attribute. * The selection of the checkbox list is taken from the value of the model attribute.
* @param array $items the data item used to generate the checkboxes. * @param array $items the data item used to generate the checkboxes.
* The array keys are the labels, while the array values are the corresponding checkbox values. * The array values are the labels, while the array keys are the corresponding checkbox values.
* Note that the labels will NOT be HTML-encoded, while the values will. * Note that the labels will NOT be HTML-encoded, while the values will.
* @param array $options options (name => config) for the checkbox list. The following options are specially handled: * @param array $options options (name => config) for the checkbox list. The following options are specially handled:
* *
......
...@@ -57,8 +57,8 @@ class DetailView extends Widget ...@@ -57,8 +57,8 @@ class DetailView extends Widget
* @var array a list of attributes to be displayed in the detail view. Each array element * @var array a list of attributes to be displayed in the detail view. Each array element
* represents the specification for displaying one particular attribute. * represents the specification for displaying one particular attribute.
* *
* An attribute can be specified as a string in the format of "Name" or "Name:Type", where "Name" refers to * An attribute can be specified as a string in the format of "Name" or "Name:Format", where "Name" refers to
* the attribute name, and "Type" represents the type of the attribute. The "Type" is passed to the [[Formatter::format()]] * the attribute name, and "Format" represents the format of the attribute. The "Format" is passed to the [[Formatter::format()]]
* method to format an attribute value into a displayable text. Please refer to [[Formatter]] for the supported types. * method to format an attribute value into a displayable text. Please refer to [[Formatter]] for the supported types.
* *
* An attribute can also be specified in terms of an array with the following elements: * An attribute can also be specified in terms of an array with the following elements:
...@@ -67,8 +67,8 @@ class DetailView extends Widget ...@@ -67,8 +67,8 @@ class DetailView extends Widget
* - label: the label associated with the attribute. If this is not specified, it will be generated from the attribute name. * - label: the label associated with the attribute. If this is not specified, it will be generated from the attribute name.
* - value: the value to be displayed. If this is not specified, it will be retrieved from [[model]] using the attribute name * - value: the value to be displayed. If this is not specified, it will be retrieved from [[model]] using the attribute name
* by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into a displayable text * by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into a displayable text
* according to the "type" option. * according to the "format" option.
* - type: the type of the value that determines how the value would be formatted into a displayable text. * - format: the type of the value that determines how the value would be formatted into a displayable text.
* Please refer to [[Formatter]] for supported types. * Please refer to [[Formatter]] for supported types.
* - visible: whether the attribute is visible. If set to `false`, the attribute will be displayed. * - visible: whether the attribute is visible. If set to `false`, the attribute will be displayed.
*/ */
...@@ -145,7 +145,7 @@ class DetailView extends Widget ...@@ -145,7 +145,7 @@ class DetailView extends Widget
if (is_string($this->template)) { if (is_string($this->template)) {
return strtr($this->template, [ return strtr($this->template, [
'{label}' => $attribute['label'], '{label}' => $attribute['label'],
'{value}' => $this->formatter->format($attribute['value'], $attribute['type']), '{value}' => $this->formatter->format($attribute['value'], $attribute['format']),
]); ]);
} else { } else {
return call_user_func($this->template, $attribute, $index, $this); return call_user_func($this->template, $attribute, $index, $this);
...@@ -174,11 +174,11 @@ class DetailView extends Widget ...@@ -174,11 +174,11 @@ class DetailView extends Widget
foreach ($this->attributes as $i => $attribute) { foreach ($this->attributes as $i => $attribute) {
if (is_string($attribute)) { if (is_string($attribute)) {
if (!preg_match('/^(\w+)(\s*:\s*(\w+))?$/', $attribute, $matches)) { if (!preg_match('/^(\w+)(\s*:\s*(\w+))?$/', $attribute, $matches)) {
throw new InvalidConfigException('The attribute must be specified in the format of "Name" or "Name:Type"'); throw new InvalidConfigException('The attribute must be specified in the format of "Name" or "Name:Format"');
} }
$attribute = [ $attribute = [
'name' => $matches[1], 'name' => $matches[1],
'type' => isset($matches[3]) ? $matches[3] : 'text', 'format' => isset($matches[3]) ? $matches[3] : 'text',
]; ];
} }
...@@ -186,8 +186,8 @@ class DetailView extends Widget ...@@ -186,8 +186,8 @@ class DetailView extends Widget
throw new InvalidConfigException('The attribute configuration must be an array.'); throw new InvalidConfigException('The attribute configuration must be an array.');
} }
if (!isset($attribute['type'])) { if (!isset($attribute['format'])) {
$attribute['type'] = 'text'; $attribute['format'] = 'text';
} }
if (isset($attribute['name'])) { if (isset($attribute['name'])) {
$name = $attribute['name']; $name = $attribute['name'];
......
...@@ -164,14 +164,14 @@ class LinkPager extends Widget ...@@ -164,14 +164,14 @@ class LinkPager extends Widget
*/ */
protected function renderPageButton($label, $page, $class, $disabled, $active) protected function renderPageButton($label, $page, $class, $disabled, $active)
{ {
$options = ['class' => $class === '' ? null : $class];
if ($active) { if ($active) {
$class .= ' ' . $this->activePageCssClass; Html::addCssClass($options, $this->activePageCssClass);
} }
if ($disabled) { if ($disabled) {
$class .= ' ' . $this->disabledPageCssClass; Html::addCssClass($options, $this->disabledPageCssClass);
return Html::tag('li', Html::tag('span', $label), $options);
} }
$class = trim($class);
$options = ['class' => $class === '' ? null : $class];
return Html::tag('li', Html::a($label, $this->pagination->createUrl($page), ['data-page' => $page]), $options); return Html::tag('li', Html::a($label, $this->pagination->createUrl($page), ['data-page' => $page]), $options);
} }
......
...@@ -32,10 +32,10 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase ...@@ -32,10 +32,10 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
*/ */
public function getParam($name, $default = null) public function getParam($name, $default = null)
{ {
if (self::$params === null) { if (static::$params === null) {
self::$params = require(__DIR__ . '/data/config.php'); static::$params = require(__DIR__ . '/data/config.php');
} }
return isset(self::$params[$name]) ? self::$params[$name] : $default; return isset(static::$params[$name]) ? static::$params[$name] : $default;
} }
/** /**
......
...@@ -63,6 +63,56 @@ class MailerTest extends VendorTestCase ...@@ -63,6 +63,56 @@ class MailerTest extends VendorTestCase
$this->assertEquals($transportConfig['host'], $transport->getHost(), 'Invalid transport host!'); $this->assertEquals($transportConfig['host'], $transport->getHost(), 'Invalid transport host!');
} }
/**
* @depends testConfigureTransport
*/
public function testConfigureTransportConstruct()
{
$mailer = new Mailer();
$host = 'some.test.host';
$port = 999;
$transportConfig = [
'class' => 'Swift_SmtpTransport',
'constructArgs' => [
$host,
$port,
],
];
$mailer->setTransport($transportConfig);
$transport = $mailer->getTransport();
$this->assertTrue(is_object($transport), 'Unable to setup transport via config!');
$this->assertEquals($host, $transport->getHost(), 'Invalid transport host!');
$this->assertEquals($port, $transport->getPort(), 'Invalid transport host!');
}
/**
* @depends testConfigureTransportConstruct
*/
public function testConfigureTransportWithPlugins()
{
$mailer = new Mailer();
$pluginClass = 'Swift_Plugins_ThrottlerPlugin';
$rate = 10;
$transportConfig = [
'class' => 'Swift_SmtpTransport',
'plugins' => [
[
'class' => $pluginClass,
'constructArgs' => [
$rate,
],
],
],
];
$mailer->setTransport($transportConfig);
$transport = $mailer->getTransport();
$this->assertTrue(is_object($transport), 'Unable to setup transport via config!');
$this->assertContains(':' . $pluginClass . ':', print_r($transport, true), 'Plugin not added');
}
public function testGetSwiftMailer() public function testGetSwiftMailer()
{ {
$mailer = new Mailer(); $mailer = new Mailer();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment