Commit c745e416 by Paul Klimov

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

parents de60b411 990eb012
......@@ -16,7 +16,6 @@ use yii\web\IdentityInterface;
* @property string $password_reset_token
* @property string $email
* @property string $auth_key
* @property integer $role
* @property integer $status
* @property integer $created_at
* @property integer $updated_at
......@@ -26,7 +25,6 @@ class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const ROLE_USER = 10;
/**
* @inheritdoc
......@@ -54,9 +52,6 @@ class User extends ActiveRecord implements IdentityInterface
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]],
];
}
......
......@@ -20,7 +20,6 @@ class m130524_201442_init extends Migration
'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
'password_reset_token' => Schema::TYPE_STRING,
'email' => Schema::TYPE_STRING . ' NOT NULL',
'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
......
......@@ -48,8 +48,9 @@ class SignupForm extends Model
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save();
return $user;
if ($user->save()) {
return $user;
}
}
return null;
......
......@@ -58,12 +58,12 @@ class Alert extends \yii\bootstrap\Widget
foreach ($flashes as $type => $data) {
if (isset($this->alertTypes[$type])) {
$data = (array) $data;
foreach ($data as $message) {
foreach ($data as $i => $message) {
/* initialize css class for each alert box */
$this->options['class'] = $this->alertTypes[$type] . $appendCss;
/* assign unique id to each alert box */
$this->options['id'] = $this->getId() . '-' . $type;
$this->options['id'] = $this->getId() . '-' . $type . '-' . $i;
echo \yii\bootstrap\Alert::widget([
'body' => $message,
......
......@@ -59,5 +59,53 @@ codecept run functional
codecept run unit
```
Code coverage support
---------------------
By default, code coverage is disabled in `codeception.yml` configuration file, you should uncomment needed rows to be able
to collect code coverage. You can run your tests and collect coverage with the following command:
```
#collect coverage for all tests
codecept run --coverage-html --coverage-xml
#collect coverage only for unit tests
codecept run unit --coverage-html --coverage-xml
#collect coverage for unit and functional tests
codecept run functional,unit --coverage-html --coverage-xml
```
You can see code coverage output under the `tests/_output` directory.
###Remote code coverage
When you run your tests not in the same process where code coverage is collected, then you should uncomment `remote` option and its
related options, to be able to collect code coverage correctly. To setup remote code coverage you should follow [instructions](http://codeception.com/docs/11-Codecoverage)
from codeception site.
1. install `Codeception c3` remote support `composer require "codeception/c3:*"`;
2. copy `c3.php` file under your `web` directory;
3. include `c3.php` file in your `index-test.php` file before application run, so it can catch needed requests.
Configuration options that are used by remote code coverage:
- c3_url: url pointing to entry script that includes `c3.php` file, so `Codeception` will be able to produce code coverage;
- remote: whether to enable remote code coverage or not;
- remote_config: path to the `codeception.yml` configuration file, from the directory where `c3.php` file is located. This is needed
so that `Codeception` can create itself instance and collect code coverage correctly.
By default `c3_url` and `remote_config` setup correctly, you only need to copy and include `c3.php` file in your `index-test.php`
After that you should be able to collect code coverage from tests that run through `PhpBrowser` or `WebDriver` with same command
as for other tests:
```
#collect coverage from remote
codecept run acceptance --coverage-html --coverage-xml
```
Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for
more details about writing and running acceptance, functional and unit tests.
actor: Tester
#coverage:
# #c3_url: http://localhost:8080/index-test.php/
# enabled: true
# #remote: true
# #remote_config: '../tests/codeception.yml'
# white_list:
# include:
# - ../models/*
# - ../controllers/*
# - ../commands/*
# - ../mail/*
# blacklist:
# include:
# - ../assets/*
# - ../config/*
# - ../runtime/*
# - ../vendor/*
# - ../views/*
# - ../web/*
# - ../tests/*
paths:
tests: codeception
log: codeception/_output
......
......@@ -8,6 +8,7 @@
namespace yii\build\controllers;
use Yii;
use yii\base\Exception;
use yii\console\Controller;
/**
......@@ -30,6 +31,8 @@ class ReleaseController extends Controller
*/
public function actionPrepare($version)
{
$this->resortChangelogs($version);
$this->mergeChangelogs($version);
$this->closeChangelogs($version);
$this->composerSetStability($version);
$this->updateYiiVersion($version);
......@@ -77,9 +80,95 @@ class ReleaseController extends Controller
}
}
protected function resortChangelogs($version)
{
foreach($this->getChangelogs() as $file) {
// split the file into relevant parts
list($start, $changelog, $end) = $this->splitChangelog($file, $version);
$changelog = $this->resortChangelog($changelog);
file_put_contents($file, implode("\n", array_merge($start, $changelog, $end)));
}
}
protected function mergeChangelogs($version)
{
$file = $this->getFrameworkChangelog();
// split the file into relevant parts
list($start, $changelog, $end) = $this->splitChangelog($file, $version);
$changelog = $this->resortChangelog($changelog);
$changelog[] = '';
$extensions = $this->getExtensionChangelogs();
asort($extensions);
foreach($extensions as $changelogFile) {
if (!preg_match('~extensions/([a-z]+)/CHANGELOG\\.md~', $changelogFile, $m)) {
throw new Exception("Illegal extension changelog file: " . $changelogFile);
}
list( , $extensionChangelog, ) = $this->splitChangelog($changelogFile, $version);
$name = $m[1];
$ucname = ucfirst($name);
$changelog[] = "### $ucname Extension (yii2-$name)";
$changelog = array_merge($changelog, $extensionChangelog);
}
file_put_contents($file, implode("\n", array_merge($start, $changelog, $end)));
}
/**
* Extract changelog content for a specific version
*/
protected function splitChangelog($file, $version)
{
$lines = explode("\n", file_get_contents($file));
// split the file into relevant parts
$start = [];
$changelog = [];
$end = [];
$state = 'start';
foreach($lines as $l => $line) {
// starting from the changelogs headline
if (isset($lines[$l-2]) && strpos($lines[$l-2], $version) !== false &&
isset($lines[$l-1]) && strncmp($lines[$l-1], '---', 3) === 0) {
$state = 'changelog';
}
if ($state === 'changelog' && isset($lines[$l+1]) && strncmp($lines[$l+1], '---', 3) === 0) {
$state = 'end';
}
${$state}[] = $line;
}
return [$start, $changelog, $end];
}
/**
* Ensure sorting of the changelog lines
*/
protected function resortChangelog($changelog)
{
// cleanup whitespace
foreach($changelog as $i => $line) {
$changelog[$i] = rtrim($line);
}
// TODO sorting
return $changelog;
}
protected function getChangelogs()
{
return array_merge([YII2_PATH . '/CHANGELOG.md'], glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md'));
return array_merge([$this->getFrameworkChangelog()], $this->getExtensionChangelogs());
}
protected function getFrameworkChangelog()
{
return YII2_PATH . '/CHANGELOG.md';
}
protected function getExtensionChangelogs()
{
return glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md');
}
protected function composerSetStability($version)
......
......@@ -62,7 +62,7 @@ Conceptos clave
* [Componentes](concept-components.md)
* [Propiedades](concept-properties.md)
* **TBD** [Eventos](concept-events.md)
* [Eventos](concept-events.md)
* [Comportamientos (Behaviors)](concept-behaviors.md)
* [Configuraciones](concept-configurations.md)
* [Alias](concept-aliases.md)
......@@ -72,12 +72,16 @@ Conceptos clave
Trabajar con bases de datos
-----------------------------
* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y manipulación de esquemas
* **TBD** [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de abstracción
* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y definición de relaciones
* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en equipo
---------------------------
* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y
manipulación de esquemas
* [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de
abstracción
* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y
definición de relaciones
* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en
equipo
* **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md)
......@@ -102,7 +106,7 @@ Visualizar datos
* **TBD** [Proveedores de datos](output-data-providers.md)
* **TBD** [Widgets de datos](output-data-widgets.md)
* **TBD** [Trabajar con scripts de cliente](output-client-scripts.md)
* **TBD** [Utilización de temas](output-theming.md)
* [Temas](output-theming.md)
Seguridad
......@@ -193,7 +197,6 @@ Clases auxiliares
* **TBD** [Información general](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Security](helper-security.md)
Clase Auxiliar URL (URL Helper)
===============================
La clase auxiliar URL proporciona un conjunto de métodos estáticos para gestionar URLs.
Obtener URLs Comunes
--------------------
Se pueden usar dos métodos para obtener URLs comunes: URL de inicio (home URL) y URL base (base URL) de la petición
(request) actual. Para obtener la URL de inicio se puede usar el siguiente código:
```php
$relativeHomeUrl = Url::home();
$absoluteHomeUrl = Url::home(true);
$httpsAbsoluteHomeUrl = Url::home('https');
```
Si no se pasan parámetros, las URLs generadas son relativas. Se puede pasar `true`para obtener la URL absoluta del
esquema actual o especificar el esquema explícitamente (`https`, `http`).
Para obtener la URL base de la petición actual, se puede usar el siguiente código:
```php
$relativeBaseUrl = Url::base();
$absoluteBaseUrl = Url::base(true);
$httpsAbsoluteBaseUrl = Url::base('https');
```
El único parámetro del método funciona exactamente igual que para `Url::home()`.
Creación de URLs
----------------
Para crear una URL para una ruta determinada se puede usar `Url::toRoute()`. El metodo utiliza [[\yii\web\UrlManager]]
para crear una URL:
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
```
Se puede especificar la ruta como una cadena de texto, p. ej. `site/index`. También se puede usar un array si se
quieren especificar parámetros para la URL que se esta generando. El formato del array debe ser:
```php
// genera: /index.php?r=site/index&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
```
Si se quiere crear una URL con un enlace, se puede usar el formato de array con el parámetro `#`. Por ejemplo,
```php
// genera: /index.php?r=site/index&param1=value1#name
['site/index', 'param1' => 'value1', '#' => 'name']
```
Una ruta puede ser absoluta o relativa. Una ruta absoluta tiene una barra al principio (p. ej. `/site/index`),
mientras que una ruta relativa no la tiene (p. ej. `site/index` o `index`). Una ruta relativa se convertirá en una
ruta absoluta siguiendo las siguientes normas:
- Si la ruta es una cadena vacía, se usará la [[\yii\web\Controller::route|route]] actual;
- Si la ruta no contiene barras (p. ej. `index`), se considerará que es el ID de una acción del controlador actual y
se antepondrá con [[\yii\web\Controller::uniqueId]];
- Si la ruta no tiene barra inicial (p. ej. `site/index`), se considerará que es una ruta relativa del modulo actual y
se le antepondrá el [[\yii\base\Module::uniqueId|uniqueId]] del modulo.
A continuación se muestran varios ejemplos del uso de este método:
```php
// /index?r=site/index
echo Url::toRoute('site/index');
// /index?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// http://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', 'https');
```
El otro método `Url::to()` es muy similar a [[toRoute()]]. La única diferencia es que este método requiere que la ruta
especificada sea un array. Si se pasa una cadena de texto, se tratara como una URL.
El primer argumento puede ser:
- un array: se llamará a [[toRoute()]] para generar la URL. Por ejemplo: `['site/index']`,
`['post/index', 'page' => 2]`. Se puede revisar [[toRoute()]] para obtener más detalles acerca de como especificar
una ruta.
- una cadena que empiece por `@`: se tratará como un alias, y se devolverá la cadena correspondiente asociada a este
alias.
- una cadena vacía: se devolverá la URL de la petición actual;
- una cadena de texto: se devolverá sin alteraciones.
Cuando se especifique `$schema` (tanto una cadena de text como `true`), se devolverá una URL con información del host
(obtenida mediante [[\yii\web\UrlManager::hostInfo]]). Si `$url` ya es una URL absoluta, su esquema se reemplazará con
el especificado.
A continuación se muestran algunos ejemplos de uso:
```php
// /index?r=site/index
echo Url::to(['site/index']);
// /index?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// la URL solicitada actualmente
echo Url::to();
// /images/logo.gif
echo Url::to('@web/images/logo.gif');
// images/logo.gif
echo Url::to('images/logo.gif');
// http://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', true);
// https://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', 'https');
```
Recordar la URL para utilizarla más adelante
--------------------------------------------
Hay casos en que se necesita recordar la URL y después usarla durante el procesamiento de una de las peticiones
secuenciales. Se puede logar de la siguiente manera:
```php
// Recuerda la URL actual
Url::remember();
// Recuerda la URL especificada. Revisar Url::to() para ver formatos de argumentos.
Url::remember(['product/view', 'id' => 42]);
// Recuerda la URL especificada con un nombre asignado
Url::remember(['product/view', 'id' => 42], 'product');
```
En la siguiente petición se puede obtener la URL memorizada de la siguiente manera:
```php
$url = Url::previous();
$productUrl = Url::previous('product');
```
Reconocer la relatividad de URLs
--------------------------------
Para descubrir si una URL es relativa, es decir, que no contenga información del host, se puede utilizar el siguiente
código:
```php
$isRelative = Url::isRelative('test/it');
```
Temas
=====
> Nota: Esta sección está en desarrollo.
Un tema (theme) es un directorio de archivos y de vistas (views) y layouts. Cada archivo de este directorio
sobrescribe el archivo correspondiente de una aplicación cuando se renderiza. Una única aplicación puede usar
múltiples temas para que pueden proporcionar experiencias totalmente diferentes. Solo se puede haber un único tema
activo.
> Nota: Los temas no están destinados a ser redistribuidos ya que están demasiado ligados a la aplicación. Si se
quiere redistribuir una apariencia personalizada, se puede considerar la opción de
[asset bundles](structure-assets.md) de archivos CSS y Javascript.
Configuración de un Tema
------------------------
La configuración de un tema se especifica a través del componente `view` de la aplicación. Para establecer que un tema
trabaje con vistas de aplicación básicas, la configuración de la aplicación debe contener lo siguiente:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
],
],
],
```
En el ejemplo anterior, el `pathMap` define un mapa (map) de las rutas a las que se aplicará el tema mientras que
`baseUrl` define la URL base para los recursos a los que hacen referencia los archivos del tema.
En nuestro caso `pathMap` es `['@app/views' => '@app/themes/basic']`. Esto significa que cada vista de `@app/views`
primero se buscará en `@app/themes/basic` y si existe, se usará la vista del directorio del tema en lugar de la vista
original.
Por ejemplo, con la configuración anterior, la versión del tema para la vista `@app/views/site/index.php` será
`@app/themes/basic/site/index.php`. Básicamente se reemplaza `@app/views` en `@app/views/site/index.php` por
`@app/themes/basic`.
### Temas para Módulos
Para utilizar temas en los módulos, el `pathMap` debe ser similar al siguiente:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => [
'@app/views' => '@app/themes/basic',
'@app/modules' => '@app/themes/basic/modules', // <-- !!!
],
],
],
],
```
Esto permite aplicar el tema a `@app/modules/blog/views/comment/index.php` con la vista
`@app/themes/basic/modules/blog/views/comment/index.php`.
### Temas para Widgets
Para utilizar un tema en una vista que se encuentre en `@app/widgets/currency/views/index.php`, se debe aplicar la
siguiente configuración para el componente vista, tema:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/widgets' => '@app/themes/basic/widgets'],
],
],
],
```
Con la configuración anterior, se puede crear una versión de la vista `@app/widgets/currency/index.php` para que se
aplique el tema en `@app/themes/basic/widgets/currency/index.php`.
Uso de Multiples Rutas
----------------------
Es posible mapear una única ruta a múltiples rutas de temas. Por ejemplo:
```php
'pathMap' => [
'@app/views' => [
'@app/themes/christmas',
'@app/themes/basic',
],
]
```
En este caso, primero se buscara la vista en `@app/themes/christmas/site/index.php`, si no se encuentra, se intentará
en `@app/themes/basic/site/index.php`. Si la vista no se encuentra en ninguna de rutas especificadas, se usará la
vista de aplicación.
Esta capacidad es especialmente útil si se quieren sobrescribir algunas rutas temporal o condicionalmente.
\ No newline at end of file
......@@ -96,7 +96,7 @@ All Rights Reserved.
データの表示
------------
* [データの書式設定](output-formatter.md)
* [データのフォーマット](output-formatter.md)
* **TBD** [ページネーション](output-pagination.md)
* **TBD** [並べ替え](output-sorting.md)
* [データプロバイダ](output-data-providers.md)
......@@ -109,10 +109,10 @@ All Rights Reserved.
------------
* [認証](security-authentication.md)
* [権限](security-authorization.md)
* [権限付与](security-authorization.md)
* [パスワードを扱う](security-passwords.md)
* **TBD** [Auth クライアント](security-auth-clients.md)
* **TBD** [最善の慣行](security-best-practices.md)
* [ベストプラクティス](security-best-practices.md)
キャッシュ
......@@ -128,49 +128,49 @@ All Rights Reserved.
RESTful ウェブサービス
----------------------
* [クイックスタート](rest-quick-start.md)
* [リソース](rest-resources.md)
* [コントローラ](rest-controllers.md)
* [ルーティング](rest-routing.md)
* [レスポンスの書式設定](rest-response-formatting.md)
* [認証](rest-authentication.md)
* [転送レート制限](rest-rate-limiting.md)
* [バージョン管理](rest-versioning.md)
* [エラー処理](rest-error-handling.md)
* **翻訳未着手** [クイックスタート](rest-quick-start.md)
* **翻訳未着手** [リソース](rest-resources.md)
* **翻訳未着手** [コントローラ](rest-controllers.md)
* **翻訳未着手** [ルーティング](rest-routing.md)
* **翻訳未着手** [レスポンスの書式設定](rest-response-formatting.md)
* **翻訳未着手** [認証](rest-authentication.md)
* **翻訳未着手** [転送レート制限](rest-rate-limiting.md)
* **翻訳未着手** [バージョン管理](rest-versioning.md)
* **翻訳未着手** [エラー処理](rest-error-handling.md)
開発ツール
----------
* [デバッグツールバーとデバッガ](tool-debugger.md)
* [Gii を使ってコードを生成する](tool-gii.md)
* **翻訳未着手** [デバッグツールバーとデバッガ](tool-debugger.md)
* **翻訳未着手** [Gii を使ってコードを生成する](tool-gii.md)
* **TBD** [API ドキュメントを生成する](tool-api-doc.md)
テスト
------
* [概要](test-overview.md)
* [テスト環境の構築](test-environment-setup.md)
* [ユニットテスト](test-unit.md)
* [機能テスト](test-functional.md)
* [承認テスト](test-acceptance.md)
* [フィクスチャ](test-fixtures.md)
* **翻訳未着手** [概要](test-overview.md)
* **翻訳未着手** [テスト環境の構築](test-environment-setup.md)
* **翻訳未着手** [ユニットテスト](test-unit.md)
* **翻訳未着手** [機能テスト](test-functional.md)
* **翻訳未着手** [承認テスト](test-acceptance.md)
* **翻訳未着手** [フィクスチャ](test-fixtures.md)
スペシャルトピック
------------------
* [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md)
* [アプリケーションを一から構築する](tutorial-start-from-scratch.md)
* [コンソールコマンド](tutorial-console.md)
* [コアのバリデータ](tutorial-core-validators.md)
* [国際化](tutorial-i18n.md)
* [メール](tutorial-mailing.md)
* [パフォーマンスチューニング](tutorial-performance-tuning.md)
* [共有ホスト環境](tutorial-shared-hosting.md)
* [テンプレートエンジン](tutorial-template-engines.md)
* [サードパーティのコードを扱う](tutorial-yii-integration.md)
* **翻訳未着手** [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md)
* **翻訳未着手** [アプリケーションを一から構築する](tutorial-start-from-scratch.md)
* **翻訳未着手** [コンソールコマンド](tutorial-console.md)
* **翻訳未着手** [コアのバリデータ](tutorial-core-validators.md)
* **翻訳未着手** [国際化](tutorial-i18n.md)
* **翻訳未着手** [メール](tutorial-mailing.md)
* **翻訳未着手** [パフォーマンスチューニング](tutorial-performance-tuning.md)
* **翻訳未着手** [共有ホスト環境](tutorial-shared-hosting.md)
* **翻訳未着手** [テンプレートエンジン](tutorial-template-engines.md)
* **翻訳未着手** [サードパーティのコードを扱う](tutorial-yii-integration.md)
ウィジェット
......@@ -184,16 +184,16 @@ RESTful ウェブサービス
* Menu: **TBD** link to demo page
* LinkPager: **TBD** link to demo page
* LinkSorter: **TBD** link to demo page
* [Bootstrap ウィジェット](widget-bootstrap.md)
* [Jquery UI ウィジェット](widget-jui.md)
* **翻訳未着手** [Bootstrap ウィジェット](widget-bootstrap.md)
* **翻訳未着手** [Jquery UI ウィジェット](widget-jui.md)
ヘルパ
------
* [概要](helper-overview.md)
* [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* [Url](helper-url.md)
* **翻訳未着手** [概要](helper-overview.md)
* **翻訳未着手** [ArrayHelper](helper-array.md)
* **翻訳未着手** [Html](helper-html.md)
* **翻訳未着手** [Url](helper-url.md)
* **TBD** [Security](helper-security.md)
エイリアス
=======
ファイルパスや URL を表すのにエイリアスを使用すると、あなたはプロジェクト内で絶対パスや URL をハードコードする必要がなくなります。エイリアスは、通常のファイルパスや URL と区別するために、 `@` 文字で始まる必要があります。Yii はすでに利用可能な多くの事前定義エイリアスを持っています。
たとえば、 `@yii` というエイリアスは Yii フレームワークのインストールパスを表し、 `@web` は現在実行中の Web アプリケーションのベース 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は、必ずしも実在するファイルまたはリソースを参照しない場合があります。
定義済みのエイリアスがあれば、スラッシュ `/` に続けて 1 つ以上のパスセグメントを追加することで([[Yii::setAlias()]]
の呼び出しを必要とせずに) 新しいエイリアスを導出することができます。 [[Yii::setAlias()]] を通じて定義されたエイリアスは
*ルートエイリアス* となり、それから派生したエイリアスは *派生エイリアス* になります。たとえば、 `@foo` がルートエイリアスなら、
`@foo/bar/file.php` は派生エイリアスです。
エイリアスを、他のエイリアス (ルートまたは派生のいずれか) を使用して定義することができます:
```php
Yii::setAlias('@foobar', '@foo/bar');
```
ルートエイリアスは通常、 [ブートストラップ](runtime-bootstrapping.md) 段階で定義されます。
たとえば、[エントリスクリプト](structure-entry-scripts.md)[[Yii::setAlias()]] を呼び出すことができます。
便宜上、 [アプリケーション](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を解決することができます。
同メソッドで、対応するファイルパスまたは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は、派生エイリアス内のルートエイリアス部分を、対応するパス/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>
-------------
エイリアスは、それをパスやURLに変換するための [[Yii::getAlias()​]] の呼び出しがなくても、Yiiの多くの場所でみられます。
たとえば、 [[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|ベースパス]]
- `@runtime`, 現在実行中のアプリケーションの [[yii\base\Application::runtimePath|ランタイムパス]] 。デフォルトは `@app/runtime`
- `@webroot`, 現在実行中の Web アプリケーションの Web ルートディレクトリ。エントリスクリプトを含むディレクトリをもとに決定されます。
- `@web`, 現在実行中の Web アプリケーションのベース URL。これは、 [[yii\web\Request::baseUrl]] と同じ値を持ちます。
- `@vendor`, [[yii\base\Application::vendorPath|Composerのベンダーディレクトリ]] 。デフォルトは `@app/vendor`
- `@bower`, [bower パッケージ](http://bower.io/) が含まれるルートディレクトリ。デフォルトは `@vendor/bower`
- `@npm`, [npm パッケージ](https://www.npmjs.org/) が含まれるルートディレクトリ。デフォルトは `@vendor/npm`
`@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');
```
クラスのオートローディング
=================
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) に準拠した、高性能なクラスのオートローダーを提供します。
このオートローダーは、あなたが `Yii.php` ファイルをインクルードするときにインストールされます。
> 補足: 説明を簡単にするため、このセクションではクラスのオートローディングについてのみお話しします。しかし、
ここに記述されている内容は、同様に、インタフェースとトレイトのオートロードにも適用されることに注意してください。
Yii オートローダーの使用 <a name="using-yii-autoloader"></a>
------------------------
Yii のクラスオートローダーを使用するには、自分のクラスを作成して名前を付けるとき、次の2つの単純なルールに従わなければなりません:
* 各クラスは名前空間の下になければなりません (例 `foo\bar\MyClass`)
* 各クラスは次のアルゴリズムで決定される個別のファイルに保存されなければなりません:
```php
// $className は先頭にバックスラッシュを持つ完全修飾名
$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) でなければなりません。
[Basic Application Template](start-basic.md) を使用している場合、最上位の名前空間 `app` の下にクラスを置くことができ、
そうすると、新しいエイリアスを定義しなくても、Yii によってそれらをオートロードできるようになります。これは `@app`
[事前定義されたエイリアス](concept-aliases.md#predefined-aliases) であるためで、`app\components\MyClass` のようなクラス名を
今説明したアルゴリズムに従って、クラスファイル `AppBasePath/components/MyClass.php` だと解決できるのです。
[Advanced Application Template](tutorial-advanced-app.md) では、各階層にそれ自身のルートエイリアスを持っています。たとえば、
フロントエンド層はルートエイリアス `@frontend` を持ち、バックエンド層は `@backend` です。その結果、名前空間 `frontend` の下に
フロントエンドクラスを置き、バックエンドクラスを `backend` の下に置けます。これで、これらのクラスは Yii のオートローダーによって
オートロードできるようになります。
クラスマップ <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 のオートローダーが、任意クラスのオートローディング要求に応答する最初のものになります。
たとえば、次のコードは [Basic Application Template](start-basic.md)[エントリスクリプト](structure-entry-scripts.md) から抜粋したものです。
最初の行は、Composer のオートローダーをインストールしており、二行目は Yii のオートローダーをインストールしています。
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
あなたは Yii のオートローダーを使わず、Composer のオートローダーだけを単独で使用することもできます。しかし、そうすることによって、
あなたのクラスのオートローディングのパフォーマンスは低下し、クラスをオートロード可能にするために Composer が設定したルールに従わなければならなくなります。
> Info: Yiiのオートローダーを使用したくない場合は、 `Yii.php` ファイルの独自のバージョンを作成し、
それを [エントリスクリプト](structure-entry-scripts.md) でインクルードする必要があります。
エクステンションクラスのオートロード <a name="autoloading-extension-classes"></a>
-----------------------------
Yii のオートローダーは、 [エクステンション](structure-extensions.md) クラスのオートロードが可能です。唯一の要件は、
エクステンションがその `composer.json` ファイルに正しく `autoload` セクションを指定していることです。
`autoload` 指定方法の詳細については [Composer のドキュメント](https://getcomposer.org/doc/04-schema.md#autoload) 参照してください。
Yii のオートローダーを使用しない場合でも、まだ Composer のオートローダーはエクステンションクラスをオートロード可能です。
コンポーネント
==========
コンポーネントは、Yiiアプリケーションの主要な構成ブロックです。コンポーネントは [[yii\base\Component]] 、
またはその派生クラスのインスタンスです。コンポーネントが他のクラスに提供する主な機能は次の 3 つです:
* [プロパティ](concept-properties.md)
* [イベント](concept-events.md)
* [ビヘイビア](concept-behaviors.md)
個々にでも、組み合わせでも、これらの機能は Yii のクラスのカスタマイズ性と使いやすさをとても高めてくれます。たとえば、[[yii\jui\DatePicker|日付選択]] を行うユーザインターフェース·コンポーネントは、
対話型の日付選択UIを生成するとき、ビューで次のように使用することができます:
```php
use yii\jui\DatePicker;
echo DatePicker::widget([
'language' => 'ja',
'name' => 'country',
'clientOptions' => [
'dateFormat' => 'yy-mm-dd',
],
]);
```
クラスが [[yii\base\Component]] を継承しているおかげで、ウィジェットのプロパティは簡単に記述できます。
コンポーネントは非常に強力ですが、 [イベント](concept-events.md)[ビヘイビア](concept-behaviors.md) をサポートするため、
余分にメモリとCPU時間を要し、通常のオブジェクトよりも少し重くなります。
あなたのコンポーネントがこれら2つの機能を必要としない場合、[[yii\base\Component]] の代わりに、 [[yii\base\Object]] からコンポーネントクラスを派生することを検討してもよいでしょう。
そうすることで、あなたのコンポーネントは、 [プロパティ](concept-properties.md) のサポートが維持されたまま、通常のPHPオブジェクトのように効率的になります。
[[yii\base\Component]] または [[yii\base\Object]] からクラスを派生するときは、次の規約に従うことが推奨されます:
- コンストラクタをオーバーライドする場合は、コンストラクタの *最後の* パラメータとして `$config` パラメータを指定し、親のコンストラクタにこのパラメータを渡すこと。
- 自分がオーバーライドしたコンストラクタの *最後で* 、必ず親クラスのコンストラクタを呼び出すこと。
- [[yii\base\Object::init()]] メソッドをオーバーライドする場合は、自分の `init` メソッドの *最初に* 、必ず `init` の親実装を呼び出すようにすること。
例:
```php
namespace yii\components\MyClass;
use yii\base\Object;
class MyClass extends Object
{
public $prop1;
public $prop2;
public function __construct($param1, $param2, $config = [])
{
// ... 構成前の初期化
parent::__construct($config);
}
public function init()
{
parent::init();
// ... 構成後の初期化
}
}
```
このガイドラインに従うことで、あなたのコンポーネントは生成時に [コンフィグ可能](concept-configurations.md) になります。例:
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// とする代わりに
$component = \Yii::createObject([
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
```
> 補足: [[Yii::createObject()]] を呼び出すアプローチは複雑に見えますが、より強力です。というのも、それが [依存性注入コンテナ](concept-di-container.md) 上に実装されているからです。
[[yii\base\Object]] クラスには、次のオブジェクトライフサイクルが適用されます:
1. コンストラクタ内の事前初期化。ここでデフォルトのプロパティ値を設定することができます。
2. `$config` によるオブジェクトの構成。構成情報は、コンストラクタ内で設定されたデフォルト値を上書きすることがあります。
3. [[yii\base\Object::init()|init()]] 内の事後初期化。サニティ・チェックやプロパティの正規化を行いたいときは、このメソッドをオーバーライドします。
4. オブジェクトのメソッド呼び出し。
最初の 3 つのステップは、すべてのオブジェクトのコンストラクタ内で発生します。これは、あなたがクラスインスタンス (つまり、オブジェクト) を得たときには、
すでにそのオブジェクトが適切な、信頼性の高い状態に初期化されていることを意味します。
プロパティ
==========
PHPでは、クラスのメンバ変数は *プロパティ* とも呼ばれます。これらの変数は、クラス定義の一部で、クラスのインスタンスの状態を表すために
(すなわち、クラスのあるインスタンスを別のものと区別するために) 使用されます。現実によく、特別な方法でこのプロパティの読み書きを扱いたい
場合があります。たとえば、`label` プロパティに割り当てられる文字列が常にトリミングされるようにしたい、など。その仕事を成し遂げるために、
あなたは次のようなコードを使ってきたのではありませんか:
```php
$object->label = trim($label);
```
上記のコードの欠点は、 `label` プロパティを設定するすべてのコードで、`trim()` を呼び出す必要があるということです。もし将来的に、
`label` プロパティに、最初の文字を大文字にしなければならない、といった新たな要件が発生したら、 `label` に値を代入するすべてのコードを変更しなければなりません。コー​​ドの繰り返しはバグを誘発するので、できれば避けたいところです。
この問題を解決するために、Yii は *getter* メソッドと *setter* メソッドをベースにしたプロパティ定義をサポートする、 [[yii\base\Object]] 基底クラスを提供します。
クラスがその機能を必要とするなら、 [[yii\base\Object]] またはその子クラスを継承しましょう。
> 補足: Yiiのフレームワークのほぼすべてのコアクラスは、 [[yii\base\Object]] またはその子クラスを継承しています。
これは、コアクラスに getter または setter があれば、それをプロパティのように使用できることを意味します。
getter メソッドは、名前が `get` で始まるメソッドで、setter メソッドは、`set` で始まるメソッドです。
`get` または `set` プレフィクスの後の名前で、プロパティ名を定義します。次のコードに示すように、たとえば、`getLabel()` という getter と `setLabel()` という setter は、
`label` という名前のプロパティを定義します:
```php
namespace app\components;
use yii\base\Object;
class Foo extends Object
{
private $_label;
public function getLabel()
{
return $this->_label;
}
public function setLabel($value)
{
$this->_label = trim($value);
}
}
```
(詳しく言うと、getter および setter メソッドは、この場合には、内部的に `_label` と名付けられた private 属性を参照する `label` プロパティを作っています。)
getter と setter によって定義されたプロパティは、クラスのメンバ変数のように使用することができます。主な違いは、
それらのプロパティが読み取りアクセスされるときは、対応する getter ソッドが呼び出されることであり、プロパティに値が割り当てられるときには、
対応する setter メソッドが呼び出されるということです。例:
```php
// $label = $object->getLabel(); と同じ
$label = $object->label;
// $object->setLabel('abc'); と同じ
$object->label = 'abc';
```
setter なしの getter で定義されたプロパティは、 *読み取り専用* です。そのようなプロパティに値を代入しようとすると、
[[yii\base\InvalidCallException|InvalidCallException]] が発生します。同様に、getter なしの setter で定義されたプロパティは、
*書き込み専用* で、そのようなプロパティを読み取りしようとしても、例外が発生します。書き込み専用のプロパティを持つのは一般的ではありませんが。
getter と ​​setter で定義されたプロパティには、いくつかの特別なルールと制限があります:
* この種のプロパティでは、名前の *大文字と小文字を区別しません* 。たとえば、 `$object->label``$object->Label` は同じです。
これは、PHPのメソッド名が大文字と小文字を区別しないためです。
* この種のプロパティの名前と、クラスのメンバ変数の名前とが同じである場合、後者が優先されます。
たとえば、上記の `Foo` クラスがもしメンバ変数 `label` を持っているとすると、`$object->label = 'abc'`
という代入は *メンバ変数の* `label` に作用することになり、その行で `setLabel()` setter メソッドは呼び出されなくなります。
* これらのプロパティは可視性をサポートしていません。プロパティが public、protected、private であるかどうかで、
getter または setter メソッドの定義に違いは生じません。
* プロパティは、 *静的でない* getter および setter でしか定義できません。静的メソッドは同じようには扱われません。
このガイドの冒頭で説明した問題に戻ると、 `label` に値が代入されているあらゆる箇所で `trim()` を呼ぶのではなく、もう `setLabel()` という setter の内部だけで `trim()` を呼べば済むのです。
さらに、新しい要求でラベルの先頭を大文字にする必要が発生しても、他のいっさいのコードに触れることなく、すぐに `setLabel()` メソッドを変更することができます。一箇所の変更は、すべての `label` への代入に普遍的に作用します。
サービスロケータ
===============
サービスロケータは、アプリケーションが必要とする可能性のある各種のサービス (またはコンポーネント) を提供する方法を知っているオブジェクトです。
サービスロケータ内では、各コンポーネントは単一のインスタンスとして存在し、IDによって一意に識別されます。
あなたは、このIDを使用してサービスロケータからコンポーネントを取得できます。
Yii では、サービスロケータは単純に [[yii\di\ServiceLocator]] のインスタンス、または子クラスのインスタンスです。
Yii の中で最も一般的に使用されるサービスロケータは、 *アプリケーション* オブジェクトで、 `\Yii::$app`
を通じてアクセスできます。それが提供するサービスは、 *アプリケーションコンポーネント* と呼ばれ、それは `request`
`response``urlManager` のようなコンポーネントです。あなたはサービスロケータによって提供される機能を通じて、
簡単に、これらのコンポーネントを構成、あるいは独自の実装に置き換え、といったことができます。
アプリケーションオブジェクトの他に、各モジュールオブジェクトもまたサービスロケータです。
サービスロケータを使用する最初のステップは、コンポーネントを登録することです。コンポーネントは、 [[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);
```
いったんコンポーネントが登録されたら、次の 2 つの方法のいずれかで、その ID を使ってそれにアクセスすることができます:
```php
$cache = $locator->get('cache');
// または代わりに
$cache = $locator->cache;
```
以上のように、 [[yii\di\ServiceLocator]] はコンポーネント ID を使用したプロパティのように、コンポーネントにアクセスすることができます。
あなたが最初にコンポーネントにアクセスしたとき、 [[yii\di\ServiceLocator]] はコンポーネントの登録情報を使用してコンポーネントの新しいインスタンスを作成し、
それを返します。後でそのコンポーネントが再度アクセスされた場合、サービスロケータは同じインスタンスを返します。
[[yii\di\ServiceLocator::has()]] を使って、コンポーネント ID がすでに登録されているかをチェックできます。
無効なIDで [[yii\di\ServiceLocator::get()]] を呼び出した場合、例外がスローされます。
サービスロケータは多くの場合、 [構成情報](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;
},
],
];
```
......@@ -18,7 +18,7 @@ Yii はデフォルトで下記の DBMS をサポートしています。
- [CUBRID](http://www.cubrid.org/): バージョン 9.3 以上。(cubrid PDO 拡張の [バグ](http://jira.cubrid.org/browse/APIS-658)
のために、値を引用符で囲む機能が動作しません。そのため、サーバだけでなくクライアントも CUBRID 9.3 が必要になります)
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): バージョン 2005 以上。
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): バージョン 2008 以上。
構成
......@@ -199,7 +199,7 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
テーブルとカラムの名前を引用符で囲む
テーブルとカラムの名前を引用符で囲む <a name="quoting-table-and-column-names"></a>
------------------------------------
テーブルとカラムの名前をクエリの中で安全に使えるようにするために、Yii にそれらの名前を引用符で適切に囲ませることが出来ます。
......
Elasticsearch
=============
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
Mongo DB
========
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
Redis
=====
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
Sphinx Search
=============
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
ファイルをアップロードする
==========================
Yii におけるファイルのアップロードは、フォームモデル、その検証規則、そして、いくらかのコントローラコードによって行われます。
アップロードを適切に処理するために何が必要とされるのか、見ていきましよう。
一つのファイルをアップロードする
--------------------------------
まず最初に、ファイルのアップロードを処理するモデルを作成する必要があります。
次の内容を持つ `models/UploadForm.php` を作って作成してください。
```php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
/**
* UploadForm がアップロードのフォームの背後にあるモデルである。
*/
class UploadForm extends Model
{
/**
* @var UploadedFile file 属性
*/
public $file;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file'],
];
}
}
```
上記のコードにおいて作成した `UploadForm` というモデルは、HTML フォームで `<input type="file">` となる `$file` という属性を持ちます。
この属性は [[yii\validators\FileValidator|FileValidator]] を使用する `file` という検証規則を持ちます。
### フォームのビュー
次に、フォームを表示するビューを作成します。
```php
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>送信</button>
<?php ActiveForm::end() ?>
```
ファイルのアップロードを可能にする `'enctype' => 'multipart/form-data'` は不可欠です。
`fileInput()` がフォームの入力フィールドを表します。
### コントローラ
そして、フォームとモデルを結び付けるコントローラを作成します。
```php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file && $model->validate()) {
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
`model->load(...)` の代りに `UploadedFile::getInstance(...)` を使っています。
[[\yii\web\UploadedFile|UploadedFile]] はモデルの検証を実行せず、アップロードされたファイルに関する情報を提供するだけです。
そのため、`$model->validate()` を手作業で実行して、[[yii\validators\FileValidator|FileValidator]] を起動する必要があります。
[[yii\validators\FileValidator|FileValidator]] は、下記のコアコードが示しているように、属性がファイルであることを要求します。
```php
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []]; // "ファイルをアップロードしてください。" というエラーメッセージ
}
```
検証が成功したら、ファイルを保存します。
```php
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
```
「ベーシック」アプリケーションテンプレートを使っている場合は、`uploads` フォルダを `web` の下に作成しなければなりません。
以上です。ページをロードして、アップロードを試して見てください。ファイルは `basic/web/uploads` にアップロードされます。
検証
----
たいていの場合、検証規則を調整して、特定のファイルだけを受け取るようにしたり、アップロードを必須としたりする必要があります。
下記で、よく使われる規則の構成を見てみましよう。
### Required
ファイルのアップロードを必須とする必要がある場合は、次のように `skipOnEmpty``false` に設定します。
```php
public function rules()
{
return [
[['file'], 'file', 'skipOnEmpty' => false],
];
}
```
### MIME タイプ
アップロードされるファイルのタイプを検証することは賢明なことです。
`FileValidator` はこの目的のための `extensions` プロパティを持っています。
```php
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'gif, jpg',],
];
}
```
ただし、ファイル拡張子が検証されるだけで、実際のファイルの中身は検証されないことを憶えておいてください。
ファイルの中身も検証するためには、`FileValidator``mimeType` プロパティを使います。
```php
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'jpg, png', 'mimeTypes' => 'image/jpeg, image/png',],
];
}
```
[一般的なメディアタイプの一覧表](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### 画像のプロパティ
画像をアップロードするときは、[[yii\validators\ImageValidator|ImageValidator]] が重宝するでしょう。
このバリデータは、属性が有効な画像を受け取ったか否かを検証します。
その画像は、[Imagine エクステンション](https://github.com/yiisoft/yii2/tree/master/extensions/imagine) によって、保存するか、または、処理することが出来ます。
複数のファイルをアップロードする
--------------------------------
複数のファイルを一度にアップロードする必要がある場合は、少し修正が必要になります。
モデル:
```php
class UploadForm extends Model
{
/**
* @var UploadedFile|Null ファイル属性
*/
public $file;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file', 'maxFiles' => 10], // <--- ここ !
];
}
}
```
ビュー:
```php
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>送信</button>
<?php ActiveForm::end(); ?>
```
違いがあるのは、次の行です。
```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
```
コントローラ:
```php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
単一のファイルのアップロードとは、二つの点で異なります。
最初の違いは、`UploadedFile::getInstance($model, 'file');` の代りに `UploadedFile::getInstances($model, 'file');` が使用されることです。
前者が一つのインスタンスを返すだけなのに対して、後者はアップロードされた **全ての** ファイルのインスタンスを返します。
第二の違いは、`foreach` によって、全てのファイルをそれぞれ保存している点です。
フォームを扱う
==============
> Note|注意: この節はまだ執筆中です。
Yii においてフォームを使用する主たる方法は [[yii\widgets\ActiveForm]] によるものです。
フォームがモデルに基づくものである場合はこの方法を優先すべきです。
これに加えて、[[yii\helpers\Html]] にはいくつかの有用なメソッドがあり、通常は、あらゆるフォームにボタンやヘルプテキストを追加するのに使うことが出来ます。
モデルに基づくフォームを作成する場合、最初のステップは、モデルそのものを定義することです。
モデルは、アクティブレコードクラス、あるいは、もっと汎用的な Model クラスから派生させることが出来ます。
このログインフォームの例では、汎用的なモデルを使用します。
```php
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
/**
* @return array 検証規則
*/
public function rules()
{
return [
// username と password はともに必須
[['username', 'password'], 'required'],
// password は validatePassword() によって検証される
['password', 'validatePassword'],
];
}
/**
* パスワードを検証する
* このメソッドがパスワードのインライン検証に使用される
*/
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Incorrect username or password.');
}
}
/**
* 提供された username と password でユーザをログインさせる。
* @return boolean ユーザのログインが成功したかどうか
*/
public function login()
{
if ($this->validate()) {
$user = User::findByUsername($this->username);
return true;
} else {
return false;
}
}
}
```
コントローラはこのモデルのインスタンスをビューに渡し、ビューでは [[yii\widgets\ActiveForm|ActiveForm]] ウィジェットが使われます。
```php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
<?php $form = ActiveForm::begin([
'id' => 'login-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?= Html::submitButton('ログイン', ['class' => 'btn btn-primary']) ?>
</div>
</div>
<?php ActiveForm::end() ?>
```
上記のコードでは、[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] がフォームのインスタンスを作成するだけでなく、フォームの開始をマークしています。
[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] と [[yii\widgets\ActiveForm::end()|ActiveForm::end()]] の間に置かれた全てのコンテントが `<form>` タグによって囲まれます。
その他のウィジェットと同じように、ウィジェットをどのように構成すべきかに関するオプションを指定するために、`begin` メソッドに配列を渡すことが出来ます。
この例では、追加の CSS クラスと要素を特定するための ID が渡されて、開始 `<form>` タグに適用されています。
フォームの中で、フォームの要素を作成するために、ActiveForm ウィジェットの [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] メソッドが呼ばれています。このメソッドは、要素のラベルと、適用できる JavaScript の検証メソッドがあれば、それらも追加します。
このメソッドの呼び出し結果を直接にエコーすると、結果は通常の (text の) インプットになります。
出力結果をカスタマイズするためには、このメソッドの呼び出しに追加のメソッドをチェーンします。
```php
<?= $form->field($model, 'password')->passwordInput() ?>
// または
<?= $form->field($model, 'username')->textInput()->hint('お名前を入力してください')->label('お名前') ?>
```
これで、フォームのフィールドによって定義されたテンプレートに従って、`<label>``<input>` など、全てのタグが生成されます。
これらのタグを自分で追加するためには、`Html` ヘルパクラスを使うことが出来ます。
HTML5 のフィールドを使いたい場合は、次のように、インプットのタイプを直接に指定することが出来ます。
```php
<?= $form->field($model, 'email')->input('email') ?>
```
モデルの属性を指定するためには、もっと洗練された方法を使うことも出来ます。
例えば、複数のファイルをアップロードしたり、複数の項目を選択したりする場合に、属性の名前に `[]` を付けて、属性が配列の値を取り得ることを指定することが出来ます。
```php
// 複数のファイルのアップロードを許可する
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);
// 複数の項目をチェックすることを許可する
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
```
> **tip**|**ヒント**: 必須フィールドをアスタリスク付きのスタイルにするために、次の CSS を使うことが出来ます。
>
```css
div.required label:after {
content: " *";
color: red;
}
```
一つのフォームで複数のモデルを扱う
----------------------------------
時として、一つのフォームで同じ種類の複数のモデルを扱わなければならないことがあります。
例えば、それぞれが「名前-値」の形で保存され、`Setting` モデルとして表される複数の設定項目を扱うフォームです。
以下に、これを Yii で実装する方法を示します。
コントローラアクションから始めましよう。
```php
namespace app\controllers;
use Yii;
use yii\base\Model;
use yii\web\Controller;
use app\models\Setting;
class SettingsController extends Controller
{
// ...
public function actionUpdate()
{
$settings = Setting::find()->indexBy('id')->all();
if (Model::loadMultiple($settings, Yii::$app->request->post()) && Model::validateMultiple($settings)) {
foreach ($settings as $setting) {
$setting->save(false);
}
return $this->redirect('index');
}
return $this->render('update', ['settings' => $settings]);
}
}
```
上記のコードでは、データベースからモデルを読み出すときに `indexBy` を使って、モデルの ID でインデックスされた配列にモデルを代入しています。
このインデックスが、後で、フォームフィールドを特定するために使われます。
`loadMultiple` が POST から来るフォームデータを複数のモデルに代入し、`validateMultiple` が全てのモデルを一度に検証します。
保存するときの検証をスキップするために、`save` のパラメータに `false` を渡しています。
次に、`update` ビューにあるフォームです。
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($settings as $index => $setting) {
echo Html::encode($setting->name) . ': ' . $form->field($setting, "[$index]value");
}
ActiveForm::end();
```
ここで全ての設定項目について、それぞれ、名前と値を入れたインプットをレンダリングしています。
インプットの名前に適切なインデックスを追加することが肝腎です。
というのは、`loadMultiple` がそれを見て、どのモデルにどの値を代入するかを決定するからです。
複数のモデルを扱う複雑なフォーム
================================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
......@@ -29,8 +29,8 @@ Yii を他のフレームワークと比べるとどうか?
- 高性能であることは常に Yii の主たる目標です。
Yii はワンマンショーではありません。Yii は [強力なコア開発チーム][] および Yii 開発に間断なく貢献してくれるプロフェッショナルの大きなコミュニティーに支えられたプロジェクトです。
Yii 開発チームは最新のウェブ開発の潮流や、他のフレームワークやプロジェクトに見られる最善の慣行と機能から目を離しません。
他のところで見出された関連性の高い最善の慣行と機能は、定期的にコアフレームワークに組み込まれ、シンプルかつエレガントなインターフェイスを通じて公開されます。
Yii 開発チームは最新のウェブ開発の潮流や、他のフレームワークやプロジェクトに見られるベストプラクティスと機能から目を離しません。
他のところで見出された関連性の高いベストプラクティスと機能は、定期的にコアフレームワークに組み込まれ、シンプルかつエレガントなインターフェイスを通じて公開されます。
[強力なコア開発チーム]: http://www.yiiframework.com/about/
......
クライアントスクリプトを扱う
============================
> Note|注意: この節はまだ執筆中です。
### スクリプトを登録する
[[yii\web\View]] オブジェクトに対してスクリプトを登録することが出来ます。
このための専用のメソッドが二つあります。
すなわち、インラインスクリプトのための [[yii\web\View::registerJs()|registerJs()]] と、外部スクリプトのための [[yii\web\View::registerJsFile()|registerJsFile()]] です。
インラインスクリプトは、設定のためや、動的に生成されるコードのために有用なものです。
次のようにして、これらを追加するメソッドを使うことが出来ます。
```php
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
```
最初の引数は、ページに挿入したい実際の JS コードです。
二番目の引数は、スクリプトがページのどの場所に挿入されるべきかを決定します。
取りうる値は以下のとおりです。
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] - head セクション。
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] - 開始の `<body>` の直後。
- [[yii\web\View::POS_END|View::POS_END]] - 終了の `</body>` の直前。
- [[yii\web\View::POS_READY|View::POS_READY]] - ドキュメントの `ready` イベントで実行するコード。これを指定すると、[[yii\web\JqueryAsset|jQuery]] が自動的に登録されます。
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] - ドキュメントの `load` イベントで実行するコード。これを指定すると、[[yii\web\JqueryAsset|jQuery]] が自動的に登録されます。
最後の引数は、スクリプトのユニークな ID です。これによってコードブロックを一意に特定し、同じ ID のスクリプトが既にある場合は、新しいものを追加するのでなく、それを置き換えます。
ID を指定しない場合は、JS コードそれ自身が ID として扱われます。
外部スクリプトは次のようにして追加することが出来ます。
```php
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [JqueryAsset::className()]]);
```
[[yii\web\View::registerJsFile()|registerJsFile()]] の引数は [[yii\web\View::registerCssFile()|registerCssFile()]] のそれと同じです。
上記の例では、`main.js` ファイルを `JqueryAsset` に依存するものとして登録しています。
これは、`main.js` ファイルが `jquery.js` の後に追加されるようになることを意味します。
この依存関係を指定しない場合は、`main.js``jquery.js` の相対的な順序は未定義となります。
[[yii\web\View::registerCssFile()|registerCssFile()]] と同じように、外部 JS ファイルを登録するのに [[yii\web\View::registerJsFile()|registerJsFile()]] を使わずに、[アセットバンドル](structure-assets.md) を使うことが強く推奨されます。
### アセットバンドルを登録する
既に述べたように、CSS と JavaScript を直接に使う代りにアセットバンドルを使うことが望まれます。
アセットバンドルを定義する方法の詳細は、ガイドの [アセットマネージャ](structure-assets.md) の節で知ることが出来ます。
既に定義されているアセットバンドルを使うことについては、次のように非常に簡明です。
```php
\frontend\assets\AppAsset::register($this);
```
### CSS を登録する
[[yii\web\View::registerCss()|registerCss()]] またはr [[yii\web\View::registerCssFile()|registerCssFile()]] を使って CSS を登録することが出来ます。
前者は CSS のコードブロックを登録し、後者は外部 CSS ファイルを登録します。
例えば、
```php
$this->registerCss("body { background: #f00; }");
```
上記のコードは、以下の内容をページの head セクションに追加する結果となります。
```html
<style>
body { background: #f00; }
</style>
```
`style` タグに追加のプロパティを指定したい場合は、三番目の引数として「名前-値」のペアの配列を渡します。
`style` タグが一つだけになることを保証する必要がある場合は、メタタグの説明で言及したように、4番目の引数を使います。
```php
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
'depends' => [BootstrapAsset::className()],
'media' => 'print',
], 'css-print-theme');
```
上記のコードは、ページの head セクションに CSS ファイルへのリンクを追加します。
* 最初の引数が登録されるべき CSS ファイルを指定します。
* 二番目の引数は、結果として生成される `<link>` タグの HTML 属性を指定するものです。
ただし、`depends` オプションは特別な処理を受けます。
このオプションは、この CSS ファイルが依存するアセットバンドルを指定するものです。
この例では、依存するアセットバンドルは [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] です。
これは、この CSS ファイルが、[[yii\bootstrap\BootstrapAsset|BootstrapAsset]] に含まれる CSS ファイルの *後* に追加されることを意味します。
* 最後の引数は、この CSS ファイルを特定するための ID を指定するものです。
指定されていない場合は、CSS ファイルの URL が代りに ID として使用されます。
外部 CSS ファイルを登録するためには、[[yii\web\View::registerCssFile()|registerCssFile()]] を使うのではなく、[アセットバンドル](structure-assets.md) を使うことが強く推奨されます。
アセットバンドルを使うと、複数の CSS ファイルを結合して圧縮することが可能になります。
トラフィックの多いウェブサイトではそうすることが望まれます。
データプロバイダ
================
> Note|注意: この節はまだ執筆中です。
データプロバイダは、 [[yii\data\DataProviderInterface]] によってデータセットを抽象化し、ページネーションと並べ替えを処理します。
[グリッドやリストなどのデータウィジェット](output-data-widgets.md) で使用することが出来ます。
Yii は三つのデータプロバイダを内蔵しています。すなわち、[[yii\data\ActiveDataProvider]]、[[yii\data\ArrayDataProvider]] そして [[yii\data\SqlDataProvider]] です。
アクティブデータプロバイダ
--------------------------
`ActiveDataProvider`[[yii\db\Query]] および [[yii\db\ActiveQuery]] を使って DB クエリを実行して、データを提供します。
次のコードは、これを使って、ActiveRecord のインスタンスを提供する例です。
```php
$provider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
そして次の例は、ActiveRecord なしで ActiveDataProvider を使う方法を示すものです。
```php
$query = new Query();
$provider = new ActiveDataProvider([
'query' => $query->from('post'),
'sort' => [
// デフォルトのソートを name ASC, created_at DESC とする
'defaultOrder' => [
'name' => SORT_ASC,
'created_at' => SORT_DESC
]
],
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
配列データプロバイダ
--------------------
ArrayDataProvider はデータの配列に基づいたデータプロバイダを実装するものです。
[[yii\data\ArrayDataProvider::$allModels]] プロパティが、並べ替えやページネーションの対象となるデータの全てのモデルを含みます。
ArrayDataProvider は、並べ替えとページネーションを実行した後に、データを提供します。
[[yii\data\ArrayDataProvider::$sort]] および [[yii\data\ArrayDataProvider::$pagination]] のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。
[[yii\data\ArrayDataProvider::$allModels]] 配列の要素は、オブジェクト (例えば、モデルのオブジェクト) であるか、連想配列 (例えば、DAO のクエリ結果) であるかの、どちらかです。
[[yii\data\ArrayDataProvider::$key]] プロパティには、必ず、データレコードを一意的に特定出来るフィールドの名前をセットするか、そのようなフィールドがない場合は `false` をセットするかしなければなりません。
`ActiveDataProvider` と比較すると、`ArrayDataProvider` は、[[yii\data\ArrayDataProvider::$allModels]] を準備して持たなければならないため、効率が良くありません。
`ArrayDataProvider` は次のようにして使用することが出来ます。
```php
$query = new Query();
$provider = new ArrayDataProvider([
'allModels' => $query->from('post')->all(),
'sort' => [
'attributes' => ['id', 'username', 'email'],
],
'pagination' => [
'pageSize' => 10,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
> Note|注意: 並べ替えの機能を使いたいときは、どのカラムがソート出来るかをプロバイダが知ることが出来るように、[[sort]] プロパティを構成しなければなりません。
SQL データプロバイダ
--------------------
SqlDataProvider は、素の SQL 文に基づいたデータプロバイダを実装するものです。
これは、各要素がクエリ結果の行を表す配列の形式でデータを提供します。
他のプロバイダ同様に、SqlDataProvider も、並べ替えとページネーションをサポートしています。
並べ替えとページネーションは、与えられた [[yii\data\SqlDataProvider::$sql]] 文を "ORDER BY" 句および "LIMIT" 句で修正することによって実行されます。
[[yii\data\SqlDataProvider::$sort]] および [[yii\data\SqlDataProvider::$pagination]] のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。
`SqlDataProvider` は次のようにして使用することが出来ます。
```php
$count = Yii::$app->db->createCommand('
SELECT COUNT(*) FROM user WHERE status=:status
', [':status' => 1])->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => 'SELECT * FROM user WHERE status=:status',
'params' => [':status' => 1],
'totalCount' => $count,
'sort' => [
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
],
],
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの user のレコードを取得する
$models = $dataProvider->getModels();
```
> Note|注意: ページネーションの機能を使いたい場合は、[[yii\data\SqlDataProvider::$totalCount]] プロパティに (ページネーション無しの) 総行数を設定しなければなりません。
そして、並べ替えの機能を使いたい場合は、どのカラムがソート出来るかをプロバイダが知ることが出来るように、[[yii\data\SqlDataProvider::$sort]] プロパティを構成しなければなりません。
あなた自身のカスタムデータプロバイダを実装する
----------------------------------------------
(内容未定)
ページネーション
================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
並べ替え
========
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
テーマ
======
> Note|注意: この節はまだ執筆中です。
テーマとは、あるディレクトリの下に集められたビューとレイアウトのファイルです。
テーマの各ファイルが、アプリケーションの対応するファイルをレンダリングの際にオーバーライドします。
一つのアプリケーションは複数のテーマを使用することが可能で、それぞれのテーマはまったく異なるユーザ体験を提供することが出来ます。
いつでも一つのテーマだけがアクティブになり得ます。
> Note|注意: ビューはアプリケーションの固有性が強いものですので、通常は、テーマを再配布可能なものとして作ることはしません。
カスタマイズしたルックアンドフィールを再配布したい場合は、テーマの代りに、[アセットバンドル](structure-assets.md) の形で CSS と JavaScript のファイルを再配布することを検討してください。
テーマを構成する
----------------
テーマの構成情報は、アプリケーションの `view` コンポーネントを通じて指定します。
`basic application` のビューに対して働くテーマをセットアップするためには、アプリケーションの構成情報ファイルに以下のように記述しなければなりません。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
],
],
],
```
上記においては、`pathMap` が元のパスからテーマのパスへの割り付けを定義し、`baseUrl` がテーマのファイルによって参照されるリソースのベース URL を定義しています。
私たちの例では、`pathMap``['@app/views' => '@app/themes/basic']` です。
これは、`@app/views` の全てのビューは、最初に `@app/themes/basic` の下で探され、そのテーマのディレクトリにビューが存在していれば、それが元のビューの代りに使われる、ということを意味します。
例えば、上記の構成においては、ビューファイル `@app/views/site/index.php` のテーマ版は `@app/themes/basic/site/index.php` になります。
基本的には、`@app/views/site/index.php``@app/views``@app/themes/basic` に置き換えるわけです。
ランタイムにおいてテーマを構成するためには、ビューをレンダリングする前に次のコードを使用することが出来ます。
典型的には、コントローラの中に次のコードを置きます。
```php
$this->getView()->theme = Yii::createObject([
'class' => '\yii\base\Theme',
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
]);
```
### モジュールにテーマを適用する
モジュールにテーマを適用するためには、`pathMap` を次のようなものにすることが出来ます。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => [
'@app/views' => '@app/themes/basic',
'@app/modules' => '@app/themes/basic/modules', // <-- !!!
],
],
],
],
```
これによって、`@app/modules/blog/views/comment/index.php``@app/themes/basic/modules/blog/views/comment/index.php` というテーマを適用することが出来ます。
### ウィジェットにテーマを適用する
`@app/widgets/currency/views/index.php` に配置されているウィジェットのビューにテーマを適用するためには、ビューコンポーネントのテーマに、次のような構成情報を設定する必要があります。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/widgets' => '@app/themes/basic/widgets'],
],
],
],
```
上記の構成によって、`@app/widgets/currency/index.php` ビューのテーマ版を `@app/themes/basic/widgets/currency/index.php` として作成することが出来るようになります。
複数のパスを使う
----------------
一つのパスを複数のテーマパスに割り付けることが出来ます。例えば、
```php
'pathMap' => [
'@app/views' => [
'@app/themes/christmas',
'@app/themes/basic',
],
]
```
この場合、最初に `@app/themes/christmas/site/index.php` というビューファイルが探され、それが見つからない場合は、次に `@app/themes/basic/site/index.php` が探されます。
そして、そこにもビューがない場合は、アプリケーションのビューが使用されます。
この機能は、いくつかのビューを一時的または条件的にオーバーライドしたい場合に、特に役立ちます。
......@@ -438,7 +438,7 @@ URL 規則のパターンには、ウェブサーバ名を含むことが出来
> Tip|ヒント: URL が全てスラッシュで終るようにするためには、URL 接尾辞として `/` を設定することが出来ます。
> Note|注意: URL 接尾辞を構成すると、リクエストされた URL が接尾辞を持たない場合は、認識できない URL であると見なされるようになります。
SEO の目的からも、これが推奨される慣行です。
SEO の目的からも、これが推奨されるプラクティスです。
場合によっては、URL によって異なる接尾辞を使いたいことがあるでしょう。
その目的は、個々の URL 規則の [[yii\web\UrlRule::suffix|suffix]] プロパティを構成することによって達成できます。
......
Auth クライアント
=================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
認証
====
> Note|注意: この節はまだ執筆中です。
認証はユーザが誰であるかを確認する行為であり、ログインプロセスの基礎となるものです。
典型的には、認証は、識別子 (ユーザ名またはメールアドレス) とパスワードの組み合わせを使用します。
ユーザはこれらの値をフォームを通じて送信し、アプリケーションは送信された情報を以前に (例えば、ユーザ登録時に) 保存された情報と比較します。
Yii では、このプロセス全体が半自動的に実行されます。
開発者に残されているのは、認証システムにおいて最も重要なクラスである [[yii\web\IdentityInterface]] を実装することだけです。
典型的には、`IdentityInterface` の実装は `User` モデルを使って達成されます。
十分な機能を有する認証の実例を [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md) の中に見出すことが出来ます。
下記にインターフェイスのメソッドだけをリストします。
```php
class User extends ActiveRecord implements IdentityInterface
{
// ...
/**
* 与えられた ID によって識別子を探す
*
* @param string|integer $id 探すための ID
* @return IdentityInterface|null 与えられた ID に合致する識別子オブジェクト
*/
public static function findIdentity($id)
{
return static::findOne($id);
}
/**
* 与えられたトークンによって識別子を探す
*
* @param string $token 探すためのトークン
* @return IdentityInterface|null 与えられたトークンに合致する識別子オブジェクト
*/
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
/**
* @return int|string 現在のユーザの ID
*/
public function getId()
{
return $this->id;
}
/**
* @return string 現在のユーザの認証キー
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
* @param string $authKey
* @return boolean 認証キーが現在のユーザに対して有効か否か
*/
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
}
```
概要を述べたメソッドのうち、二つは単純なものです。
`findIdentity` は ID の値を受け取って、その ID と関連付けられたモデルのインスタンスを返します。
`getId` メソッドは ID そのものを返します。
その他のメソッドのうち、二つのもの - `getAuthKey``validateAuthKey` - は、「次回から自動ログイン ("remember me")」のクッキーに対して追加のセキュリティを提供するために使われます。
`getAuthKey` メソッドは全てのユーザに対してユニークな文字列を返さなければなりません。
`Yii::$app->getSecurity()->generateRandomString()` を使うと、信頼性の高い方法でユニークな文字列を生成することが出来ます。
これをユーザのレコードの一部として保存しておくのが良いアイデアです。
```php
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($this->isNewRecord) {
$this->auth_key = Yii::$app->getSecurity()->generateRandomString();
}
return true;
}
return false;
}
```
`validateAuthKey` メソッドでは、パラメータとして渡された `$authKey` 変数 (これ自体はクッキーから読み出されます) をデータベースから読み出された値と比較する必要があるだけです。
セキュリティのベストプラクティス
================================
下記において、一般的なセキュリティの指針を復習し、Yii を使ってアプリケーションを開発するときに脅威を回避する方法を説明します。
基本的な指針
------------
どのようなアプリケーションが開発されているかに関わらず、セキュリティに関しては二つの大きな指針が存在します。
1. 入力をフィルタする。
2. 出力をエスケープする。
### 入力をフィルタする
入力をフィルタするとは、入力値は決して安全なものであると見なさず、取得した値が実際に許可さていれる値に含まれるか否かを常にチェックしなければならない、ということを意味します。
つまり、並べ替えが三つのフィールド `title``created_at` および `status` によって実行され、フィールドの値がインプットによって提供されるものであることを知っている場合、取得した値を受信するその場でチェックする方が良い、ということです。
基本的な PHP の形式では、次のようなコードになります。
```php
$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
throw new Exception('Invalid sort value.');
}
```
Yii においては、たいていの場合、同様のチェックを行うために [フォームのバリデーション](input-validation.md) を使うことになるでしょう。
### 出力をエスケープする
データを使用するコンテキストに応じて、出力をエスケープしなければなりません。
つまり、HTML のコンテキストでは、`<``>` などの特殊な文字をエスケープしなければなりません。
JavaScript や SQL のコンテキストでは、対象となる文字は別のセットになります。
全てを手動でエスケープするのは間違いを生じやすいことですから、Yii は異なるコンテキストに応じたエスケープを実行するためのさまざまなツールを提供しています。
SQL インジェクションを回避する
------------------------------
SQL インジェクションは、次のように、エスケープされていない文字列を連結してクエリテキストを構築する場合に発生します。
```php
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
```
正しいユーザ名を提供する代りに、攻撃者は `'; DROP TABLE user; --` のような文字列をあなたのアプリケーションに与えることが出来ます。
結果として構築される SQL は次のようになります。
```sql
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
```
これは有効なクエリで、空のユーザ名を持つユーザを探してから、`user` テーブルを削除します。
おそらく、ウェブサイトは破壊されて、データは失われることになります (定期的なバックアップは設定済みですよね、ね? )。
Yii においては、ほとんどのデータベースクエリは、PDO のプリペアドステートメントを適切に使用する [アクティブレコード](db-active-record.md) を経由して実行されます。
プリペアドステートメントの場合は、上で説明したようなクエリの改竄は不可能です。
それでも、[生のクエリ](db-dao.md)[クエリビルダ](db-query-builder.md) を必要とする場合はあります。
その場合には、データを渡すための安全な方法を使わなければなりません。
データをカラムの値として使う場合は、プリペアドステートメントを使うことが望まれます。
```php
// query builder
$userIDs = (new Query())
->select('id')
->from('user')
->where('status=:status', [':status' => $status])
->all();
// DAO
$userIDs = $connection
->createCommand('SELECT id FROM user where status=:status')
->bindValues([':status' => $status])
->queryColumn();
```
データがカラム名やテーブル名を指定するために使われる場合は、事前定義された一連の値だけを許可するのが最善の方法です。
```php
function actionList($orderBy = null)
{
if (!in_array($orderBy, ['name', 'status'])) {
throw new BadRequestHttpException('名前とステータスだけを並べ替えに使うことが出来ます。')
}
// ...
}
```
それが不可能な場合は、テーブル名とカラム名をエスケープしなければなりません。
Yii はそういうエスケープのための特別な文法を持っており、それを使うと、サポートされている全てのデータベースに対して同じ方法でエスケープすることが出来ます。
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
この文法の詳細は、[テーブルとカラムの名前を引用符で囲む](db-dao.md#quoting-table-and-column-names) で読むことが出来ます。
XSS を回避する
--------------
XSS すなわちクロスサイトスクリプティングは、ブラウザに HTML を出力する際に、出力が適切にエスケープされていないと発生します。
例えば、ユーザ名を入力できるフォームで `Alexander` の代りに `<script>alert('Hello!');</script>` と入力した場合、ユーザ名をエスケープせずに出力している全てのページでは、JavaScript `alert('Hello!');` が実行されて、ブラウザにアラートボックスがポップアップ表示されます。
ウェブサイト次第では、そのようなスクリプトを使って、無害なアラートではなく、あなたの名前を使ってメッセージを送信したり、さらには銀行取引を実行したりすることが可能です。
XSS の回避は、Yii においてはとても簡単です。一般に、二つのケースがあります。
1. データを平文テキストとして出力したい。
2. データを HTML として出力したい。
平文テキストしか必要でない場合は、エスケープは次のようにとても簡単です。
```php
<?= \yii\helpers\Html::encode($username) ?>
```
HTML である場合は、HtmlPurifier から助けを得ることが出来ます。
```php
<?= \yii\helpers\HtmlPurifier::process($description) ?>
```
HtmlPurifier の処理は非常に重いので、キャッシュを追加することを検討してください。
CSRF を回避する
---------------
TBD: what's CSRF, how it works, intro
1. HTTP の規格に従うこと、すなわち、GET はアプリケーションの状態を変更すべきではない。
2. Yii の CSRF 保護を有効にしておくこと。
TBD: how CSRF protection works
ファイルの曝露を回避する
------------------------
デフォルトでは、サーバのウェブルートは、`index.php` がある `web` ディレクトリを指すように意図されています。
共有ホスティング環境の場合、それをすることが出来ずに、全てのコード、構成情報、ログをサーバのウェブルートの下に置かなくてはならないことがあり得ます。
そういう場合には、`web` 以外の全てに対してアクセスを拒否することを忘れないでください。
それも出来ない場合は、アプリケーションを別の場所でホストすることを検討してください。
実運用環境ではデバッグ情報とデバッグツールを無効にする
------------------------------------------------------
デバッグモードでは、Yii は極めて多くのエラー情報を出力します。これは確かに開発には役立つものです。
しかし、実際の所、これらの饒舌なエラー情報は、攻撃者にとっても、データベース構造、構成情報の値、コードの断片などを曝露してくれる重宝なものです。
実運用のアプリケーションにおいては、決して `index.php``YII_DEBUG``true` にして走らせてはいけません。
実運用環境では Gii を決して有効にしてはいけません。
Gii を使うと、データベース構造とコードに関する情報を得ることが出来るだけでなく、コードを Gii によって生成したもので書き換えることすら出来てしまいます。
デバッグツールバーは本当に必要でない限り実運用環境では使用を避けるべきです。
これはアプリケーションと構成情報の全ての詳細を曝露することが出来ます。
どうしても必要な場合は、あなたの IP だけに適切にアクセス制限されていることを再度チェックしてください。
セキュリティ
============
> Note|注意: この節はまだ執筆中です。
十分なセキュリティは、どのようなアプリケーションであっても、健全さを保って成功するためには欠くことが出来ないものです。
不幸なことに、理解が不足しているためか、実装の難易度が高すぎるためか、セキュリティのことになると手を抜く開発者がたくさんいます。
Yii によって駆動されるアプリケーションを可能な限り安全にするために、Yii はいくつかの優秀な使いやすいセキュリティ機能を内蔵しています。
ハッシュとパスワードの検証
--------------------------
ほとんどの開発者はパスワードを平文テキストでは保存できないということを知っていますが、パスワードを `md5``sha1` でハッシュしてもまだ安全だと思っている開発者がたくさんいます。
かつては、前述のハッシュアルゴリズムを使えば十分であった時もありましたが、現代のハードウェアをもってすれば、そのようなハッシュはブルートフォースアタックを使って非常に簡単に復元することが可能です。
最悪のシナリオ (アプリケーションに侵入された場合) であっても、ユーザのパスワードについて強化されたセキュリティを提供することが出来るように、ブルートフォースアタックに対する耐性が強いハッシュアルゴリズムを使う必要があります。
現在、最善の選択は `bcrypt` です。
PHP では、[crypt 関数](http://php.net/manual/ja/function.crypt.php) を使って `bcrypt` ハッシュを生成することが出来ます。
Yii は `crypt` を使ってハッシュを安全に生成し検証することを容易にする二つのヘルパ関数を提供します。
ユーザが初めてパスワードを提供するとき (例えば、ユーザ登録の時) には、パスワードをハッシュする必要があります。
```php
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
```
そして、ハッシュを対応するモデル属性と関連付けて、後で使用するためにデータベースに保存します。
ユーザがログインを試みたときは、送信されたパスワードは、前にハッシュされて保存されたパスワードと照合して検証されます。
```php
if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// よろしい、ユーザをログインさせる
} else {
// パスワードが違う
}
```
擬似乱数データを生成する
------------------------
擬似乱数データはさまざまな状況で役に立ちます。
例えば、メール経由でパスワードをリセットするときは、トークンを生成してデータベースに保存し、それをユーザにメールで送信します。
そして、ユーザはこのトークンを自分がアカウントの所有者であることの証拠として使用します。
このトークンがユニークかつ推測困難なものであることは非常に重要なことです。
さもなくば、攻撃者がトークンの値を推測してユーザのパスワードをリセットする可能性があります。
Yii のセキュリティヘルパは擬似乱数データの生成を単純な作業にしてくれます。
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
暗号論的に安全な乱数データを生成するためには、`openssl` 拡張をインストールしている必要があることに注意してください。
暗号化と復号化
--------------
Yii は秘密鍵を使ってデータを暗号化/復号化することを可能にする便利なヘルパ関数を提供しています。
データを暗号化関数に渡して、秘密鍵を持つ者だけが復号化することが出来るようにすることが出来ます。
例えば、何らかの情報をデータベースに保存する必要があるけれども、(たとえアプリケーションのデータベースが第三者に漏洩した場合でも) 秘密鍵を持つユーザだけがそれを見ることが出来るようにする必要がある、という場合には次のようにします。
```php
// $data と $secretKey はフォームから取得する
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// $encryptedData をデータベースに保存する
```
そして、後でユーザがデータを読みたいときは、次のようにします。
```php
// $secretKey はユーザ入力から取得、$encryptedData はデータベースから取得
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
データの完全性を確認する
------------------------
データが第三者によって改竄されたり、更には何らかの形で毀損されたりしていないことを確認する必要がある、という場合があります。
Yii は二つのヘルパ関数の形で、データの完全性を確認するための簡単な方法を提供しています。
秘密鍵とデータから生成されたハッシュをデータにプレフィクスします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$genuineData は信頼できるソースから取得
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
データの完全性が毀損されていないかチェックします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$data は信頼できないソースから取得
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```
todo: XSS prevention, CSRF prevention, cookie protection, refer to 1.1 guide
プロパティを設定することによって、CSRF バリデーションをコントローラ および/または アクション単位で無効にすることも出来ます。
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF バリデーションはこのアクションおよびその他のアクションに適用されない
}
}
```
特定のアクションに対して CSRF バリデーションを無効にするためには、次のようにします。
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ... ここで、何らかの条件に基づいて `$this->enableCsrfValidation` をセットする ...
// 親のメソッドを呼ぶ。プロパティが true なら、その中で CSRF がチェックされる。
return parent::beforeAction($action);
}
}
```
クッキーを安全にする
--------------------
- validation
- httpOnly is default
参照
----
以下も参照してください。
- [ビューのセキュリティ](structure-views.md#security)
......@@ -33,3 +33,4 @@ Gii をコード生成に使うと、ウェブ開発のプロセスの大部分
- Facebook: <https://www.facebook.com/groups/yiitalk/>
- Twitter: <https://twitter.com/yiiframework>
- LinkedIn: <https://www.linkedin.com/groups/yii-framework-1483367>
- Stackoverflow: <http://stackoverflow.com/questions/tagged/yii2>
......@@ -305,7 +305,7 @@ if (YII_ENV_DEV) {
#### [[yii\base\Application::params|params]] <a name="params"></a>
このプロパティは、グローバルにアクセス可能なアプリケーションパラメータの配列を規定します。
コードの中のいたる処でハードコードされた数値や文字列を使う代りに、それらをアプリケーションパラメータとして一ヶ所で定義し、必要な場所ではそのパラメータを使うというのが良い慣行です。
コードの中のいたる処でハードコードされた数値や文字列を使う代りに、それらをアプリケーションパラメータとして一ヶ所で定義し、必要な場所ではそのパラメータを使うというのが良いプラクティスです。
例えば、次のように、サムネール画像のサイズをパラメータとして定義することが出来ます。
```php
......
......@@ -418,7 +418,7 @@ class SiteController extends Controller
6. アプリケーションはアクションの結果を受け取り、それを [レスポンス](runtime-responses.md) に割り当てる。
## 最善の慣行<a name="best-practices"></a>
## ベストプラクティス<a name="best-practices"></a>
良く設計されたアプリケーションでは、コントローラはたいてい非常に軽いものになり、それぞれのアクションは数行のコードしか含まないものになります。
あなたのコントローラが少々複雑になっている場合、そのことは、通常、コントローラをリファクタして、コードの一部を他のクラスに移動すべきことを示すものです。
......
......@@ -229,10 +229,10 @@ Composer が Bower または NPM のパッケージをインストールする
例えば、上記の `autoload` の宣言は、`@yii/imagine` という名前のエイリアスに対応することになります。
### 推奨される慣行 <a name="recommended-practices"></a>
### 推奨されるプラクティス <a name="recommended-practices"></a>
エクステンションは他の人々によって使われることを意図したものですから、多くの場合、追加の開発努力が必要になります。
以下に、高品質のエクステンションを作成するときによく用いられ、また推奨される慣行のいくつかを紹介します。
以下に、高品質のエクステンションを作成するときによく用いられ、また推奨されるプラクティスのいくつかを紹介します。
#### 名前空間 <a name="namespaces"></a>
......@@ -345,7 +345,7 @@ Yii はテストのサポートを提供しており、それよって、ユニ
#### バージョン管理 <a name="versioning"></a>
エクステンションのリリースごとにバージョン番号 (例えば `1.0.1`) を付けるべきです。
どのようなバージョン番号を付けるべきかを決定するときは、[セマンティックバージョニング](http://semver.org)慣行に従うことを推奨します。
どのようなバージョン番号を付けるべきかを決定するときは、[セマンティックバージョニング](http://semver.org)プラクティスに従うことを推奨します。
#### リリース(公開) <a name="releasing"></a>
......
......@@ -460,7 +460,7 @@ public function fields()
> および `password_reset_token` を選んで除去しています。
## 最善の慣行<a name="best-practices"></a>
## ベストプラクティス<a name="best-practices"></a>
モデルは、業務のデータ、規則、ロジックを表わす中心的なオブジェクトです。
モデルは、さまざまな場所で再利用される必要がよくあります。
......
......@@ -236,7 +236,7 @@ class Module extends \yii\base\Module
このリストには、直接の子と孫以下の両方のモジュールが含まれ、クラス名によってインデックスされています。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
モジュールは、それぞれ密接に関係する一連の機能を含む数個のグループに分割できるような、規模の大きなアプリケーションに最も適しています。
そのような機能グループをそれぞれモジュールとして、特定の個人やチームによって開発することが出来ます。
......
......@@ -680,7 +680,7 @@ http://localhost/index.php?r=site/page&view=about
[[yii\web\ViewAction::viewPrefix]] を構成して、ビューを探すディレクトリを変更することが出来ます。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
ビューはエンドユーザが望む形式でモデルを表現することに対して責任を持ちます。一般的に、ビューは
......
......@@ -172,7 +172,7 @@ public function run()
[[yii\base\Widget::getViewPath()]] メソッドをオーバーライドして、ウィジェットのビューファイルを含むディレクトリをカスタマイズすることが出来ます。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
ウィジェットはビューのコードを再利用するためのオブジェクト指向の方法です。
......
......@@ -74,14 +74,14 @@ Conceitos Chave
Trabalhando com Banco de Dados
------------------------------
* [Data Access Objects (DAO, Objeto de Acesso a Dados)](db-dao.md) - Estabelecendo uma conexão com o Banco de Dados, consultas básicas, transações e manipulação do esquema
* [Query Builder (Construtor de Consulta)](db-query-builder.md) - Consultando o banco de dados usando uma camada de abstração simples
* [Active Record](db-active-record.md) - Sobre o Active Record ORM, recuperando e manipulando registros e definindo relacionamentos
* [Migrations (Migrações)](db-migrations.md) - Aplica controle de versão para seus banco de dados em um ambiente de desenvolvimento em equipe
* [Data Access Objects (DAO, Objeto de Acesso a Dados)](db-dao.md)? Estabelecendo uma conexão com o Banco de Dados, consultas básicas, transações e manipulação do esquema
* [Query Builder (Construtor de Consulta)](db-query-builder.md)? Consultando o banco de dados usando uma camada de abstração simples
* [Active Record](db-active-record.md): Sobre o Active Record ORM, recuperando e manipulando registros e definindo relacionamentos
* [Migrations (Migrações)](db-migrations.md): Aplica controle de versão para seus banco de dados em um ambiente de desenvolvimento em equipe
* **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md)
* **TBD** [ElasticSearch](db-elastic-search.md)
* **TBD** [ElasticSearch](db-elasticsearch.md)
Coletando Dados de Usuários
......@@ -96,7 +96,7 @@ Coletando Dados de Usuários
Exibindo Dados
---------------
* [Formatando Dados](output-formatting.md)
* [Formatando Dados](output-formatter.md)
* **TBD** [Paginação](output-pagination.md)
* **TBD** [Ordenação](output-sorting.md)
* [Data Providers (Provedores de Dados)](output-data-providers.md)
......@@ -125,7 +125,7 @@ Cache
* [Cache HTTP](caching-http.md)
Web Services com RESTful
Web Services RESTful
------------------------
* [Introdução](rest-quick-start.md)
......@@ -151,7 +151,7 @@ Testes
------
* [Visão Geral](test-overview.md)
* [Configuração do ambiente de testes](test-endvironment-setup.md)
* [Configuração do ambiente de testes](test-environment-setup.md)
* [Testes Unitários](test-unit.md)
* [Testes Funcionais](test-functional.md)
* [Testes de Aceitação](test-acceptance.md)
......@@ -184,16 +184,16 @@ Widgets
* Menu: **TBD** link para a página de demonstração
* LinkPager: **TBD** link para a página de demonstração
* LinkSorter: **TBD** link para a página de demonstração
* [Widgets do Bootstrap](bootstrap-widgets.md)
* [Widgets do Jquery UI](jui-widgets.md)
* [Widgets do Bootstrap](widget-bootstrap.md)
* [Widgets do Jquery UI](widget-jui.md)
Helpers
-------
* [Visão Geral](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md)
* [ArrayHelper](helper-array.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Segurança](helper-security.md)
......@@ -6,8 +6,24 @@ ou baixando um arquivo compactado. O primeiro modo é o preferido, já que permi
que você instale novas [extensões](structure-extensions.md) ou atualize o
Yii simplesmente executando um único comando.
> Note: Ao contrário do Yii 1, as instalações padrão do Yii 2 resultam em
tanto o framework quanto um esqueleto de aplicação sendo baixados e instalados.
A instalação do Yii padrão resulta no download e instalação tanto do framework
quanto de um template de aplicação.
Um template de aplicação é uma aplicação do Yii implementando algumas recursos básicos,
como a autenticação, o formulário de contato, etc.
Este código é organizado de uma forma recomendada. No entanto, ele pode servir
como ponto de partida para seus projetos.
Nesta e nas próximas seções, iremos descrever como instalar o *Template Básico de
Aplicação* do Yii e como implementar novas funcionalidades em cima deste template.
O Yii também fornece um outro template chamado de [Template Avançado de Aplicação](tutorial-advanced-app.md) que é melhor usado em uma equipe de desenvolvimento que desenvolvem
aplicações de multiplas camadas.
> Informação: O Template Básico de Aplicação é adequado para o desenvolvimento de
cerca de 90% das aplicações Web. Este template difere do Template Avançado de
Aplicação principalmente na forma de como o seu código é organizado. Se você é
novo no Yii, recomendamos fortemente em escolher o Template Básico de Aplicação
pela sua simplicidade além de ter funcionalidades o suficiente.
If you are new to Yii, we strongly recommend you stick to the Basic Application Template for its simplicity yet sufficient functionalities.
Instalando via Composer <a name="installing-via-composer"></a>
......@@ -39,15 +55,12 @@ o que permite gerenciar dependências via bower e npm package por meio do Compos
Você apenas precisa rodar este comando uma vez. O segundo comando instala o Yii
em um diretório chamado `basic`. Você pode escolher um diretório diferente se quiser.
> Nota: Durante a instalação do Yii pode acontecer que o Composer peça suas
> credenciais de login do Github por ultrapassar taxa limite (rate-limit) da API do Github.
> Isso é normal pois o Composer necessita obter muitas informações de todos os
> pacotes no Github.
> Logando no Github incrementa a taxa limite (rate-limit) da API para que o Composer
> possa continuar o seu trabalho. Para mais detalhes, por favor consulte a
> [documentação do Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Observação: Durante a instalação, o Composer pode pedir suas credenciais de login
> do Github. Isto é normal, pelo fato do Composer precisar obter a taxa limite
> (rate-limit) da API para recuperar as informações de dependência de pacotes do
> Github. Para mais detalhes, consulte a [documentação do Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Tip: Se você quiser instalar a última versão de desenvolvimento do Yii, você
> Dica: Se você quiser instalar a última versão de desenvolvimento do Yii, você
> pode usar o seguinte comando, que adiciona uma [opção de estabilidade](https://getcomposer.org/doc/04-schema.md#minimum-stability):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
......@@ -78,8 +91,9 @@ Outras Opções de Instalação <a name="other-installation-options"></a>
As instruções de instalação acima mostram como instalar o Yii, que também cria
uma aplicação Web básica que funciona imediatamente sem qualquer configuração ou
modificação (*out of the box*). Este método é um bom ponto de início para projetos
pequenos ou para quando você começar a aprender o Yii.
modificação (*out of the box*).
Esta abordagem é um bom ponto de partida para a maioria dos projetos, seja ele
pequeno ou grande. É especialmente adequado se você acabou de começar a aprender Yii.
No entanto, existem outras opções de instalação disponíveis:
......
......@@ -39,7 +39,7 @@
php /path/to/yii-application/init
```
Для производственных сервером удобно выполнять данную команду в неинтерактивном режиме.
Для производственных серверов удобно выполнять данную команду в неинтерактивном режиме.
```
php /path/to/yii-application/init --env=Production overwrite=All
......@@ -139,7 +139,7 @@
- `frontend/config/main.php`
- `frontend/config/main-local.php`
Парамтры считываются в следующем порядке:
Параметры считываются в следующем порядке:
- `common/config/params.php`
- `common/config/params-local.php`
......
......@@ -49,7 +49,7 @@ All Rights Reserved.
* [Огляд](runtime-overview.md)
* [Bootstrapping](runtime-bootstrapping.md)
* [Роутінг та створення URL](runtime-routing.md)
* [Маршрутизація та створення URL](runtime-routing.md)
* [Запити](runtime-requests.md)
* [Відповіді](runtime-responses.md)
* [Сесії та кукі](runtime-sessions-cookies.md)
......@@ -112,7 +112,7 @@ All Rights Reserved.
* [Авторизація](security-authorization.md)
* [Робота з паролями](security-passwords.md)
* **TBD** [Клієнти авторизації](security-auth-clients.md)
* **TBD** [Кращі практики](security-best-practices.md)
* [Кращі практики](security-best-practices.md)
Кешування
......@@ -131,7 +131,7 @@ RESTful веб-сервіси
* [Швидкий старт](rest-quick-start.md)
* [Ресурси](rest-resources.md)
* [Контролери](rest-controllers.md)
* [Роутінг](rest-routing.md)
* [Маршрутизація](rest-routing.md)
* [Форматування відповіді](rest-response-formatting.md)
* [Аутентифікація](rest-authentication.md)
* [Обмеження частоти запитів](rest-rate-limiting.md)
......@@ -193,7 +193,7 @@ RESTful веб-сервіси
* [Огляд](helper-overview.md)
* [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Security](helper-security.md)
Вхідні скрипти
===============
==============
Вхідні скрипти це перша ланка в процесі початкового завантаження додатку. Додаток (веб додаток або консольний додаток)
включає єдиний вхідний скрипт. Кінцеві користувачі роблять запити до вхідного скрипта, який створює об’єкти додатка і перенаправляє запит до них.
має єдиний вхідний скрипт. Кінцеві користувачі роблять запити до вхідного скрипта, який створює об’єкти додатка та
перенаправляє запит до них.
Вхідні скрипти для веб додатків повинні бути збережені в теках доступних з веб, таким чином вони можуть бути доступними кінцевому користувачу. Такі скрипти за звичай називаються `index.php`, але також можут використовуватись і інші імена, які можуть бути розпізнані використовуваними веб-серверами.
Вхідні скрипти для веб додатків повинні бути збережені в директоріях, доступних із веб, таким чином, вони можуть бути
доступними кінцевим користувачам. Зазвичай вони називаються `index.php`, але також можут використовуватись і інші
імена, які можуть бути розпізнані веб-серверами.
Вхідні скрипти для консольних додатків за звичай розміщенні в [кореневій директорії](structure-applications.md) додатку і мають назву
`yii` (з суфіксом `.php`). Вони мають права на виконання, таким чином користувачі зможуть запускати консольні додатки через команду `./yii <маршрут> [аргументи] [опції]`.
Вхідні скрипти для консольних додатків зазвичай розміщенні у [кореневій директорії](structure-applications.md)
додатку і мають назву `yii` (з суфіксом `.php`). Вони повинні мати права на виконання, щоб користувачі мали змогу
запускати консольні додатки через команду `./yii <маршрут> [аргументи] [опції]`.
Вхідні скрипти в основному виконують наступну роботу:
* Оголошують глобальні константи;
* Реєструють завантажувач класів [Composer](http://getcomposer.org/doc/01-basic-usage.md#autoloading);
* Підключають файл класа [[Yii]];
* Реєструють автозавантажувач класів [Composer](http://getcomposer.org/doc/01-basic-usage.md#autoloading);
* Підключають файл класу [[Yii]];
* Завантажують конфігурацію додатка;
* Створюють і конфігурують об’єкт [додатка](structure-applications.md);
* Викликають метод [[yii\base\Application::run()]] додатка для опрацювання вхідного запиту.
* Викликають метод [[yii\base\Application::run()]] додатка для обробки вхідного запиту.
## Веб додатки <a name="web-applications"></a>
......@@ -29,16 +33,16 @@
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// реєстрація завантажувача класів Composer
// реєстрація автозавантажувача класів Composer
require(__DIR__ . '/../vendor/autoload.php');
// підключення файла класа Yii
// підключення файла класу Yii
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// завантаження конфігурації додатка
$config = require(__DIR__ . '/../config/web.php');
// створення і конфігурація додатка, а також виклик метода для опрацювання вхідного запиту
// створення, конфігурація та виконання додатка
(new yii\web\Application($config))->run();
```
......@@ -60,14 +64,14 @@ $config = require(__DIR__ . '/../config/web.php');
defined('YII_DEBUG') or define('YII_DEBUG', true);
// fcgi не має констант STDIN и STDOUT, вони визначаються за замовчуванням
// fcgi не має констант STDIN та STDOUT за замовчуванням
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));
// реєстрація завантажувача класів Composer
// реєстрація автозавантажувача класів Composer
require(__DIR__ . '/vendor/autoload.php');
// підключення файла класа Yii
// підключення файла класу Yii
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
// завантаження конфігурації додатка
......@@ -83,11 +87,15 @@ exit($exitCode);
Вхідні скрипти є найкращим місцем для оголошення глобальних констант. Yii підтримує наступні три константи:
* `YII_DEBUG`: вказує чи працює додаткок у відлагоджувальному режимі. Перебуваючи у відлагоджувальному режимі, додаток буде збирати більше інформації у логи і покаже більш детальний стек викликів, якщо виникне виняток. По цій причині, відлагоджувальний режим повинен бути використаний тільки в процесі розробки. За замовчуванням значення `YII_DEBUG` дорівнює false;
* `YII_ENV`: вказує в якому середовищі працює додаток. Дана тема детально розглянута в розділі [Конфігурації](concept-configurations.md#environment-constants).
За замовчуванням значення `YII_ENV` дорівнює `'prod'`, що значить, що додаток працює у виробничому режимі;
* `YII_ENABLE_ERROR_HANDLER`: вказує чи потрібно включати наявний у Yii обробник помилок. За замовчуванням значення даної константи
дорівнює true.
* `YII_DEBUG`: вказує чи працює додаткок у режимі відлагодження ("debug mode"), перебуваючи у якому,
додаток буде збирати більше інформації у логи та покаже більш детальний стек викликів при отриманні виключення.
З цієї причини, режим відлагодження повинен бути використаний тільки в процесі розробки.
За замовчуванням значення `YII_DEBUG` дорівнює `false`.
* `YII_ENV`: вказує в якому середовищі працює додаток. Дана тема детально розглянута у розділі
[Конфігурації](concept-configurations.md#environment-constants). За замовчуванням значення `YII_ENV` дорівнює
`'prod'`, яке означає, що додаток працює у робочому ("production") режимі.
* `YII_ENABLE_ERROR_HANDLER`: вказує чи потрібно увімкнути наявний у Yii обробник помилок.
За замовчуванням значення даної константи дорівнює `true`.
При визначенні константи, ми зазвичай використовуєм наступний код:
......@@ -105,4 +113,5 @@ if (!defined('YII_DEBUG')) {
Перший варіант є більш коротким і зрозумілим.
Константи мають бути визначені якомога раніше, в самому початку вхідного скрипта, таким чином вони зможуть вплинути на решту PHP файлів які будуть підключатись.
Константи мають бути визначені якомога раніше, на самому початку вхідного скрипта, щоб вони могли вплинути на решту
PHP файлів, які будуть підключатись.
Огляд
=====
Yii додаток організований згідно шаблону проектування [модель-представлення-подія (MVC)](http://ru.wikipedia.org/wiki/Model-View-Controller).
[Моделі](structure-models.md) являють собою дані, бізнес логіку і бізнес правила; [представлення](structure-views.md)
відповідають за відображення інформації, в тому числі і на основі даних, отриманих з моделей; [контролери](structure-controllers.md)
приймають вхідні дані від користувача і перетворюють їх в зрозумілий для [моделей](structure-models.md) формат і команди, а також відповідають за відображення потрібного представлення.
Додатки Yii організовані згідно шаблону проектування
[модель-представлення-подія (MVC)](http://uk.wikipedia.org/wiki/Модель-вид-контролер).
[Моделі](structure-models.md) являють собою дані, бізнес логіку та бізнес правила;
[представлення](structure-views.md) відповідають за відображення даних моделей;
[контролери](structure-controllers.md) приймають вхідні дані від користувача і перетворюють їх у команди для
[моделей](structure-models.md) та [представлень](structure-views.md).
Окрім MVC, Yii додаток також має наступні сутності:
* [вхідні скрипти](structure-entry-scripts.md): це PHP скрипти, які доступні напряму кінцевому користувачу додатка.
Вони відповідають за запуск та опрацювання вхідного запиту;
Вони відповідають за запуск циклу обробки запиту.
* [додатки](structure-applications.md): це глобально доступні об’єкти, які відповідають за коректну роботу різних
компонентів додатка і їх координацію для обробки запиту;
компонентів додатка і їх координацію для обробки запиту.
* [компоненти додатку](structure-application-components.md): це об’єкти, зареєстровані в додатку і які надають
різноманітні можливості для обробки поточного запиту;
різноманітні можливості для обробки запитів.
* [модулі](structure-modules.md): це самодостатні пакети, що включають в себе повністю всі ресурси для MVC.
Додаток може бути організовано з допомогою декількох модулів;
* [фільтри](structure-filters.md): це код, який повинен бути виконаний до і після оброки запиту контролерами;
* [віджети](structure-widgets.md): це об’єкти, які можуть включати в себе [представлення](structure-views.md).
Вони можуть містити різноманітну логіку і використовуватись в різноманітних представленнях.
Додаток може бути організовано за допомогою декількох модулів.
* [фільтри](structure-filters.md): це код, який повинен бути виконаний до і після обробки запиту контролерами.
* [віджети](structure-widgets.md): це об’єкти, які можуть бути вбудованими у [представлення](structure-views.md).
Вони можуть містити різноманітну логіку і можуть бути повто використаними у різних представленнях.
Нижче на діаграмі наведена структурна схема додатку:
На наступній діаграмі наведена структурна схема додатку:
![Стандартна структура додатку](../guide/images/application-structure.png)
\ No newline at end of file
![Статична структура додатку](images/application-structure.png)
......@@ -112,7 +112,7 @@ Security
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* **TBD** [Auth Clients](security-auth-clients.md)
* **TBD** [Best Practices](security-best-practices.md)
* [Best Practices](security-best-practices.md)
Caching
......
......@@ -9,7 +9,7 @@ an Active Record instance corresponds to a row of that table, and an attribute o
instance represents the value of a column in that row. Instead of writing raw SQL statements,
you can work with Active Record in an object-oriented fashion to manipulate the data in database tables.
For example, assume `Customer` is an Active Record class is associated with the `customer` table
For example, assume `Customer` is an Active Record class which is associated with the `customer` table
and `name` is a column of the `customer` table. You can write the following code to insert a new
row into the `customer` table:
......@@ -33,7 +33,7 @@ Below is the list of databases that are currently supported by Yii Active Record
* MySQL 4.1 or later: via [[yii\db\ActiveRecord]]
* PostgreSQL 7.3 or later: via [[yii\db\ActiveRecord]]
* SQLite 2 and 3: via [[yii\db\ActiveRecord]]
* Microsoft SQL Server 2010 or later: via [[yii\db\ActiveRecord]]
* Microsoft SQL Server 2008 or later: via [[yii\db\ActiveRecord]]
* Oracle: via [[yii\db\ActiveRecord]]
* CUBRID 9.3 or later: via [[yii\db\ActiveRecord]] (Note that due to a [bug](http://jira.cubrid.org/browse/APIS-658) in
the cubrid PDO extension, quoting of values will not work, so you need CUBRID 9.3 as the client as well as the server)
......@@ -346,7 +346,7 @@ of the active record class and set the values there. For example to set the defa
public function init()
{
parent::init();
$this->status = 'active';
$this->status = self::STATUS_ACTIVE;
}
```
......@@ -700,7 +700,7 @@ if ($customers[0]->orders[0]->customer === $customers[0]) {
> you cannot call [[yii\db\ActiveQuery::inverseOf()]] further.
Joining with Relations
Joining with Relations <a name="joining-with-relations"></a>
----------------------
When working with relational databases, a common task is to join multiple tables and apply various
......@@ -1020,9 +1020,9 @@ To use Optimistic locking:
1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`.
Override the `optimisticLock()` method to return the name of this column.
2. In the Web form that collects the user input, add a hidden field that stores
the lock version of the recording being updated.
the lock version of the record being updated.
3. In the controller action that does the data updating, try to catch the [[\yii\db\StaleObjectException]]
and implement necessary business logic (e.g. merging the changes, prompting stated data)
and implement necessary business logic (e.g. merging the changes, prompting staled data)
to resolve the conflict.
Dirty Attributes
......
......@@ -15,7 +15,7 @@ By default, Yii supports the following DBMS:
- [CUBRID](http://www.cubrid.org/): version 9.3 or higher. (Note that due to a [bug](http://jira.cubrid.org/browse/APIS-658) in
the cubrid PDO extension, quoting of values will not work, so you need CUBRID 9.3 as the client as well as the server)
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): version 2005 or higher.
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): version 2008 or higher.
Configuration
......@@ -194,7 +194,7 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
Quoting Table and Column Names
Quoting Table and Column Names <a name="quoting-table-and-column-names"></a>
------------------------------
To make column and table names safe to use in queries, you can have Yii properly quote them for you:
......
......@@ -9,6 +9,7 @@ of Html helper which provides a set of static methods for handling commonly used
> Note: If your markup is nearly static it's better to use HTML directly. There's no need to wrap absolutely everything
with Html helper calls.
Basics <a name="basics"></a>
----------------------------
......@@ -39,7 +40,7 @@ In case you need just start tag or just closing tag you can use `Html::beginTag(
Options are used in many methods of Html helper and various widgets. In all these cases there is some extra handling to
know about:
- If a value is null, the corresponding attribute will not be rendered.
- Attributes whose values are of boolean type will be treated as
[boolean attributes](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
......@@ -49,13 +50,12 @@ know about:
- The "data" attribute could receive JSON. It is handled the same way as array i.e.
`'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` becomes
`data-params='{"id":1,"name":"yii"}' data-status="ok"`.
### Forming class and style dynamically
When building options for HTML tag we're often starting with defaults which we need to modify. In order to add or
remove CSS class you can use the following:
```php
$options = ['class' => 'btn btn-default'];
......@@ -88,7 +88,7 @@ could be converted there and forth by using [[yii\helpers\Html::cssStyleFromArra
[[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. The [[yii\helpers\Html::removeCssStyle()|removeCssStyle()]]
method accepts an array of properties to remove. If it's going to be a single property it could be specified as string.
Encoding and decoding content <a name="encoding-and-decoding-content"></a>
--------------------------------------------------------------------------
......@@ -104,7 +104,7 @@ $userName = Html::encode($user->name);
echo $userName;
$decodedUserName = Html::decode($userName);
```
```
Forms
......@@ -115,6 +115,7 @@ dealing with them.
> Note: consider using [[yii\widgets\ActiveForm|ActiveForm]] in case you deal with models and need validation.
### Open and close a form
Form could be opened with [[yii\helpers\Html::beginForm()|beginForm()]] method like the following:
......@@ -134,6 +135,7 @@ Closing form tag is simple:
<?= Html::endForm() ?>
```
### Buttons
In order to generate buttons you can use the following code:
......@@ -154,7 +156,6 @@ There are two groups on input methods. The ones starting with `active` and calle
with it. Active inputs are taking data from model and attribute specified while in case of regular input data is specified
directly.
The most generic methods are:
```php
......@@ -198,7 +199,7 @@ Dropdown list and list box could be rendered like the following:
First argument is the name of the input, second is the value that's currently selected and third is key-value pairs where
array key is list value and array value is list label.
If you want multiple choices to be selectable, checkbox list is a good match:
```php
......@@ -213,9 +214,8 @@ If not, use radio list:
<?= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
### Labels and errors
### Labels and errors
Same as inputs there are two methods for generating form labels. Active that's taking data from the model and non-active
that accepts data directly:
......@@ -224,8 +224,8 @@ that accepts data directly:
<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
<?= Html::activeLabel($user, 'username', ['class' => 'label username'])
```
In order to display form errors from a model or models as a summart you could use:
In order to display form errors from a model or models as a summary you could use:
```php
<?= Html::errorSummary($posts, ['class' => 'errors']) ?>
......@@ -236,11 +236,11 @@ To display individual error:
```php
<?= Html::error($post, 'title', ['class' => 'error']) ?>
```
### Names and values
There are methods to get names, ids and values for input fields based on the model. These are mailly used internally
There are methods to get names, ids and values for input fields based on the model. These are mainly used internally
but could be handy sometimes:
```php
......@@ -257,7 +257,7 @@ echo Html::getAttributeValue($post, 'title');
echo Html::getAttributeValue($post, '[0]authors[0]');
```
In the above first argument is the model while the second one is attribute expression. In its simplest for it's
In the above first argument is the model while the second one is attribute expression. In its simplest form it's
attribute name but it could be an attribute name prefixed and/or suffixed with array indexes which are mainly used
for tabular input:
......@@ -271,14 +271,13 @@ In order to get attribute name without suffixes or prefixes one can use the foll
// dates
echo Html::getAttributeName('dates[0]');
```
Styles and scripts
------------------
There two methods to generate tags wrapping embedded styles and scripts:
```php
<?= Html::style('.danger { color: #f00; }') ?>
......@@ -321,12 +320,13 @@ To link JavaScript file:
Same as with CSS first argument specifies link to the file to be included. Options could be passed as the second argument.
In options you can specify `condition` in the same way as in options for `cssFile`.
Links
-----
There's a method to generate hyperlink conveniently:
```php
<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
```
......@@ -336,17 +336,17 @@ The first argument is the title. It's not encoded so if you're using data got fr
what values it accepts. Third argument is array of tag properties.
In you need to generate `mailto` link you can use the following code:
```php
<?= Html::mailto('Contact us', 'admin@example.com') ?>
```
Images
------
In order to generate image tag use the following:
```php
<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
......@@ -357,10 +357,11 @@ generates
Aside [aliases](concept-aliases.md) the first argument can accept routes, parameters and URLs. Same way as
[Url::to()](helper-url.md) does.
Lists
-----
Unordered list could be generated like the following:
```php
......
Uploading Files
===============
> Note: This section is under development.
Uploading files in Yii is done via a form model, its validation rules and some controller code. Let's review what's
required to handle uploads properly.
Uploading files in Yii is done via the a form model, its validation rules and some controller code. Let's review what's needed
to handle uploads properly.
Form model
----------
Uploading single file
---------------------
First of all, you need to create a model that will handle file uploads. Create `models/UploadForm.php` with the following
content:
......@@ -24,7 +23,7 @@ use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* @var UploadedFile|Null file attribute
* @var UploadedFile file attribute
*/
public $file;
......@@ -40,11 +39,10 @@ class UploadForm extends Model
}
```
In the code above, we created a model `UploadForm` with an attribute `$file` that will become `<input type="file">` in
In the code above, we've created a model `UploadForm` with an attribute `file` that will become `<input type="file">` in
the HTML form. The attribute has the validation rule named `file` that uses [[yii\validators\FileValidator|FileValidator]].
Form view
---------
### Form view
Next, create a view that will render the form:
......@@ -65,10 +63,9 @@ use yii\widgets\ActiveForm;
The `'enctype' => 'multipart/form-data'` is necessary because it allows file uploads. `fileInput()` represents a form
input field.
Controller
----------
### Controller
Now create the controller that connects the form and model together:
Now create the controller that connects the form and the model together:
```php
namespace app\controllers;
......@@ -98,13 +95,16 @@ class SiteController extends Controller
```
Instead of `model->load(...)`, we are using `UploadedFile::getInstance(...)`. [[\yii\web\UploadedFile|UploadedFile]]
does not run the model validation, rather it only provides information about the uploaded file. Therefore, you need to run the validation manually via `$model->validate()` to trigger the [[yii\validators\FileValidator|FileValidator]] that expects a file:
does not run the model validation, rather it only provides information about the uploaded file. Therefore, you need to run the validation manually via `$model->validate()` to trigger the [[yii\validators\FileValidator|FileValidator]]. The validator expects that
the attribute is an uploaded file, as you see in the core framework code:
```php
$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in the code framework
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []];
}
```
If validation is successful, then we're saving the file:
If the validation is successful, then we're saving the file:
```php
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
......@@ -114,10 +114,13 @@ If you're using the "basic" application template, then folder `uploads` should b
That's it. Load the page and try uploading. Uploads should end up in `basic/web/uploads`.
Additional information
----------------------
Validation
----------
It's often required to adjust validation rules to accept certain files only or require uploading. Below we'll review
some common rule configurations.
### Required rule
### Required
If you need to make the file upload mandatory, use `skipOnEmpty` like the following:
......@@ -156,14 +159,15 @@ public function rules()
[List of common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### Validating uploaded image
### Image properties
If you upload an image, [[yii\validators\ImageValidator|ImageValidator]] may come in handy. It verifies if an attribute
received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2/tree/master/extensions/imagine).
### Uploading multiple files
Uploading multiple files
------------------------
If you need to download multiple files at once, some adjustments are required.
If you need to upload multiple files at once, some adjustments are required.
Model:
......@@ -194,15 +198,9 @@ View:
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
if ($model->hasErrors()) { //it is necessary to see all the errors for all the files.
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
}
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>Submit</button>
......@@ -212,7 +210,7 @@ if ($model->hasErrors()) { //it is necessary to see all the errors for all the f
The difference is the following line:
```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
```
Controller:
......@@ -232,31 +230,13 @@ class SiteController extends Controller
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$files = UploadedFile::getInstances($model, 'file');
foreach ($files as $file) {
$_model = new UploadForm();
$_model->file = $file;
if ($_model->validate()) {
$_model->file->saveAs('uploads/' . $_model->file->baseName . '.' . $_model->file->extension);
} else {
foreach ($_model->getErrors('file') as $error) {
$model->addError('file', $error);
}
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
if ($model->hasErrors('file')){
$model->addError(
'file',
count($model->getErrors('file')) . ' of ' . count($files) . ' files not uploaded'
);
}
}
return $this->render('upload', ['model' => $model]);
......@@ -264,5 +244,6 @@ class SiteController extends Controller
}
```
The difference is using `UploadedFile::getInstances($model, 'file');` instead of `UploadedFile::getInstance($model, 'file');`.
The former returns instances for **all** uploaded files while the latter gives you only a single instance.
There are two differences from single file upload. First is that `UploadedFile::getInstances($model, 'file');` is used
instead of `UploadedFile::getInstance($model, 'file');`. The former returns instances for **all** uploaded files while
the latter gives you only a single instance. The second difference is that we're doing `foreach` and saving each file.
......@@ -86,7 +86,7 @@ All of the content placed between [[yii\widgets\ActiveForm::begin()|ActiveForm::
As with any widget, you can specify some options as to how the widget should be configured by passing an array to
the `begin` method. In this case, an extra CSS class and identifying ID are passed to be used in the opening `<form>` tag.
In order to create a form element in the form, along with the element's label, and any application JavaScript validation,
In order to create a form element in the form, along with the element's label, and any applicable JavaScript validation,
the [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] method of the Active Form widget is called.
When the invocation of this method is echoed directly, the result is a regular (text) input.
To customize the output, you can chain additional methods to this call:
......
......@@ -22,15 +22,6 @@ if ($model->validate()) {
}
```
Behind the scenes, the `validate()` method does the following steps to perform validation:
1. Determine which attributes should be validated by getting the attribute list from [[yii\base\Model::scenarios()]]
using the current [[yii\base\Model::scenario|scenario]]. These attributes are called *active attributes*.
2. Determine which validation rules should be used by getting the rule list from [[yii\base\Model::rules()]]
using the current [[yii\base\Model::scenario|scenario]]. These rules are called *active rules*.
3. Use each active rule to validate each active attribute associated with that rule. If the rule fails,
keep an error message for the attribute in the model.
## Declaring Rules <a name="declaring-rules"></a>
......@@ -58,7 +49,7 @@ of the following format:
[
// required, specifies which attributes should be validated by this rule.
// For a single attribute, you can use the attribute name directly
// without having it in an array instead of an array
// without having it in an array
['attribute1', 'attribute2', ...],
// required, specifies the type of this rule.
......@@ -92,13 +83,13 @@ If you do not specify an `on` option, it means the rule will be applied to all s
When the `validate()` method is called, it does the following steps to perform validation:
1. Determine which attributes should be validated by checking the current [[yii\base\Model::scenario|scenario]]
against the scenarios declared in [[yii\base\Model::scenarios()]]. These attributes are the active attributes.
2. Determine which rules should be applied by checking the current [[yii\base\Model::scenario|scenario]]
against the rules declared in [[yii\base\Model::rules()]]. These rules are the active rules.
1. Determine which attributes should be validated by getting the attribute list from [[yii\base\Model::scenarios()]]
using the current [[yii\base\Model::scenario|scenario]]. These attributes are called *active attributes*.
2. Determine which validation rules should be used by getting the rule list from [[yii\base\Model::rules()]]
using the current [[yii\base\Model::scenario|scenario]]. These rules are called *active rules*.
3. Use each active rule to validate each active attribute which is associated with the rule.
The validation rules are evaluated in the order they are listed.
According to the above validation steps, an attribute will be validated if and only if it is
an active attribute declared in `scenarios()` and is associated with one or multiple active rules
declared in `rules()`.
......
......@@ -73,29 +73,29 @@ the data provider. The displayed table is equipped with sorting and pagination f
Yii grid consists of a number of columns. Depending on column type and settings these are able to present data differently.
These are defined in the columns part of GridView configuration like the following:
These are defined in the `columns` part of GridView configuration like the following:
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// A simple column defined by the data contained in $dataProvider.
// Data from the model's column1 will be used.
// Simple columns defined by the data contained in $dataProvider.
// Data from the model's column will be used.
'id',
'username',
// More complex one.
[
'class' => 'yii\grid\DataColumn', // can be omitted, default
'class' => 'yii\grid\DataColumn', // can be omitted, as it is the default
'value' => function ($data) {
return $data->name; //$data['name'] for array data, e.g. using SqlDataProvider.
return $data->name; // $data['name'] for array data, e.g. using SqlDataProvider.
},
],
],
]);
```
Note that if the columns part of the configuration isn't specified, Yii tries to show all possible data provider model columns.
Note that if the `columns` part of the configuration isn't specified, Yii tries to show all possible columns of the data provider's model.
### Column classes
......@@ -111,9 +111,9 @@ echo GridView::widget([
],
```
In addition to column classes provided by Yii that we'll review below you can create your own column classes.
In addition to column classes provided by Yii that we'll review below, you can create your own column classes.
Each column class extends from [[\yii\grid\Column]] so there are some common options you can set while configuring
Each column class extends from [[\yii\grid\Column]] so that there are some common options you can set while configuring
grid columns.
- `header` allows to set content for header row.
......@@ -151,7 +151,7 @@ echo GridView::widget([
],
[
'attribute' => 'birthday',
'format' => ['date', 'Y-m-d']
'format' => ['date', 'php:Y-m-d']
],
],
]);
......@@ -159,7 +159,7 @@ echo GridView::widget([
In the above, `text` corresponds to [[\yii\i18n\Formatter::asText()]]. The value of the column is passed as the first
argument. In the second column definition, `date` corresponds to [[\yii\i18n\Formatter::asDate()]]. The value of the
column is, again, passed as the first argument while 'Y-m-d' is used as the second argument value.
column is, again, passed as the first argument while 'php:Y-m-d' is used as the second argument value.
For a list of available formatters see the [section about Data Formatting](output-formatter.md).
......@@ -256,7 +256,7 @@ A common practice when using [active records](db-active-record.md) is to create
that provides needed functionality (it can be generated for you by Gii). This class defines the validation
rules for the search and provides a `search()` method that will return the data provider.
To add the search capability for the `Post` model, we can create `PostSearch` like in the following example:
To add the search capability for the `Post` model, we can create `PostSearch` like the following example:
```php
<?php
......@@ -419,14 +419,14 @@ $query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name'
> ```
> Info: For more information on `joinWith` and the queries performed in the background, check the
> [active record docs on eager and lazy loading](db-active-record.md#lazy-and-eager-loading).
> [active record docs on joining with relations](db-active-record.md#joining-with-relations).
#### Using sql views for filtering, sorting and displaying data
There is also another approach that can be faster and more useful - sql views. For example, if we need to show the gridview
with users and their profiles, we can do so in this way:
```php
```sql
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
......@@ -485,7 +485,7 @@ After that you can use this UserView active record with search models, without a
All attributes will be working out of the box. Note that this approach has several pros and cons:
- you don't need to specify different sorting and filtering conditions. Everything works out of the box;
- it can be much faster because of the data size, count of sql queries performed (for each relation you will need an additional query);
- it can be much faster because of the data size, count of sql queries performed (for each relation you will not need any additional query);
- since this is just a simple mapping UI on the sql view it lacks some domain logic that is in your entities, so if you have some methods like `isActive`,
`isDeleted` or others that will influence the UI, you will need to duplicate them in this class too.
......
......@@ -154,10 +154,10 @@ The format for number formatting can be adjusted using the [[yii\i18n\Formatter:
For more advanced configuration, [[yii\i18n\Formatter::numberFormatterOptions]] and [[yii\i18n\Formatter::numberFormatterTextOptions]]
can be used to configure the internally used [NumberFormatter class](http://php.net/manual/en/class.numberformatter.php)
For example to adjust the maximum and minimum value of fraction digits you can configure this property like the following:
For example, to adjust the maximum and minimum value of fraction digits, you can configure [[yii\i18n\Formatter::numberFormatterOptions]] property like the following:
```php
[
'numberFormatterOptions' => [
NumberFormatter::MIN_FRACTION_DIGITS => 0,
NumberFormatter::MAX_FRACTION_DIGITS => 2,
]
......@@ -191,4 +191,4 @@ In addition to date, time and number formatting, Yii provides a set of other use
For values that are `null` in PHP, the formatter class will print a placeholder instead of an empty string which
defaults to `(not set)` translated to the current application language. You can configure the
[[yii\i18n\Formatter::nullDisplay|nullDisplay]] property to set a custom placeholder.
If you do not you want special handling for `null` values, you can set [[yii\i18n\Formatter::nullDisplay|nullDisplay]] to `null`.
If you do not want special handling for `null` values, you can set [[yii\i18n\Formatter::nullDisplay|nullDisplay]] to `null`.
......@@ -38,6 +38,17 @@ For example, with a configuration above a themed version of a view file `@app/vi
`@app/themes/basic/site/index.php`. It basically replaces `@app/views` in `@app/views/site/index.php` with
`@app/themes/basic`.
In order to configure theme runtime you can use the following code before rendering a view. Typically it will be
placed in controller:
```php
$this->getView()->theme = Yii::createObject([
'class' => '\yii\base\Theme',
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
]);
```
### Theming modules
In order to theme modules, `pathMap` may look like the following:
......
......@@ -90,11 +90,13 @@ matches. This should be an array of controller IDs. The comparison is case-sensi
empty or not set, it means the rule applies to all controllers.
* [[yii\filters\AccessRule::roles|roles]]: specifies which user roles that this rule matches.
Two special roles are recognized, and they are checked via [[yii\web\User::isGuest]]:
Two special roles are recognized, and they are checked via [[yii\web\User::isGuest]]:
- `?`: matches a guest user (not authenticated yet)
- `@`: matches an authenticated user
Using other role names requires RBAC (to be described in the next section), and [[yii\web\User::can()]] will be called.
If this option is empty or not set, it means this rule applies to all roles.
Using other role names requires RBAC (to be described in the next section), and [[yii\web\User::can()]] will be called.
If this option is empty or not set, it means this rule applies to all roles.
* [[yii\filters\AccessRule::ips|ips]]: specifies which [[yii\web\Request::userIP|client IP addresses]] this rule matches.
An IP address can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
......@@ -202,9 +204,8 @@ return [
The `authManager` can now be accessed via `\Yii::$app->authManager`.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in three files: `@app/rbac/items.php`, `@app/rbac/assignments.php` and `@app/rbac/rules.php`.
Make sure these files are writable by the Web server process if the authorization needs to be changed online.
Sometimes you will need to create these files manually.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in files under `@app/rbac/` directory. Make sure the directory
and all the files in it are writable by the Web server process if permissions hierarchy needs to be changed online.
### Building Authorization Data
......@@ -220,7 +221,7 @@ Building authorization data is all about the following tasks:
Depending on authorization flexibility requirements the tasks above could be done in different ways.
If your permissions hierarchy doesn't change at all and you have a fixed number of users you can create a
[console command](tutorial-console.md#create-command) command that will initialize authorization data once via APIs offered by `authManager`:
[console command](tutorial-console.md#create-command) that will initialize authorization data once via APIs offered by `authManager`:
```php
<?php
......@@ -272,7 +273,7 @@ After executing the command with `yii rbac/init` we'll get the following hierarc
Author can create post, admin can update post and do everything author can.
If your application allows user signup you need to assign roles to these new users once. For example, in order for all
signed up users to become authors you in advanced application template you need to modify `frontend\models\SignupForm::signup()`
signed up users to become authors in your advanced application template you need to modify `frontend\models\SignupForm::signup()`
as follows:
```php
......@@ -302,11 +303,6 @@ For applications that require complex access control with dynamically updated au
(i.e. admin panel) may need to be developed using APIs offered by `authManager`.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in three files: `@app/rbac/items.php`, `@app/rbac/assignments.php` and `@app/rbac/rules.php`.
Make sure these files are writable by the Web server process if the authorization needs to be changed online.
Sometimes you will need to create these files manually.
### Using Rules
As aforementioned, rules add additional constraint to roles and permissions. A rule is a class extending
......@@ -416,7 +412,7 @@ assign each user to a RBAC role. Let's use an example to show how this can be do
Assume in the user table, you have a `group` column which uses 1 to represent the administrator group and 2 the author group.
You plan to have two RBAC roles `admin` and `author` to represent the permissions for these two groups, respectively.
You can create set up the RBAC data as follows,
You can set up the RBAC data as follows,
```php
......
Security best practice
======================
Security best practices
=======================
> Note: This section is under development.
>
> It has no content yet.
Below we'll review common security principles and describe how to avoid threats when developing applications using Yii.
Basic principles
----------------
There are two main principles when it comes to security no matter which application is being developed:
1. Filter input.
2. Escape output.
### Filter input
Filter input means that input should never be considered safe and you should always check if the value you've got is
actually among allowed ones i.e. if we know that sorting could be done by three fields `title`, `created_at` and `status`
and the field could be supplied via used input it's better to check the value we've got right where we're receiving it.
In terms of basic PHP that would look like the following:
```php
$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
throw new Exception('Invalid sort value.');
}
```
In Yii, most probably you'll use [form validation](input-validation.md) to do alike checks.
### Escape output
Escape output means that depending on context where we're using data it should be escaped i.e. in context of HTML you
should escape `<`, `>` and alike special characters. In context of JavaScript or SQL it will be different set of characters.
Since it's error-prone to escape everything manually Yii provides various tools to perform escaping for different
contexts.
Avoiding SQL injections
-----------------------
SQL injection happens when query text is formed by concatenating unescaped strings such as the following:
```php
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
```
Instead of supplying correct username attacker could give your applications something like `'; DROP TABLE user; --`.
Resulting SQL will be the following:
```sql
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
```
This is valid query that will search for users with empty username and then will drop `user` table most probably
resulting in broken website and data loss (you've set up regular backups, right?).
In Yii most of database querying happens via [Active Record](db-active-record.md) which properly uses PDO prepared
statements internally. In case of prepared statements it's not possible to manipulate query as was demonstrated above.
Still, sometimes you need [raw queries](db-dao.md) or [query builder](db-query-builder.md). In this case you should use
safe ways of passing data. If data is used for column values it's preferred to use prepared statements:
```php
// query builder
$userIDs = (new Query())
->select('id')
->from('user')
->where('status=:status', [':status' => $status])
->all();
// DAO
$userIDs = $connection
->createCommand('SELECT id FROM user where status=:status')
->bindValues([':status' => $status])
->queryColumn();
```
If data is used to specify column names or table names the best thing to do is to allow only predefined set of values:
```php
function actionList($orderBy = null)
{
if (!in_array($orderBy, ['name', 'status'])) {
throw new BadRequestHttpException('Only name and status are allowed to order by.')
}
// ...
}
```
In case it's not possible, table and column names should be escaped. Yii has special syntax for such escaping
which allows doing it the same way for all databases it supports:
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
You can get details about the syntax in [Quoting Table and Column Names](db-dao.md#quoting-table-and-column-names).
Avoiding XSS
------------
XSS or cross-site scripting happens when output isn't escaped properly when outputting HTML to the browser. For example,
if user can enter his name and instead of `Alexander` he enters `<script>alert('Hello!');</script>`, every page that
outputs user name without escaping it will execute JavaScript `alert('Hello!');` resulting in alert box popping up
in a browser. Depending on website instead of innocent alert such script could send messages using your name or even
perform bank transactions.
Avoiding XSS is quite easy in Yii. There are generally two cases:
1. You want data to be outputted as plain text.
2. You want data to be outputted as HTML.
If all you need is plain text then escaping is as easy as the following:
```php
<?= \yii\helpers\Html::encode($username) ?>
```
If it should be HTML we could get some help from HtmlPurifier:
```php
<?= \yii\helpers\HtmlPurifier::process($description) ?>
```
Note that HtmlPurifier processing is quite heavy so consider adding caching.
Avoiding CSRF
-------------
TBD: what's CSRF, how it works, intro
1. Follow HTTP specification i.e. GET should not change application state.
2. Keep Yii CSRF protection enabled.
TBD: how CSRF protection works
Avoiding file exposure
----------------------
By default server webroot is meant to be pointed to `web` directory where `index.php` is. In case of shared hosting
environments it could be impossible to achieve so we'll end up with all the code, configs and logs in server webroot.
If it's the case don't forget to deny access to everything except `web`. If it can't be done consider hosting your
application elsewhere.
Avoiding debug info and tools at production
-------------------------------------------
In debug mode Yii shows quite verbose errors which are certainly helpful for development. The thing is that these
verbose errors are handy for attacker as well since these could reveal database structure, configuration values and
parts of your code. Never run production applications with `YII_DEBUG` set to `true` in your `index.php`.
You should never enalble Gii at production. It could be used to get information about database structure, code and to
simply rewrite code with what's generated by Gii.
Debug toolbar should be avoided at production unless really necessary. It exposes all the application and config
details possible. If you absolutely need it check twice that access is proerly restricted to your IP only.
\ No newline at end of file
......@@ -31,3 +31,4 @@ This section will summarize the Yii resources available to help you be more prod
- Facebook: <https://www.facebook.com/groups/yiitalk/>
- Twitter: <https://twitter.com/yiiframework>
- LinkedIn: <https://www.linkedin.com/groups/yii-framework-1483367>
- Stackoverflow: <http://stackoverflow.com/questions/tagged/yii2>
......@@ -290,7 +290,17 @@ back to the attribute being validated.
Note that if the filter cannot handle array input, you should set this property to be true. Otherwise some
PHP error might occur.
> Tip: If you want to trim input values, you may directly use [trim](#trim) validator.
> Tip: If you want to trim input values, you may directly use the [trim](#trim) validator.
> Tip: There are many PHP functions that have the signature expected for the `filter` callback.
> For example to apply type casting (using e.g. [intval](http://php.net/manual/en/function.intval.php),
> [boolval](http://php.net/manual/en/function.boolval.php), ...) to ensure a specific type for an attribute,
> you can simply specify the function names of the filter without the need to wrap them in a closure:
>
> ```php
> ['property', 'filter', 'filter' => 'boolval'],
> ['property', 'filter', 'filter' => 'intval'],
> ```
## [[yii\validators\ImageValidator|image]] <a name="image"></a>
......
......@@ -3,7 +3,7 @@ Jquery UI Widgets
> Note: This section is under development.
Yii includes support for the [jQuery UI](http://api.jqueryui.com/) library in an officail extension. jQuery UI is
Yii includes support for the [jQuery UI](http://api.jqueryui.com/) library in an official extension. jQuery UI is
a curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.
Installation
......@@ -45,4 +45,4 @@ framework features. All widgets belong to `\yii\jui` namespace:
- [[yii\jui\SliderInput|SliderInput]]
- [[yii\jui\Sortable|Sortable]]
- [[yii\jui\Spinner|Spinner]]
- [[yii\jui\Tabs|Tabs]]
\ No newline at end of file
- [[yii\jui\Tabs|Tabs]]
......@@ -54,7 +54,7 @@ build translation "../docs/guide" "../docs/guide-pt-BR" > report-guide-pt-BR.htm
Antes de iniciar seus trabalhos de tradução certifique-se que o arquivo em qual
irá trabalhar esteja disponível para ser traduzido. Para isso, acesse a
[planilha no Google Docs](https://docs.google.com/spreadsheets/d/17JOpAjkJz2YZCjD6gWaUx32wskGRB-2CdFbed111iys/edit?usp=sharing).
[planilha no Google Docs](https://docs.google.com/spreadsheets/d/1pAMe-qsKK0poEsQwGI2HLFmj4afKSkEUd_1qegU5YqQ).
Regras e Observações
......@@ -74,19 +74,27 @@ Regras e Observações
- action — ação
- application system - sistema
- application template — template de aplicação
- controller — controller (controlador)
- eager loading — eager loading (carregamento na inicialização)
- lazy loading — lazy loading (carregamento retardado)
- model — model (modelo)
- query builder — query builder (construtor de consulta)
- view — view (visão)
- note — observação
- info — informação
- tip — dica
- warning - atenção
- attribute label - label do atributo
- inline action — ação inline
- standalone action — ação standalone
### Termos Sem Tradução
- active record
- alias
- cache
- CamelCase
- CamelCase, camel-case
- core
- framework
- hash
......@@ -94,4 +102,6 @@ Regras e Observações
- id
- runtime
- widget
- backend
- frontend
- web service
\ No newline at end of file
......@@ -39,6 +39,7 @@ Japanese
- Nobuo Kihara 木原伸夫, [@softark](https://github.com/softark), softark@gmail.com
- Tomoki Morita, [@jamband](https://github.com/jamband), tmsongbooks215@gmail.com
- Hisateru Tanaka, [@tanakahisateru](https://github.com/tanakahisateru), tanakahisateru@gmail.com
Russian
-------
......
Yii Framework 2 apidoc extension Change Log
===========================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #5623: Fixed crash when a class contains a setter that has no arguments e.g. `setXyz()` (cebe)
......
......@@ -13,6 +13,9 @@ use yii\apidoc\helpers\PrettyPrinter;
/**
* Represents API documentation information for a `property`.
*
* @property bool $isReadOnly If property is read only. This property is read-only.
* @property bool $isWriteOnly If property is write only. This property is read-only.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
......
......@@ -7,7 +7,6 @@
namespace yii\apidoc\templates\bootstrap\assets;
use yii\web\AssetBundle;
use yii\web\View;
/**
......@@ -16,7 +15,7 @@ use yii\web\View;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class JsSearchAsset extends AssetBundle
class JsSearchAsset extends \yii\web\AssetBundle
{
public $sourcePath = '@vendor/cebe/js-search';
public $js = [
......
Yii Framework 2 authclient extension Change Log
===============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #6000: Fixed CCS for `yii\authclient\widgets\AuthChoice` does not loaded if `popupMode` disabled (klimov-paul)
......
Yii Framework 2 bootstrap extension Change Log
==============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #5570: `yii\bootstrap\Tabs` would throw an exception if `content` is not set for one of its `items` (RomeroMsk)
......@@ -9,6 +15,7 @@ Yii Framework 2 bootstrap extension Change Log
- Enh #4146: Added `yii\bootstrap\ButtonDropdown::$containerOptions` (samdark)
- Enh #4181: Added `yii\bootstrap\Modal::$headerOptions` and `yii\bootstrap\Modal::$footerOptions` (tuxoff, samdark)
- Enh #4450: Added `yii\bootstrap\Nav::renderDropdown()` (qiangxue)
- Enh #5494: Added support for specifying a menu header as a configuration array in `yii\bootstrap\Dropdown` (hiltonjanfield, qiangxue)
- Enh #5735: Added `yii\bootstrap\Tabs::renderTabContent` to support manually rendering tab contents (RomeroMsk)
- Enh #5799: `yii\bootstrap\ButtonGroup::buttons` can take all options that are supported by `yii\bootstrap\Button` (aleksanderd)
- Chg #5874: Upgraded Twitter Bootstrap to 3.3.x (samdark)
......
......@@ -10,6 +10,7 @@ namespace yii\bootstrap;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Url;
/**
* Dropdown renders a Bootstrap dropdown menu component.
......@@ -25,7 +26,8 @@ class Dropdown extends Widget
* or an array representing a single menu with the following structure:
*
* - label: string, required, the label of the item link
* - url: string, optional, the url of the item link. Defaults to "#".
* - url: string|array, optional, the url of the item link. This will be processed by [[Url::to()]].
* If not set, the item will be treated as a menu header when the item has no sub-menu.
* - visible: boolean, optional, whether this menu item is visible. Defaults to true.
* - linkOptions: array, optional, the HTML attributes of the item link.
* - options: array, optional, the HTML attributes of the item.
......@@ -40,11 +42,6 @@ class Dropdown extends Widget
*/
public $encodeLabels = true;
/**
* @var array the HTML attributes for the widget container tag.
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/
protected $_containerOptions = [];
/**
* Initializes the widget.
......@@ -54,7 +51,6 @@ class Dropdown extends Widget
{
parent::init();
Html::addCssClass($this->options, 'dropdown-menu');
$this->_containerOptions = $this->options;
}
/**
......@@ -62,17 +58,18 @@ class Dropdown extends Widget
*/
public function run()
{
echo $this->renderItems($this->items);
echo $this->renderItems($this->items, $this->options);
BootstrapPluginAsset::register($this->getView());
}
/**
* Renders menu items.
* @param array $items the menu items to be rendered
* @param array $options the container HTML attributes
* @return string the rendering result.
* @throws InvalidConfigException if the label option is not specified in one of the items.
*/
protected function renderItems($items)
protected function renderItems($items, $options = [])
{
$lines = [];
foreach ($items as $i => $item) {
......@@ -89,18 +86,28 @@ class Dropdown extends Widget
}
$encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
$label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
$options = ArrayHelper::getValue($item, 'options', []);
$itemOptions = ArrayHelper::getValue($item, 'options', []);
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
$linkOptions['tabindex'] = '-1';
$content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions);
if (!empty($item['items'])) {
unset($this->_containerOptions['id']);
$content .= $this->renderItems($item['items']);
Html::addCssClass($options, 'dropdown-submenu');
$url = array_key_exists('url', $item) ? $item['url'] : null;
if (empty($item['items'])) {
if ($url === null) {
$content = $label;
Html::addCssClass($itemOptions, 'dropdown-header');
} else {
$content = Html::a($label, $url, $linkOptions);
}
} else {
$submenuOptions = $options;
unset($submenuOptions['id']);
$content = Html::a($label, $url === null ? '#' : $url, $linkOptions)
. $this->renderItems($item['items'], $submenuOptions);
Html::addCssClass($itemOptions, 'dropdown-submenu');
}
$lines[] = Html::tag('li', $content, $options);
$lines[] = Html::tag('li', $content, $itemOptions);
}
return Html::tag('ul', implode("\n", $lines), $this->_containerOptions);
return Html::tag('ul', implode("\n", $lines), $options);
}
}
Yii Framework 2 Codeception extension Change Log
================================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- no changes in this release.
......
Yii Framework 2 composer extension Change Log
=============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- no changes in this release.
......
......@@ -176,6 +176,9 @@ class Installer extends LibraryInstaller
protected function saveExtensions(array $extensions)
{
$file = $this->vendorDir . '/' . self::EXTENSION_FILE;
if (!file_exists(dirname($file))) {
mkdir(dirname($file), 0777, true);
}
$array = str_replace("'<vendor-dir>", '$vendorDir . \'', var_export($extensions, true));
file_put_contents($file, "<?php\n\n\$vendorDir = dirname(__DIR__);\n\nreturn $array;\n");
// invalidate opcache of extensions.php if exists
......
Yii Framework 2 debug extension Change Log
==========================================
2.0.1 under development
2.0.2 under development
-----------------------
- Bug #4820: Fixed reading incomplete debug index data in case of high request concurrency (martingeorg, samdark)
- Chg #6572: Allow panels to stay even if they do not receive any debug data (qiangxue)
2.0.1 December 07, 2014
-----------------------
- Bug #5402: Debugger was not loading when there were closures in asset classes (samdark)
......
......@@ -118,7 +118,17 @@ class DefaultController extends Controller
clearstatcache();
}
$indexFile = $this->module->dataPath . '/index.data';
if (is_file($indexFile) && is_readable($indexFile) && ($content = file_get_contents($indexFile)) !== false) {
$content = '';
$fp = @fopen($indexFile, 'r');
if ($fp !== false) {
@flock($fp, LOCK_SH);
$content = fread($fp, filesize($indexFile));
@flock($fp, LOCK_UN);
fclose($fp);
}
if ($content !== '') {
$this->_manifest = array_reverse(unserialize($content), true);
} else {
$this->_manifest = [];
......@@ -142,9 +152,6 @@ class DefaultController extends Controller
if (isset($data[$id])) {
$panel->tag = $tag;
$panel->load($data[$id]);
} else {
// remove the panel since it has not received any data
unset($this->module->panels[$id]);
}
}
$this->summary = $data['summary'];
......
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