Commit 504d9fdb by Tobias Munk

Merge commit '33edfcff' into feature/issue-1160

parents 3fc4d5eb 33edfcff
......@@ -100,7 +100,7 @@ TESTING
-------
Install additional composer packages:
* `php composer.phar require --dev "codeception/codeception: 1.8.*@dev" "codeception/specify: *" "codeception/verify: *" "yiisoft/yii2-faker: *"`
* `php composer.phar require --dev "codeception/codeception: 2.0.*" "codeception/specify: *" "codeception/verify: *" "yiisoft/yii2-faker: *"`
This application boilerplate use database in testing, so you should create three databases that are used in tests:
* `yii2_advanced_unit` - database for unit tests;
......
<?php
use yii\helpers\Html;
/* @var $this \yii\web\View */
/* @var $content string */
/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\MessageInterface the message being composed */
/* @var $content string main view render result */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
......
......@@ -25,7 +25,7 @@
"yiisoft/yii2-gii": "*"
},
"suggest": {
"codeception/codeception": "Codeception, 1.8.*@dev is currently works well with Yii.",
"codeception/codeception": "Codeception, 2.0.* is currently works well with Yii.",
"codeception/specify": "BDD style code blocks for PHPUnit and Codeception",
"codeception/verify": "BDD Assertions for PHPUnit and Codeception",
"yiisoft/yii2-faker": "Fixtures generator for Yii2 based on Faker lib"
......
......@@ -14,7 +14,7 @@ return yii\helpers\ArrayHelper::merge(
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => '@console/tests/unit/fixtures/data',
'fixtureDataPath' => '@frontend/tests/unit/fixtures/data',
'templatePath' => '@common/tests/templates/fixtures'
],
],
......
......@@ -25,7 +25,7 @@
"yiisoft/yii2-gii": "*"
},
"suggest": {
"codeception/codeception": "Codeception, 1.8.*@dev is currently works well with Yii.",
"codeception/codeception": "Codeception, 2.0.* is currently works well with Yii.",
"codeception/specify": "BDD style code blocks for PHPUnit and Codeception",
"codeception/verify": "BDD Assertions for PHPUnit and Codeception"
},
......
<?php
use yii\helpers\Html;
/* @var $this \yii\web\View */
/* @var $content string */
/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\MessageInterface the message being composed */
/* @var $content string main view render result */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
......
......@@ -6,7 +6,7 @@ After creating the basic application, follow these steps to prepare for the test
1. Install additional composer packages:
```
php composer.phar require --dev "codeception/codeception: 1.8.*@dev" "codeception/specify: *" "codeception/verify: *"
php composer.phar require --dev "codeception/codeception: 2.0.*" "codeception/specify: *" "codeception/verify: *"
```
2. In the file `_bootstrap.php`, modify the definition of the constant `TEST_ENTRY_URL` so
that it points to the correct entry script URL.
......
Service Locator
===============
Service Locator является объектом, который знает, как обеспечить всевозможные службы (или компоненты), которые могут понадобиться в приложении.
В пределах Service Locator'а, каждый компонент имеет только один экземпляр, который уникально определяется с помощью идентификатора (ID).
Уникальный идентификатор (ID) может быть использован для извлечения компонента из Service Locator'а.
В Yii Service Locator является экземпляром класса [[yii\di\ServiceLocator]] или его дочернего класса.
Наиболее часто используемый Service Locator в Yii - это объект *приложения*, который можно получить через
`\Yii::$app`. Обеспечиваемые им службы называют *компонентами приложения*, такие, как компоненты `запрос`, `ответ`, `UrlManager`.
Вы легко можете настроить эти компоненты или даже заменить их собственными реализациями,
благодаря функциональным службам, предоставляемым Service Locator'ом.
Помимо объекта приложения, объект каждого модуля так же является Service Locator'ом.
Для использования Service Locator'а первым шагом является регистрация компонентов.
Компонент может быть зарегистрирован с помощью [[yii\di\ServiceLocator::set()]].
Следующий код демонстрирует различные способы регистрации компонентов:
```php
use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
// Зарегистрирует "cache", используя имя класса, которое может быть использовано для создания компонента.
$locator->set('cache', 'yii\caching\ApcCache');
// Зарегистрирует "db", используя конфигурационный массив, который может быть использован для создания компонента.
$locator->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
]);
// Зарегистрирует "search", используя анонимную функцию, которая создаёт компонент
$locator->set('search', function () {
return new app\components\SolrService;
});
// Зарегистрирует "pageCache", используя компонент
$locator->set('pageCache', new FileCache);
```
После того, как компонент зарегистрирован, вы можете получить к нему доступ, используя уникальный идентификатор (ID),
одним из двух следующих способов:
```php
$cache = $locator->get('cache');
// или альтернативный
$cache = $locator->cache;
```
Как видно выше, [[yii\di\ServiceLocator]] позволяет обратиться к компоненту, как к свойству,
при помощи идентификатора (ID) компонента.
При обращении к компоненту впервые, [[yii\di\ServiceLocator]] будет использовать информацию о регистрации компонента,
что бы создать новый экземпляр компонента и вернёт его.
В дальнейшем при обращении к компоненту снова, Service Locator вернёт тот же экземпляр.
Что бы проверить, был ли идентификатор (ID) компонента уже зарегистрирован, можно использовать [[yii\di\ServiceLocator::has()]].
Если вы вызовете [[yii\di\ServiceLocator::get()]] с недопустимым идентификатором (ID), тогда будет выброшено исключение.
Поскольку Service Locator`ы зачастую создаются с [конфигурациями](concept-configurations.md),
записываемое свойство с именем [[yii\di\ServiceLocator::setComponents()|components]] предоставляется так,
что Вы можете его настроить и зарегистрировать несколько компонентов одновременно.
Следующий код демонстрирует конфигурационный массив,
который может использоваться для настройки приложения и регистрации компонентов "db", "cache" и "search" :
```php
return [
// ...
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'search' => function () {
return new app\components\SolrService;
},
],
];
```
数据缓存
============
数据缓存是指将一些 PHP 变量存储到缓存中,使用时再从缓存中取回。
它也是更高级缓存特性的基础,例如 [查询缓存](#query-caching)[内容缓存](caching-content.md).
数据缓存是指将一些 PHP 变量存储到缓存中,使用时再从缓存中取回。它也是更高级缓存特性的基础,例如
[查询缓存](#query-caching)[分页缓存](caching-page.md).
如下代码是一个典型的数据缓存使用模式。其中 `$cache` 代表一个 [缓存组件](#cache-components):
......@@ -51,8 +51,8 @@ if ($data === false) {
然后你就可以通过 `Yii::$app->cache` 访问上面的缓存组件了。
由于所有缓存组件都支持同样的一系列 API ,你并不需要修改使用缓存的那些代码就能直接替换为其他低层缓存组件,
只需在应用程序配置中重新配置一下就可以。例如,你可以将上述配置修改为使用 [[yii\caching\ApcCache|APC cache]]:
由于所有缓存组件都支持同样的一系列 API
,你并不需要修改使用缓存的那些代码就能直接替换为其他低层缓存组件,只需在应用程序配置中重新配置一下就可以。例如,你可以将上述配置修改为使用 [[yii\caching\ApcCache|APC cache]]:
```php
......@@ -72,10 +72,8 @@ Yii 支持一系列缓存存储器,概况如下:
* [[yii\caching\ApcCache]]: 使用 PHP [APC](http://php.net/manual/en/book.apc.php) 扩展。这个选项可以认为是集中式应用程序环境中(例如:单一服务器,没有独立的负载均衡器等)最快的缓存方案。
* [[yii\caching\DbCache]]: 使用一个数据库的表存储缓存数据。要使用这个缓存,你必须创建一个 [[yii\caching\DbCache::cacheTable]] 对应的表。
* [[yii\caching\DummyCache]]: 仅作为一个缓存占位符,不实现任何真正的缓存功能。
这个组件的目的是为了简化那些需要查询缓存有效性的代码。例如,在开发中如果服务器没有实际的缓存支持,你就可以用它配置一个缓存组件。
一个真正的缓存服务启用后,就可以切换为使用相应的缓存组件。两种条件下你都可以使用同样的代码
`Yii::$app->cache->get($key)` 尝试从缓存中取回数据而不用担心 `Yii::$app->cache` 可能是 `null`
* [[yii\caching\DummyCache]]: 仅作为一个缓存占位符,不实现任何真正的缓存功能。 这个组件的目的是为了简化那些需要查询缓存有效性的代码。例如,在开发中如果服务器没有实际的缓存支持,你就可以用它配置一个缓存组件。 一个真正的缓存服务启用后,就可以切换为使用相应的缓存组件。两种条件下你都可以使用同样的代码
`Yii::$app->cache->get($key)` 尝试从缓存中取回数据而不用担心 `Yii::$app->cache` 可能是 `null`
* [[yii\caching\FileCache]]: 使用标准文件存储缓存数据。这个特别适用于缓存大块数据,例如一个网页的内容。
* [[yii\caching\MemCache]]: 使用 PHP [memcache](http://php.net/manual/en/book.memcache.php)
[memcached](http://php.net/manual/en/book.memcached.php) 扩展。这个选项可以认为是分布式应用程序环境中(例如:多台服务器,有负载均衡等)最快的缓存方案。
......
别名(Aliases)
=======
别名(译者注:指路径/URL 别名,简称别名)用作代表文件路径和 URL,主要为了避免在代码中硬编码一些绝对路径和
URL。一个别名必须以 `@` 字符开头,以区别于传统的文件/目录路径或 URL。举栗,别名 `@yii`
指的是 Yii 框架本身的安装目录,而 `@web` 表示的是当前运行应用的根 URL(base URL)。
定义别名 <a name="defining-aliases"></a>
----------------
你可以调用 [[Yii::setAlias()]] 来给指定路径/URL 定义别名。栗子:
```php
// 文件路径的别名
Yii::setAlias('@foo', '/path/to/foo');
// URL 的别名
Yii::setAlias('@bar', 'http://www.example.com');
```
> 注意:别名所指向的文件路径或 URL 不一定是真实存在的文件或资源哦。
用一个别名,你能通过在后面接续斜杠 `/` 以及若干路径片段得到一个新的别名(无需调用
[[Yii::setAlias()]])。我们把通过 [[Yii::setAlias()]] 定义的别名成为根别名
*root aliases*,而用他们衍生出去的别名成为衍生别名 *derived aliases*。比如,`@foo` 就是跟别名,而 `@foo/bar/file.php`
是一个衍生别名。
你还可以用别名定义新别名(根别名与衍生别名均可):
```php
Yii::setAlias('@foobar', '@foo/bar');
```
根别名通常在 [引导(bootstrapping)](runtime-bootstrapping.md) 阶段定义。比如你可以在
[入口脚本](structure-entry-scripts.md) 里调用 [[Yii::setAlias()]]。为了方便起见呢,[应用主体(Application)](structure-applications.md)
提供了一个名为 `aliases` 的可写属性,你可以在应用[配置文件](concept-configurations.md)中设置它,就像这样:
```php
return [
// ...
'aliases' => [
'@foo' => '/path/to/foo',
'@bar' => 'http://www.example.com',
],
];
```
解析别名 <a name="resolving-aliases"></a>
-----------------
你可以调用 [[Yii::getAlias()]] 命令来解析一个根别名到他所对应的文件路径或 URL。同样的页面也可以用于解析衍生别名。比如:
```php
echo Yii::getAlias('@foo'); // 显示:/path/to/foo
echo Yii::getAlias('@bar'); // 显示:http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // 显示:/path/to/foo/bar/file.php
```
由衍生别名所代指的路径/URL 是通过替换掉衍生别名中的根别名部分得到的。
> 注意:[[Yii::getAlias()]] 不检查结果路径/URL 所指向的资源是否真实存在。
根别名可能也会包含斜杠 `/` 字符。[[Yii::getAlias()]] 足够聪明,能知道一个别名中的哪个部分是根别名,因此能正确解析文件路径/URL。比如:
```php
Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@foo/bar', '/path2/bar');
Yii::getAlias('@foo/test/file.php'); // 显示:/path/to/foo/test/file.php
Yii::getAlias('@foo/bar/file.php'); // 显示:/path2/bar/file.php
```
`@foo/bar` 未被定义为根别名,最后一行语句会显示为 `/path/to/foo/bar/file.php`
使用别名 <a name="using-aliases"></a>
-------------
别名在 Yii 的很多地方都会被正确识别,而无需调用 [[Yii::getAlias()]]
来把它们转换为路径/URL。比如,[[yii\caching\FileCache::cachePath]] 能同时接受文件路径或是代表文件路径的别名,多亏了 `@` 前缀,它区分开了文件路径与别名。
```php
use yii\caching\FileCache;
$cache = new FileCache([
'cachePath' => '@runtime/cache',
]);
```
请关注下 API 文档了解属性或方法参数是否支持别名。
预定义的别名 <a name="predefined-aliases"></a>
------------------
Yii 预定义了一系列别名来简化频繁引用常用路径和 URL的需求。
在核心框架中已经预定义有以下别名:
- `@yii` - `BaseYii.php` 文件所在的目录(也被称为框架安装目录)
- `@app` - 当前运行的应用 [[yii\base\Application::basePath|根路径(base path)]]
- `@runtime` - 当前运行的应用的 [[yii\base\Application::runtimePath|运行环境(runtime)路径]]
- `@vendor` - [[yii\base\Application::vendorPath|Composer 供应商目录]]
- `@webroot` - 当前运行应用的 Web 入口目录
- `@web` - 当前运行应用的根 URL
`@yii` 别名是在[入口脚本](structure-entry-scripts.md)里包含 `Yii.php` 文件时定义的,其他的别名都是在[配置应用](concept-configurations.md)的时候,于应用的构造器内定义的。
扩展的别名 <a name="extension-aliases"></a>
-----------------
每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。该别名会以该扩展在 `composer.json`
文件中所声明的根命名空间为名,且他直接代指该包的根目录。比如,如果你安装有 `yiisoft/yii2-jui` 扩展,你会自动得到
`@yii/jui` 别名,它定义于[引导启动](runtime-bootstrapping.md)阶段:
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');
```
\ No newline at end of file
类自动加载(Autoloading)
=================
Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md)[中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。该自动加载器会在包含 `Yii.php` 文件时安装好。
> 注意:为了简化叙述,本篇文档中我们只会提及类的自动加载。不过,要记得文中的描述同样也适用于接口和Trait(特质)的自动加载哦。
使用 Yii 自动加载器 <a name="using-yii-autoloader"></a>
------------------------
要使用 Yii 的类自动加载器,你需要在创建和命名尼德类的时候遵循两个简单的规则:
* 每个类都必须置于命名空间之下 (比如 `foo\bar\MyClass`)。
* 每个类都必须保存为单独文件,且其完整路径能用以下算法取得:
```php
// $className 是一个开头包含反斜杠的完整类名(译者注:请自行谷歌:fully qualified class name)
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
```
举例来说,若某个类名为 `foo\bar\MyClass`,对应类的文件路径[别名](concept-aliases.md)会是
`@foo/bar/MyClass.php`。为了让该别名能被正确解析为文件路径,`@foo``@foo/bar`
中的一个必须是[根别名](concept-aliases.md#defining-aliases)
当我们使用[基本应用模版](start-basic.md)时,你可以把你的类放置在顶级命名空间 `app` 下,这样它们就可以被 Yii
自动加载,而无需定义一个新的别名。这是因为 `@app` 本身是一个[预定义别名](concept-aliases.md#predefined-aliases),且类似于 `app\components\MyClass` 这样的类名,基于我们刚才所提到的算法,可以正确解析出 `AppBasePath/components/MyClass.php` 路径。
[高级应用模版](tutorial-advanced-app.md)里,每一逻辑层级会使用他自己的根别名。比如,在前端层,会使用 `@frontend`
而后端层会使用 `@backend`。因此,你可以把前端的类放在 `frontend` 命名空间,而后端的类放在 `backend`。 这样这些类就可以被 Yii 自动加载了。
类映射表(Class Map) <a name="class-map"></a>
---------
Yii 类自动加载器支持 **类映射表** 功能,该功能会建立一个从类的名字到类文件路径的映射。当自动加载器加载一个文件时,他首先检查映射表里有没有该类。如果有,对应的文件路径就直接加载了,省掉了进一步的检查。它可以让类的自动加载变得炒鸡快!事实上,所有的 Yii 核心类都是这样加载的。
你可以用 `Yii::$classMap` 方法向映射表中添加类,
```php
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
```
[别名](concept-aliases.md)可以被用于指定类文件的路径。你应该在[引导启动](runtime-bootstrapping.md)的过程中设置类映射表,这样映射表就可以在你使用具体类之前就准备好。
用其他自动加载器 <a name="using-other-autoloaders"></a>
-----------------------
因为 Yii 完全支持 Composer 成为一个依赖包管理器,所以推荐你也同时安装 Composer 的自动加载器,如果你用了一些自带自动加载器的第三方类库,你应该也安装下它们。
在你同时使用其他自动加载器和 Yii 自动加载器的时候,你应该在其他自动加载器安装成功 **之后**,再包含`Yii.php`
文件。这将使 Yii 成为第一个响应任何类自动加载请求的自动加载器。举例来说,以下代码提取自[基本应用模版](start-basic.md)[入口脚本](structure-entry-scripts.md) 。第一行安装了 Composer 的自动加载器,第二行才是 Yii 的自动加载器:
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
你也可以只使用 Composer 的自动加载,而不用 Yii 的自动加载。不过这样做的话,类的加载效率会下降,且你必须遵循 Composer 所设定的规则,从而让你的类满足可以被自动加载的要求。
> 补充:若你不想要使用 Yii 的自动加载器,你必须创建一个你自己版本的 `Yii.php` 文件,并把它包含进你的[入口脚本](structure-entry-scripts.md)里。
自动加载扩展类 <a name="autoloading-extension-classes"></a>
-----------------------------
Yii 自动加载器支持自动加载[扩展](structure-extensions.md)的类。唯一的要求是它需要在 `composer.json`
文件里正确地定义 `autoload` 部分。请参考 [Composer 文档(英文)](https://getcomposer.org/doc/04-schema.md#autoload)[中文汉化](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#autoload)),来了解如何正确描述 `autoload` 的更多细节。
在你不使用 Yii 的自动加载器时,Composer 的自动加载器仍然可以帮你自动加载扩展内的类。
\ No newline at end of file
Yii 是什么
===========
Yii 是一个高性能的、基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作 `Yee``[ji:]`) 在汉语中的意
思是“简单、发展变化”。也可以看作是 **Yes It Is**! 的缩写。
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作
`易`)在中文里有“极致简单与不断变化”两重含义,也可看作 **Yes It Is**!的缩写
Yii 最适合做什么?
---------------------
Yii 是一个通用的 Web 编程框架,意味着它可以用于开发任意类型的 PHP Web 应用程序。由于它基于组件的架构和精致的缓存支持,它
特别适用于开发大型的应用程序,例门户,论坛,内容管理系统(CMS),电子商务项目,RESTful Web 服务等等。
Yii 是一个通用的 Web 编程框架,即可以用于开发各种基于 PHP 的
Web 应用。因为基于组件的框架结构和设计精巧的缓存支持,Yii 特别适合开发大型应用,如门户网站、论坛、内容管理系统(CMS)、电子商务项目和 RESTful Web 服务等。
Yii 和其他框架相比呢?
-------------------------------------------
- 和其他 PHP 框架类似,Yii 实现了 MVC(Model-View-Controller)设计模式并基于该模式组织代码。
- Yii 遵循一个哲学——代码要写的简单而又优雅。它永远不会为了要遵循某个设计模式而过度设计代码。
- Yii 是一个一站式框架,提供了大量经过验证的、入手可用的特性,例如:对关系型和NoSQL数据库都提供了查询构建器
(query builders)和 ActiveRecord;RESTful API 开发支持;多层缓存支持;还有更多。
- Yii 非常易于扩展。你可以自定义或替换几乎任何一处核心代码。你也会受益于它一致性的扩展架构,开发可再分发的扩展。
- 高性能始终是 Yii 的一个主要目标。
- Yii 的代码简洁优雅,这是 Yii 的编程哲学。它永远不会为了要迎合某个设计模式而对代码进行过度的设计。
- Yii 是一个全栈框架,提供了大量久经考验,开箱即用的特性,例如:对关系型和 NoSQL 数据库都提供了查询生成器(QueryBuilders)和 ActiveRecord;RESTful API 的开发支持;多层缓存支持;等等。
- Yii 非常易于扩展。你可以自定义或替换几乎任何一处核心代码。你还会受益于它坚实可靠的扩展架构,使用、再开发或再发布扩展。
- 高性能始终是 Yii 的首要目标之一。
Yii 不是一场独角戏,它有一个[强大的开发者团队][]提供支持,也有一个庞大的专家社区,持续不断地对Yii的开发作出贡献。
Yii 开发者团队始终对 Web 开发最新潮流和其他框架及项目中的优秀实践和特性保持密切的关注,其他地方出现的最相关优秀实践及
特性会被不定期的整合进核心框架中,并提供简单优雅的接口。
Yii 不是一场独角戏,它有一个[强大的开发者团队](http://www.yiiframework.com/about/)提供支持,也有一个庞大的专家社区,持续不断地对 Yii 的开发作出贡献。Yii 开发者团队始终对 Web 开发最新潮流和其他框架及项目中的最佳实践和特性保持密切的关注,那些有意义的最佳实践及特性会被不定期的整合进核心框架中,并提供简单优雅的接口。
[强大的开发者团队]: http://www.yiiframework.com/about/
Yii 版本
------------
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是一个旧版本,现在处于维护状态。2.0是一个彻底重写的 Yii,采用了最新的技术和协
议,包括 Composer,PSR,命名空间,trait 等等。 2.0 版本代表了最新一代的框架,是未来几年中的主力开发版本。本指南主要基于
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器(Composer)、PHP 代码规范(PSR)、命名空间、Traits(特质)等等。 2.0 版代表了最新一代框架,是未来几年中我们的主要开发版本。本指南主要基于
2.0 版本编写。
系统要求和前置条件
系统要求和先决条件
------------------------------
Yii 2.0 需要 PHP 5.4.0 或以上版本支持。你可以通过运行任何 Yii 发行包中附带的系统要求检查器查看每个具体特性所需的 PHP 配
置。
使用 Yii 需要对面向对象编程(OOP)有基本的了解,因为 Yii 是一个纯面向对象的框架。
Yii 2.0 还是用了 PHP 的最新特性,例如 [命名空间](http://www.php.net/manual/en/language.namespaces.php)
[trait](http://www.php.net/manual/en/language.oop5.traits.php)
理解这些概念有助于你更快地掌握 Yii 2.0。
使用 Yii 需要对面向对象编程(OOP)有基本了解,因为 Yii 是一个纯面向对象的框架。Yii 2.0 还使用了 PHP 的最新特性,例如 [命名空间](http://www.php.net/manual/en/language.namespaces.php)
[Trait(特质)](http://www.php.net/manual/en/language.oop5.traits.php)。理解这些概念将有助于你更快地掌握 Yii 2.0。
......@@ -141,6 +141,7 @@ Layout can be used to setup mail CSS styles or other shared content:
use yii\helpers\Html;
/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\MessageInterface the message being composed */
/* @var $content string main view render result */
?>
<?php $this->beginPage() ?>
......@@ -227,4 +228,4 @@ another one for the 'Message'.
You can use `yii\mail\BaseMailer` and `yii\mail\BaseMessage` as a base classes for your solution. These classes
already contains basic logic, which is described in this guide. However, their usage is not mandatory, it is enough
to implement `yii\mail\MailerInterface` and `yii\mail\MessageInterface` interfaces.
Then you need to implement all abstract methods to build you solution.
\ No newline at end of file
Then you need to implement all abstract methods to build you solution.
......@@ -63,7 +63,7 @@ class SiteController extends Controller
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'successCallback'],
],
]
];
}
public function successCallback($client)
......
......@@ -62,7 +62,9 @@ Yii Framework 2 Change Log
- Bug #3989: Fixed yii\log\FileTarget::$rotateByCopy to avoid any rename (cebe)
- Bug #3996: Traversing `Yii::$app->session` may cause a PHP error (qiangxue)
- Bug #4020: OCI column detection did not work so gii and other things failed (Sanya1991)
- Bug #4123: Trace level in logger had no effect in Targets, traces where not logged (cebe)
- Bug #4127: `CaptchaValidator` clientside error message wasn't formed properly (samdark)
- Bug #4162: Fixed bug where schema name was not used in ’SHOW CREATE TABLE’ query in `yii\db\mysql\Schema` (stevekr)
- Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark)
- Bug: URL encoding for the route parameter added to `\yii\web\UrlManager` (klimov-paul)
- Bug: Fixed the bug that requesting protected or private action methods would cause 500 error instead of 404 (qiangxue)
......@@ -121,6 +123,7 @@ Yii Framework 2 Change Log
- Removed character maps for non-latin languages.
- Improved overall slug results.
- Added note about the fact that intl is required for non-latin languages to requirements checker.
- Enh #3992: In mail layouts you can now access the message object via `$message` variable (qiangxue)
- Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq)
- Enh #4072: `\yii\rbac\PhpManager` adjustments (samdark)
- Data is now stored in three separate files for items, assignments and rules. File format is simpler.
......@@ -163,6 +166,7 @@ Yii Framework 2 Change Log
- Chg #3956: Flash messages set via `Yii::$app->session->setFlash()` will be removed only if they are accessed (qiangxue)
- Chg #3989: The default value for `yii\log\FileTarget::$rotateByCopy` now defaults to true to work on windows by default (cebe)
- Chg #4071: `mail` component renamed to `mailer`, `yii\log\EmailTarget::$mail` renamed to `yii\log\EmailTarget::$mailer` (samdark)
- Chg #4147: `BaseMailer::compose()` will not overwrite the `message` parameter if it is explicitly provided (qiangxue)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
- Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
......@@ -170,6 +174,7 @@ Yii Framework 2 Change Log
- Chg: Removed `yii\rest\ActiveController::$transactional` property and connected functionality (samdark)
- Chg: Changed the default value of the `keyPrefix` property of cache components to be null (qiangxue)
- Chg: Added `prefix` column to `yii\log\DbTarget` to have the same amount of information logged as in files and emails (cebe)
- Chg: Use `limit(null)` instead of `limit(-1)` in migration controller to be compatible to more backends (cebe)
- New #3911: Added `yii\behaviors\SluggableBehavior` that fills the specified model attribute with the transliterated and adjusted version to use in URLs (creocoder)
......
......@@ -328,7 +328,7 @@ abstract class BaseMigrateController extends Controller
}
// try mark down
$migrations = array_keys($this->getMigrationHistory(-1));
$migrations = array_keys($this->getMigrationHistory(null));
foreach ($migrations as $i => $migration) {
if (strpos($migration, $version . '_') === 0) {
if ($i === 0) {
......@@ -544,7 +544,7 @@ abstract class BaseMigrateController extends Controller
protected function migrateToTime($time)
{
$count = 0;
$migrations = array_values($this->getMigrationHistory(-1));
$migrations = array_values($this->getMigrationHistory(null));
while ($count < count($migrations) && $migrations[$count] > $time) {
++$count;
}
......@@ -575,7 +575,7 @@ abstract class BaseMigrateController extends Controller
}
// try migrate down
$migrations = array_keys($this->getMigrationHistory(-1));
$migrations = array_keys($this->getMigrationHistory(null));
foreach ($migrations as $i => $migration) {
if (strpos($migration, $version . '_') === 0) {
if ($i === 0) {
......@@ -598,7 +598,7 @@ abstract class BaseMigrateController extends Controller
protected function getNewMigrations()
{
$applied = [];
foreach ($this->getMigrationHistory(-1) as $version => $time) {
foreach ($this->getMigrationHistory(null) as $version => $time) {
$applied[substr($version, 1, 13)] = true;
}
......@@ -621,7 +621,7 @@ abstract class BaseMigrateController extends Controller
/**
* Returns the migration history.
* @param integer $limit the maximum number of records in the history to be returned
* @param integer $limit the maximum number of records in the history to be returned. `null` for "no limit".
* @return array the migration history
*/
abstract protected function getMigrationHistory($limit);
......
......@@ -716,7 +716,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
$changedAttributes = [];
foreach ($values as $name => $value) {
$changedAttributes[$name] = $this->_oldAttributes[$name];
$changedAttributes[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
$this->_oldAttributes[$name] = $value;
}
$this->afterSave(false, $changedAttributes);
......
......@@ -225,7 +225,7 @@ class Schema extends \yii\db\Schema
*/
protected function getCreateTableSql($table)
{
$row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteSimpleTableName($table->name))->queryOne();
$row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteTableName($table->fullName))->queryOne();
if (isset($row['Create Table'])) {
$sql = $row['Create Table'];
} else {
......
......@@ -47,6 +47,6 @@ class QueryParamAuth extends AuthMethod
*/
public function handleFailure($response)
{
throw new UnauthorizedHttpException('You are requesting with an invalid access token.');
throw new UnauthorizedHttpException(Yii::t('yii', 'You are requesting with an invalid access token.'));
}
}
......@@ -9,6 +9,7 @@ namespace yii\log;
use Yii;
use yii\base\Component;
use yii\base\ErrorHandler;
/**
* Dispatcher manages a set of [[Target|log targets]].
......@@ -183,7 +184,7 @@ class Dispatcher extends Component
} catch (\Exception $e) {
$target->enabled = false;
$targetErrors[] = [
'Unable to send log via '. get_class($target) .': ' . $e->getMessage(),
'Unable to send log via ' . get_class($target) . ': ' . ErrorHandler::convertExceptionToString($e),
Logger::LEVEL_WARNING,
__METHOD__,
microtime(true),
......
......@@ -235,9 +235,16 @@ abstract class Target extends Component
if (!is_string($text)) {
$text = VarDumper::export($text);
}
$traces = [];
if (isset($message[4])) {
foreach($message[4] as $trace) {
$traces[] = "in {$trace['file']}:{$trace['line']}";
}
}
$prefix = $this->getMessagePrefix($message);
return date('Y-m-d H:i:s', $timestamp) . " {$prefix}[$level][$category] $text";
return date('Y-m-d H:i:s', $timestamp) . " {$prefix}[$level][$category] $text"
. (empty($traces) ? '' : "\n " . implode("\n ", $traces));
}
/**
......
......@@ -144,6 +144,8 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
return Yii::createObject($config);
}
private $_message;
/**
* Creates a new message instance and optionally composes its body content via view rendering.
*
......@@ -167,30 +169,41 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
public function compose($view = null, array $params = [])
{
$message = $this->createMessage();
if ($view !== null) {
if ($view === null) {
return $message;
}
if (!array_key_exists('message', $params)) {
$params['message'] = $message;
if (is_array($view)) {
if (isset($view['html'])) {
$html = $this->render($view['html'], $params, $this->htmlLayout);
}
if (isset($view['text'])) {
$text = $this->render($view['text'], $params, $this->textLayout);
}
} else {
$html = $this->render($view, $params, $this->htmlLayout);
}
$this->_message = $message;
if (is_array($view)) {
if (isset($view['html'])) {
$html = $this->render($view['html'], $params, $this->htmlLayout);
}
if (isset($html)) {
$message->setHtmlBody($html);
if (isset($view['text'])) {
$text = $this->render($view['text'], $params, $this->textLayout);
}
if (isset($text)) {
$message->setTextBody($text);
} elseif (isset($html)) {
if (preg_match('|<body[^>]*>(.*?)</body>|is', $html, $match)) {
$html = $match[1];
}
$html = preg_replace('|<style[^>]*>(.*?)</style>|is', '', $html);
$message->setTextBody(strip_tags($html));
} else {
$html = $this->render($view, $params, $this->htmlLayout);
}
$this->_message = null;
if (isset($html)) {
$message->setHtmlBody($html);
}
if (isset($text)) {
$message->setTextBody($text);
} elseif (isset($html)) {
if (preg_match('|<body[^>]*>(.*?)</body>|is', $html, $match)) {
$html = $match[1];
}
$html = preg_replace('|<style[^>]*>(.*?)</style>|is', '', $html);
$message->setTextBody(strip_tags($html));
}
return $message;
}
......@@ -277,7 +290,7 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
{
$output = $this->getView()->render($view, $params, $this);
if ($layout !== false) {
return $this->getView()->render($layout, ['content' => $output], $this);
return $this->getView()->render($layout, ['content' => $output, 'message' => $this->_message], $this);
} else {
return $output;
}
......
......@@ -7,14 +7,14 @@ else
# basic application:
composer install --dev --prefer-dist -d apps/basic
cd apps/basic && composer require --dev codeception/codeception:1.8.*@dev codeception/specify:* codeception/verify:*
cd apps/basic && composer require --dev codeception/codeception:2.0.* codeception/specify:* codeception/verify:*
php vendor/bin/codecept build && cd ../..
# advanced application:
composer install --dev --prefer-dist -d apps/advanced
cd apps/advanced && composer require --dev codeception/codeception:1.8.*@dev codeception/specify:* codeception/verify:*
cd apps/advanced && composer require --dev codeception/codeception:2.0.* codeception/specify:* codeception/verify:*
./init --env=Development
sed -i s/root/travis/ common/config/main-local.php
cd backend && php ../vendor/bin/codecept build
......
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