Merge branch 'master' of git://github.com/yiisoft/yii2 into ru-db-active-record.md

This commit is contained in:
Pavel Ivanov
2015-06-29 21:17:47 +03:00
8 changed files with 807 additions and 53 deletions

View File

@ -0,0 +1,296 @@
Sessões e Cookies
====================
Sessões e cookies permitem que dados sejam persistentes entre várias requisições de usuários. No PHP simples você pode acessá-los através das variáveis globais `$_SESSION` e `$_COOKIE`, respectivamente. Yii encapsula sessões e cookies como objetos e portanto, permite que você possa acessá-los de um modo orientado à objetos com melhorias adicionais úteis.
## Sessões<span id="sessions"></span>
Assim como [requisições](runtime-requests.md) e [respostas](runtime-responses.md), você pode ter acesso a sessões através do [componente de aplicação](structure-application-components.md) `session` que é uma instância de [[yii\web\Session]], por padrão.
### Abrindo e Fechando Sessões <span id="opening-closing-sessions"></span>
Para abrir e fechar uma sessão, você pode fazer o seguinte:
```php
$session = Yii::$app->session;
// verifica se a sessão está pronta para abrir
if ($session->isActive) ...
// abre uma sessão
$session->open();
// fecha uma sessão
$session->close();
// destrói todos os dados registrados em uma sessão.
$session->destroy();
```
Você pode chamar [[yii\web\Session::open()|open()]] and [[yii\web\Session::close()|close()]] várias vezes, sem causar erros; internamente os métodos irão verificar primeiro se a sessão já está aberta.
### Acessando Dados da Sessão <span id="access-session-data"></span>
Para acessar os dados armazenados em sessão, você pode fazer o seguinte:
```php
$session = Yii::$app->session;
// obter uma variável de sessão. Os exemplos abaixo são equivalentes:
$language = $session->get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] : null;
// definir uma variável de sessão. Os exemplos abaixo são equivalentes:
$session->set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';
// remover uma variável de sessão. Os exemplos abaixo são equivalentes:
$session->remove('language');
unset($session['language']);
unset($_SESSION['language']);
// verifica se a variável de sessão existe. Os exemplos abaixo são equivalentes:
if ($session->has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...
// percorrer todas as variáveis de sessão. Os exemplos abaixo são equivalentes:
foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...
```
> Observação: Quando você acessa os dados da sessão através do componente `session`, uma sessão será automaticamente aberta caso não tenha sido feito antes. Isso é diferente de acessar dados da sessão através de `$_SESSION`, o que requer uma chamada explícita de `session_start()`.
Ao trabalhar com dados de sessão que são arrays, o componente `session` tem uma limitação que o impede de modificar diretamente um elemento do array. Por exemplo,
```php
$session = Yii::$app->session;
// o seguinte código não funciona
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// o seguinte código funciona:
$session['captcha'] = [
'number' => 5,
'lifetime' => 3600,
];
// o seguinte código também funciona:
echo $session['captcha']['lifetime'];
```
Você pode usar uma das seguintes soluções para resolver este problema:
```php
$session = Yii::$app->session;
// use diretamente $_SESSION (certifique-se que Yii::$app->session->open() tenha sido chamado)
$_SESSION['captcha']['number'] = 5;
$_SESSION['captcha']['lifetime'] = 3600;
// obter todo o array primeiro, modificá-lo e depois salvá-lo
$captcha = $session['captcha'];
$captcha['number'] = 5;
$captcha['lifetime'] = 3600;
$session['captcha'] = $captcha;
// use ArrayObject em vez de array
$session['captcha'] = new \ArrayObject;
...
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// armazenar dados de array utilizando chaves com um prefixo comum
$session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
```
Para um melhor desempenho e legibilidade do código, recomendamos a última solução alternativa. Isto é, em vez de armazenar um array como uma variável de sessão única, você armazena cada elemento do array como uma variável de sessão que compartilha o mesmo prefixo de chave com outros elementos do array.
### Armazenamento de Sessão Personalizado <span id="custom-session-storage"></span>
A classe padrão [[yii\web\Session]] armazena dados da sessão como arquivos no servidor. Yii Também fornece as seguintes classes de sessão implementando diferentes formas de armazenamento:
* [[yii\web\DbSession]]: armazena dados de sessão em uma tabela no banco de dados.
* [[yii\web\CacheSession]]: armazena dados de sessão em um cache com a ajuda de um [cache component](caching-data.md#cache-components) configurado.
* [[yii\redis\Session]]: armazena dados de sessão utilizando [redis](http://redis.io/) como meio de armazenamento.
* [[yii\mongodb\Session]]: armazena dados de sessão em um [MongoDB](http://www.mongodb.org/).
Todas essas classes de sessão suportam o mesmo conjunto de métodos da API. Como resultado, você pode mudar para uma classe de armazenamento de sessão diferente, sem a necessidade de modificar o código da aplicação que usa sessões.
> Observação: Se você deseja acessar dados de sessão via`$_SESSION` enquanto estiver usando armazenamento de sessão personalizado, você deve certificar-se de que a sessão já foi iniciada por [[yii\web\Session::open()]]. Isso ocorre porque os manipuladores de armazenamento de sessão personalizada são registrados dentro deste método.
Para saber como configurar e usar essas classes de componentes, por favor consulte a sua documentação da API. Abaixo está um exemplo que mostra como configurar [[yii\web\DbSession]] na configuração da aplicação para usar uma tabela do banco de dados para armazenamento de sessão:
```php
return [
'components' => [
'session' => [
'class' => 'yii\web\DbSession',
// 'db' => 'mydb', // ID do componente de aplicação da conexão DB. O padrão é 'db'.
// 'sessionTable' => 'my_session', // nome da tabela de sessão. O padrão é 'session'.
],
],
];
```
Você também precisa criar a tabela de banco de dados a seguir para armazenar dados de sessão:
```sql
CREATE TABLE session
(
id CHAR(40) NOT NULL PRIMARY KEY,
expire INTEGER,
data BLOB
)
```
onde 'BLOB' refere-se ao tipo BLOB do seu DBMS preferido. Estes são os tipos de BLOB que podem ser usados para alguns SGBD populares:
- MySQL: LONGBLOB
- PostgreSQL: BYTEA
- MSSQL: BLOB
> Observação: De acordo com a configuração `session.hash_function` no php.ini , pode ser necessário ajustar o tamanho da coluna `id`. Por exemplo, se a configuração for `session.hash_function=sha256`, você deve usar um tamanho de 64 em vez de 40.
### Dados Flash <span id="flash-data"></span>
Dados flash é um tipo especial de dados de sessão que, uma vez posto em uma requisição, só estarão disponíveis durante a próxima requisição e serão automaticamente excluídos depois. Dados flash são mais comumente usados para implementar mensagens que só devem ser exibidas para os usuários finais, uma vez, tal como uma mensagem de confirmação exibida após um usuário submeter um formulário com sucesso.
Você pode definir e acessar dados de flash através do componente da aplicação `session`. Por exemplo,
```php
$session = Yii::$app->session;
// Request #1
// defini uma mensagem flash chamada "postDeleted"
$session->setFlash('postDeleted', 'You have successfully deleted your post.');
// Request #2
// exibe uma mensagem flash chamada "postDeleted"
echo $session->getFlash('postDeleted');
// Request #3
// $result será falso uma vez que a mensagem flash foi automaticamente excluída
$result = $session->hasFlash('postDeleted');
```
Assim como os dados da sessão regular, você pode armazenar dados arbitrários como os dados flash.
Quando você chama [[yii\web\Session::setFlash()]], ele substituirá todos os dados flash existente que tenha o mesmo nome.
Para acrescentar novos dados flash para uma mensagem existente com o mesmo nome, você pode chamá [[yii\web\Session::addFlash()]].
Por exemplo:
```php
$session = Yii::$app->session;
// Request #1
// adicionar algumas mensagens flash com o nome de "alerts"
$session->addFlash('alerts', 'You have successfully deleted your post.');
$session->addFlash('alerts', 'You have successfully added a new friend.');
$session->addFlash('alerts', 'You are promoted.');
// Request #2
// $alerts é um array de mensagens flash com o nome de "alerts"
$alerts = $session->getFlash('alerts');
```
> Observação: Tente não usar [[yii\web\Session::setFlash()]] junto com [[yii\web\Session::addFlash()]] para dados flash com o mesmo nome. Isto porque o último método coloca os dados flash automaticamente em um array, de modo que ele pode acrescentar novos dados flash com o mesmo nome. Como resultado, quando você chamar [[yii\web\Session::getFlash()]], você pode às vezes achar que está recebendo um array, quando na verdade você está recebendo uma string, dependendo da ordem da invocação destes dois métodos.
> Dica: Para mostrar mensagens flash você pode usar o widget [[yii\bootstrap\Alert|bootstrap Alert]] da seguinte forma:
>
> ```php
> echo Alert::widget([
> 'options' => ['class' => 'alert-info'],
> 'body' => Yii::$app->session->getFlash('postDeleted'),
> ]);
> ```
## Cookies <span id="cookies"></span>
Yii representa cada cookie como um objeto de [[yii\web\Cookie]]. Ambos, [[yii\web\Request]] e [[yii\web\Response]] mantém uma coleção de cookies através da propriedade chamada `cookies`. A coleção de cookie no primeiro representa os cookies submetidos na requisição, enquanto a coleção de cookie no último representa os cookies que são para serem enviados ao usuário.
### Lendo Cookies <span id="reading-cookies"></span>
Você pode obter os cookies na requisição corrente usando o seguinte código:
```php
// pega a coleção de cookie (yii\web\CookieCollection) do componente "request"
$cookies = Yii::$app->request->cookies;
// pega o valor do cookie "language". se o cookie não existir, retorna "en" como o valor padrão.
$language = $cookies->getValue('language', 'en');
// um caminho alternativo para pegar o valor do cookie "language"
if (($cookie = $cookies->get('language')) !== null) {
$language = $cookie->value;
}
// você também pode usar $cookies como um array
if (isset($cookies['language'])) {
$language = $cookies['language']->value;
}
// verifica se existe um cookie "language"
if ($cookies->has('language')) ...
if (isset($cookies['language'])) ...
```
### Enviando Cookies <span id="sending-cookies"></span>
Você pode enviar cookies para o usuário final utilizando o seguinte código:
```php
// pega a coleção de cookie (yii\web\CookieCollection) do componente "response"
$cookies = Yii::$app->response->cookies;
// adicionar um novo cookie a resposta que será enviado
$cookies->add(new \yii\web\Cookie([
'name' => 'language',
'value' => 'zh-CN',
]));
// remove um cookie
$cookies->remove('language');
// outra alternativa para remover um cookie
unset($cookies['language']);
```
Além das propriedades [[yii\web\Cookie::name|name]], [[yii\web\Cookie::value|value]] mostradas nos exemplos acima, a classe [[yii\web\Cookie]] também define outras propriedades para representar plenamente todas as informações de cookie disponíveis, tal como [[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]]. Você pode configurar essas propriedades conforme necessário para preparar um cookie e, em seguida, adicioná-lo à coleção de cookie da resposta.
> Observação: Para melhor segurança, o valor padrão de [[yii\web\Cookie::httpOnly]] é definido para `true`. Isso ajuda a reduzir o risco de um script do lado do cliente acessar o cookie protegido (se o browser suporta-lo). Você pode ler o [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) para mais detalhes.
### Validação de Cookie <span id="cookie-validation"></span>
Quando você está lendo e enviando cookies através dos componentes `request` e `response` como mostrado nas duas últimas subseções, você aproveita a segurança adicional de validação de cookie que protege que os cookies sejam modificados no lado do cliente. Isto é conseguido através da assinatura de cada cookie com um hash string, que permite a aplicação dizer se o cookie foi modificado no lado do cliente. Se assim for, o cookie não será acessível através do [[yii\web\Request::cookies|cookie collection]] do componente `request`.
> Observação: Validação de cookie apenas protege os valores dos cookies de serem modificados. Se um cookie não for validado, você ainda pode acessá-lo através de `$_COOKIE`. Isso ocorre porque as bibliotecas de terceiros podem manipular os cookies de forma independente que não envolve a validação de cookie.
Validação de cookie é habilitada por padrão. Você pode desabilitá-la definindo a propriedade [[yii\web\Request::enableCookieValidation]] para `false`, entretanto recomendamos fortemente que você não o faça.
> Observação: Cookies que são enviados/recebidos diretamente através de `$_COOKIE` e `setcookie()` NÃO serão validados.
Ao usar a validação de cookie, você deve especificar uma [[yii\web\Request::cookieValidationKey]] que será usada para gerar o supracitado hash strings. Você pode fazê-lo através da configuração do componente `request` na configuração da aplicação:
```php
return [
'components' => [
'request' => [
'cookieValidationKey' => 'fill in a secret key here',
],
],
];
```
> Observação: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] é fundamental para a segurança da sua aplicação. Ela só deve ser conhecida por pessoas de sua confiança. Não armazená-la no sistema de controle de versão.

View File

@ -98,7 +98,7 @@ All Rights Reserved.
* [Форматирование данных](output-formatting.md)
* [Постраничная разбивка](output-pagination.md)
* [Сортировка](output-sorting.md)
* **TBD** [Провайдеры данных](output-data-providers.md)
* [Провайдеры данных](output-data-providers.md)
* **TBD** [Виджеты для данных](output-data-widgets.md)
* [Темизация](output-theming.md)
@ -176,7 +176,7 @@ All Rights Reserved.
* [Интернационализация](tutorial-i18n.md)
* **TBD** [Отправка почты](tutorial-mailing.md)
* [Оптимизация производительности](tutorial-performance-tuning.md)
* **TBD** [Работа на shared хостинге](tutorial-shared-hosting.md)
* [Окружение виртуального хостинга](tutorial-shared-hosting.md)
* **TBD** [Шаблонизаторы](tutorial-template-engines.md)

View File

@ -0,0 +1,337 @@
Провайдеры данных
==============
В разделах [Постраничное разделение данных](output-pagination.md) и [Сортировка](output-sorting.md) было описано,
как сделать возможность для конечных пользователей, чтобы они могли выбирать определённую страницу для вывода данных и
сортировку их по некоторым колонкам.
Провайдер данных это класс, который реализует [[yii\data\DataProviderInterface]]. Такая реализация поддерживает в основном
разбивку на страницы и сортировку. Они обычно используются для работы [виджетов данных](output-data-widgets.md), что позволяет
конечным пользователям интерактивно использовать сортировку данных и их разбивку на страницы.
В Yii реализованы следующие классы провайдеров данных:
* [[yii\data\ActiveDataProvider]]: использует [[yii\db\Query]] или [[yii\db\ActiveQuery]] для запроса данных из базы данных,
возвращая их в виде массива или экземпляров [Active Record](db-active-record.md).
* [[yii\data\SqlDataProvider]]: выполняет запрос SQL к базе данных и возвращает результат в виде массива.
* [[yii\data\ArrayDataProvider]]: принимает большой массив и возвращает выборку из него с возможностью сортировки и разбивки
на страницы.
Использование всех этих провайдеров данных имеет общую закономерность:
```php
// создание провайдера данных с конфигурацией для сортировки и постраничной разбивки
$provider = new XyzDataProvider([
'pagination' => [...],
'sort' => [...],
]);
// Получение данных с разбивкой на страницы и сортировкой.
$models = $provider->getModels();
// получение количества данных на текущей странице
$count = $provider->getCount();
// получение общего количества данных на всех страницах
$totalCount = $provider->getTotalCount();
```
Определение поведений сортировки и разбивки для провайдера данных устанавливается через его свойства
[[yii\data\BaseDataProvider::pagination|pagination]] и [[yii\data\BaseDataProvider::sort|sort]], которые соответствуют
настройкам [[yii\data\Pagination]] and [[yii\data\Sort]]. Вы можете отключить сортировку и разбивку на страницы путём
выставления их настроек в `false`.
[Виджеты данных](output-data-widgets.md), такие как [[yii\grid\GridView]], имеют свойство `dataProvider`, которое может
принимать экземпляр провайдера данных для отображения его данных. Например:
```php
echo yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
]);
```
Эти провайдеры данных в некоторой степени различаются по использовании, в зависимости от источника данных. Далее
опишем более подробно использование каждого провайдера данных.
## ActiveDataProvider <span id="active-data-provider"></span>
Для использования [[yii\data\ActiveDataProvider]], необходимо настроить его свойство [[yii\data\ActiveDataProvider::query|query]].
Оно принимает любой [[yii\db\Query]] или [[yii\db\ActiveQuery]] объект. Если использовать первый, то данные будут возвращены в
виде массивов, если второй - данные также могут быть возвращены в виде массивов, а также в виде экземпляров
[Active Record](db-active-record.md). Например:
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// возвращает массив Post объектов
$posts = $provider->getModels();
```
Если изменить `$query` в этом примере на следующий код, то будут возвращены сырые массивы.
```php
use yii\db\Query;
$query = (new Query())->from('post')->where(['status' => 1]);
```
> Совет: Если query содержит условия сортировки в `orderBy`, то новые условия, полученные от конечных пользователей
(через настройки `sort`) будут добавлены к существующим условиям в `orderBy`. Любые условия в `limit` и `offset`
and `offset` будут переписаны запросом конечного пользователя к различным страницам ( через конфигурацию `pagination`)
По умолчанию, [[yii\data\ActiveDataProvider]] использует компонент приложения `db` для подключения к базе данных. Можно
использовать разные базы данных, настроив подключение через конфигурацию свойства [[yii\data\ActiveDataProvider::db]].
## SqlDataProvider <span id="sql-data-provider"></span>
[[yii\data\SqlDataProvider]] работает с сырыми запросами SQL, которые используются для извлечение необходимых данных.
Основываясь на спецификации из [[yii\data\SqlDataProvider::sort|sort]] и [[yii\data\SqlDataProvider::pagination|pagination]],
провайдер данных будет добавлять `ORDER BY` и `LIMIT` конструкции к SQL запросу, для возврата только запрошенной
страницы данных с учётом определённой сортировки.
Для использования [[yii\data\SqlDataProvider]], необходимо настроить свойства [[yii\data\SqlDataProvider::sql|sql]] и
[[yii\data\SqlDataProvider::totalCount|totalCount]]. Например:
```php
use yii\data\SqlDataProvider;
$count = Yii::$app->db->createCommand('
SELECT COUNT(*) FROM post WHERE status=:status
', [':status' => 1])->queryScalar();
$provider = new SqlDataProvider([
'sql' => 'SELECT * FROM post WHERE status=:status',
'params' => [':status' => 1],
'totalCount' => $count,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'title',
'view_count',
'created_at',
],
],
]);
// возвращает массив данных
$models = $provider->getModels();
```
> Совет: Свойство [[yii\data\SqlDataProvider::totalCount|totalCount]] обязательно только тогда, когда вам нужна разбивка
на страницы. Всё потому, что запрос SQL [[yii\data\SqlDataProvider::sql|sql]] будет изменяться провайдером данных для возврата
только текущей запрошенной страницы. Провайдеру необходимо знать общее количество данных в запросе для корректного
вычисления разбивки на доступные страницы.
## ArrayDataProvider <span id="array-data-provider"></span>
[[yii\data\ArrayDataProvider]] лучше использовать для работы с большим массивом. Этот провайдер помогает вернуть выборку
из большого массива с сортировкой по одному или нескольким колонкам. Для использования [[yii\data\ArrayDataProvider]]
необходимо определить свойство [[yii\data\ArrayDataProvider::allModels|allModels]], как большой массив. Элементы в
большом массиве могут быть ассоциативными массивами (например результаты выборки из [DAO](db-dao.md)) или объекты (
[Active Record](db-active-record.md) экземпляры). Например:
```php
use yii\data\ArrayDataProvider;
$data = [
['id' => 1, 'name' => 'name 1', ...],
['id' => 2, 'name' => 'name 2', ...],
...
['id' => 100, 'name' => 'name 100', ...],
];
$provider = new ArrayDataProvider([
'allModels' => $data,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => ['id', 'name'],
],
]);
// получает строки для текущей запрошенной странице
$rows = $provider->getModels();
```
> Совет: Сравнивая с [Active Data Provider](#active-data-provider) и [SQL Data Provider](#sql-data-provider),
ArrayDataProvider менее эффективный потому, что требует загрузки *всех* данных в память.
## Принципы работы с ключами данных <span id="working-with-keys"></span>
При возврате данных с помощью провайдера, часто требуется идентификация каждого элемента по уникальному ключу. Например,
если данные - это какая-то информация по клиенту, то возможно понадобится использовать ID клиента, как ключ для данных по
каждому клиенту. Провайдер данных через [[yii\data\DataProviderInterface::getModels()]] может вернуть список из ключей
и соответствующего набора данных. Например,
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => Post::find(),
]);
// возвращает массив объектов Post
$posts = $provider->getModels();
// возвращает значения первичного ключа в соответствии с $posts
$ids = $provider->getKeys();
```
В выше описанном примере, так как [[yii\data\ActiveDataProvider]] предоставляется один [[yii\db\ActiveQuery]] объект, то
в этом случае провайдер достаточно умён, чтобы вернуть значения первичных ключей в качестве идентификатора. Также есть
возможность настроить способ вычисления значение идентификатора, через настройку [[yii\data\ActiveDataProvider::key]], как
имя колонки или функция вычисления значений ключа. Например:
```php
// используется "slug" колонка как ключ
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => 'slug',
]);
// используется результат md5(id) как ключ
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => function ($model) {
return md5($model->id);
}
]);
```
## Создание своего провайдера данных <span id="custom-data-provider"></span>
Для создания своих классов провайдера данных, необходимо реализовать [[yii\data\DataProviderInterface]]. Простой способ
сделать это - наследовать [[yii\data\BaseDataProvider]], который помогает сфокусироваться на логике ядра провайдера данных.
В основном необходимо реализовать следующие методы:
- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]:подготавливает модели данных, которые будут доступны
в текущей странице и возвращает их в виде массива.
- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]: принимает массив имеющихся в настоящее время моделей
данных и возвращает ключи, связанные с ними.
- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]:возвращает значение, указывающее общее количество
моделей данных в провайдере данных.
Ниже приведён пример провайдера данных, который эффективно считывает данные из CSV:
```php
<?php
use yii\data\BaseDataProvider;
class CsvDataProvider extends BaseDataProvider
{
/**
* @var string name of the CSV file to read
*/
public $filename;
/**
* @var string|callable name of the key column or a callable returning it
*/
public $key;
/**
* @var SplFileObject
*/
protected $fileObject; // SplFileObject is very convenient for seeking to particular line in a file
/**
* @inheritdoc
*/
public function init()
{
parent::init();
// open file
$this->fileObject = new SplFileObject($this->filename);
}
/**
* @inheritdoc
*/
protected function prepareModels()
{
$models = [];
$pagination = $this->getPagination();
if ($pagination === false) {
// in case there's no pagination, read all lines
while (!$this->fileObject->eof()) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
} else {
// in case there's pagination, read only a single page
$pagination->totalCount = $this->getTotalCount();
$this->fileObject->seek($pagination->getOffset());
$limit = $pagination->getLimit();
for ($count = 0; $count < $limit; ++$count) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
}
return $models;
}
/**
* @inheritdoc
*/
protected function prepareKeys($models)
{
if ($this->key !== null) {
$keys = [];
foreach ($models as $model) {
if (is_string($this->key)) {
$keys[] = $model[$this->key];
} else {
$keys[] = call_user_func($this->key, $model);
}
}
return $keys;
} else {
return array_keys($models);
}
}
/**
* @inheritdoc
*/
protected function prepareTotalCount()
{
$count = 0;
while (!$this->fileObject->eof()) {
$this->fileObject->next();
++$count;
}
return $count;
}
}
```

View File

@ -5,7 +5,7 @@
разделяется на несколько частей, каждая из которых содержит и отображает только часть данных за один раз.
Такие части называются страницами, а сам процесс называется постраничным разделением данных.
Если вы используете [источник данных](output-data-providers.md) с одним из [виджетов данных](output-data-widgets.md),
Если вы используете [провайдер данных](output-data-providers.md) с одним из [виджетов данных](output-data-widgets.md),
то в этом случае будет автоматически использовано постраничное разделение данных. В противном случае вам требуется создать объект [[\yii\data\Pagination]],
заполнить его такими данными как [[\yii\data\Pagination::$totalCount|общее количество элементов]],
[[\yii\data\Pagination::$pageSize|количество элементов на одной странице]] и [[\yii\data\Pagination::$page|текущая страница]], затем применить

View File

@ -2,7 +2,7 @@
=======
Иногда выводимые данные требуется отсортировать в соответствии с одним или несколькими атрибутами.
Если вы используете [источник данных](output-data-providers.md) с одним из [виджетов данных](output-data-widgets.md),
Если вы используете [провайдер данных](output-data-providers.md) с одним из [виджетов данных](output-data-widgets.md),
сортировка будет применена автоматически. В противном случае вы должны создать экземпляр [[yii\data\Sort]],
настроить его и применить к запросу. Он также может быть передан в представление, где будет использован
для создания ссылок на сортировку по определенным атрибутам.

View File

@ -0,0 +1,120 @@
Окружение виртуального хостинга
==========================
Окружение виртуальных хостингов зачастую весьма ограничено в настройках конфигурации и структуры директорий.
Тем не менее, в большинстве случаев, внеся некоторые корректировки возможно запустить Yii2 на виртуальном хостинге.
Установка Basic приложения.
---------------------------
Поскольку на виртуальном хостинге обычно только один webroot, то лучше использовать Basic приложение. Прочитайте раздел
[Установка Yii](start-installation.md) и установите Basic приложение локально. После того как приложение работает локально,
можно сделать некоторые корректировки, которые помогут разместить приложение на виртуальном хостинге.
### Переименование webroot <span id="renaming-webroot"></span>
Подключитесь к вашему виртуальному хостингу используя FTP или другой способ. Вероятнее всего вы увидите следующее:
```
config
logs
www
```
В приведенном выше описании, `www` - это webroot директория вебсервера. Она может называться по-другому. Возможные названия:
`www`, `htdocs` или `public_html`.
В Basic приложении webroot называется `web`. Перед загрузкой своего приложения на виртуальный хостинг, переименуйте
локальный webroot на название webroot виртуального хостинга. Например `web` в `www` или `public_html`, в зависимости от
наименования webroot вашего хостинга.
### Корневая директория FTP доступна для записи
Если вы можете записать в корневую директорию, так где располагаются `config`, `logs` и `www`, то загрузите сюда же
`assets`, `commands` и остальные директории, также как у вас локально.
### Добавим настройки для вебсервера <span id="add-extras-for-webserver"></span>
Если ваш сервер Apache, то вы можете добавить в `web`(или `public_html`, или наподобие, там где располагается `index.php` файл)
директорию один файл `.htaccess` со следующим содержимым:
```
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
```
В случае использования nginx не требуется каких-либо дополнительных настроек.
### Проверка требований
Для того чтобы запустить Yii, ваш веб-сервер должен соответствовать его требованиям. Минимальное требование к PHP - это
его версия 5.4. Для того, чтобы проверить требования, скопируйте `requirements.php` из корневого каталога в каталог webroot
и запустить его с помощью браузера, используя url `http://example.com/requirements.php`. Не забудьте после проверки требований
удалить файл `requirements.php`.
Установка Advanced приложения
---------------------------------
Установка Advanced приложения немного сложнее, чем установка Basic, из-за того, что в Advanced приложении
имеются две директории webroot, работа с которыми на виртуальном хостинге не поддерживается. Нам нужно внести изменения
в структуру директорий.
### Перемещение входных скриптов в одну директорию webroot
Для начала нам необходимо директория webroot. Создайте новую директорию и назовите её, так же как на виртуальном хостинге,
например как описывалось выше в [Переименование webroot](#renaming-webroot) `www` или `public_html`, или наподобие.
Затем создайте следующую структуру в `www` директории, которую вы только что создали:
```
www
admin
backend
common
console
environments
frontend
...
```
`www` будет нашей фронтенд директорией, переместите в неё всё из `frontend/web`. Также поступите и для `backend/web`,
скопировав всё в `www/admin`. В каждом случае нужно настроить пути внутри файлов `index.php` и `index-test.php`.
### Отдельные сессии и куки
Изначально подразумевалось, что приложения бекенд и фронтенд располагаются на разных доменах. Когда мы перенесли всё в
один домен, то куки и сессии из бекенда и фронтенда будут пересекаться. Для исправления этого внесите следующие настройки
в конфигурацию backend приложения `backend/config/main.php`:
```php
'components' => [
'request' => [
'csrfParam' => '_backendCSRF',
'csrfCookie' => [
'httpOnly' => true,
'path' => '/admin',
],
],
'user' => [
'identityCookie' => [
'name' => '_backendIdentity',
'path' => '/admin',
'httpOnly' => true,
],
],
'session' => [
'name' => 'BACKENDSESSID',
'cookieParams' => [
'path' => '/admin',
],
],
],
```

View File

@ -195,7 +195,7 @@ class FontAwesomeAsset extends AssetBundle
'fonts/',
'css/',
]
],
];
}
```

View File

@ -17,63 +17,64 @@
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'(not set)' => '(тапсырылған жок)',
'(not set)' => '(берілмеген)',
'An internal server error occurred.' => 'Сервердің ішкі қатесі туды.',
'Are you sure you want to delete this item?' => 'Бұл элементті жоюға сенімдісіз бе?',
'Delete' => 'Жою',
'Error' => 'Қате',
'File upload failed.' => 'Файлды жүктеу сәті болмады',
'Home' => 'Басы',
'Invalid data received for parameter "{param}".' => 'Параметрдің мағынасы дұрыс емес"{param}".',
'Invalid data received for parameter "{param}".' => '"{param}" параметріне дұрыс емес мән берілген.',
'Login Required' => 'Кіруді сұрайды.',
'Missing required arguments: {params}' => 'Қажетті дәлелдер жоқ: {params}',
'Missing required arguments: {params}' => 'Қажетті аргументтер жоқ: {params}',
'Missing required parameters: {params}' => 'Қажетті параметрлер жоқ: {params}',
'No' => 'Жоқ',
'No help for unknown command "{command}".' => 'Анықтама белгісіз команда үшін ақиық "{command}".',
'No help for unknown sub-command "{command}".' => 'Анықтама белгісіз субкоманда үшін ақиық "{command}".',
'No results found.' => 'Ештене табылған жок.',
'Only files with these extensions are allowed: {extensions}.' => 'Файлды жүктеу тек қана осы аумақтармен: {extensions}.',
'Page not found.' => 'Парақ табылған жок.',
'Please fix the following errors:' => 'Мына қателерді түзеніз:',
'Please upload a file.' => 'Файлды жүктеу.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Жазбалар көрсетілген <b>{begin, number}-{end, number}</b> дан <b>{totalCount, number}</b>.',
'The file "{file}" is not an image.' => 'Файл «{file}» сурет емес.',
'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Файл «{file}» көлемі өте үлкен. Өлшемі осыдан аспау керек,неғұрлым {limit, number} {limit, plural, one{байт} few{байтар} many{байтар} other{байтар}}.',
'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Файл «{file}» көлемі өте кіші. Өлшемі осыдан астам болу керек,неғұрлым {limit, number} {limit, plural, one{байт} few{байтар} many{байтар} other{байтар}}.',
'The format of {attribute} is invalid.' => 'Форматың мағынасы дұрыс емес «{attribute}».',
'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» өте үлкен. Ұзындығы осыдан аспау керек,неғұрлым {limit, number} {limit, plural, one{пиксель} few{пиксельдер} many{пиксельдер} other{пиксельдер}}.',
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» өте үлкен. Ені осыдан аспау керек,неғұрлым {limit, number} {limit, plural, one{пиксель} few{пиксельдер} many{пиксельдер} other{пиксельдер}}.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» өте кіші. Ұзындығы осыдан астам болу керек,неғұрлым limit, number} {limit, plural, one{пиксель} few{пиксельдер} many{пиксельдер} other{пиксельдер}}.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» өте кіші. Ені осыдан астам болу керек,неғұрлым {limit, number} {limit, plural, one{пиксель} few{пиксельдер} many{пиксельдер} other{пиксельдер}}.',
'No help for unknown command "{command}".' => 'Белгісіз "{command}" командасы үшін көмек табылмады.',
'No help for unknown sub-command "{command}".' => 'Белгісіз "{command}" ішкі командасы үшін көмек табылмады.',
'No results found.' => 'Нәтиже табылған жок.',
'Only files with these extensions are allowed: {extensions}.' => 'Тек мына кеңейтудегі файлдарға ғана рұқсат етілген: {extensions}.',
'Page not found.' => 'Бет табылған жок.',
'Please fix the following errors:' => 'Өтінеміз, мына қателерді түзеңіз:',
'Please upload a file.' => 'Файлды жүктеңіз.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => '<b>{totalCount, number}</b> жазбадан <b>{begin, number}-{end, number}</b> аралығы көрсетілген.',
'The file "{file}" is not an image.' => '«{file}» файлы сурет емес.',
'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => '«{file}» файлының өлшемі тым үлкен. Көлемі {limit, number} байттан аспау керек.',
'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => '«{file}» файлының өлшемі тым кіші. Көлемі {limit, number} байттан кем болмауы керек.',
'The format of {attribute} is invalid.' => '«{attribute}» аттрибутының форматы дұрыс емес.',
'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '«{file}» суретінің өлшемі тым үлкен. Биіктігі {limit, number} пиксельден аспауы қажет.',
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '«{file}» суретінің өлшемі тым үлкен. Ені {limit, number} пиксельден аспауы қажет.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '«{file}» суретінің өлшемі тым кіші. Биіктігі {limit, number} пиксельден кем болмауы қажет.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '«{file}» суретінің өлшемі тым кіші. Ені {limit, number} пиксельден кем болмауы қажет.',
'The verification code is incorrect.' => 'Тексеріс коды қате.',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Барі <b>{count, number}</b> {count, plural, one{жазба} few{жазбалар} many{жазбалар} other{жазбалар}}.',
'Unable to verify your data submission.' => 'Берілген мәліметердің тексеру сәті болмады.',
'Unknown command "{command}".' => 'Белгісіз команда "{command}".',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Барлығы <b>{count, number}</b> жазба.',
'Unable to verify your data submission.' => 'Жіберілген мәліметерді тексеру мүмкін емес.',
'Unknown command "{command}".' => '"{command}" командасы белгісіз.',
'Unknown option: --{name}' => 'Белгісіз опция: --{name}',
'Update' => 'Жаңалау',
'Update' => 'Жаңарту',
'View' => 'Көру',
'Yes' => 'Я',
'You are not allowed to perform this action.' => 'Сізге адал әрекет жасауға болмайды',
'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Сіз осыдан жүктеуге астам {limit, number} {limit, plural, one{файла} few{файлдар} many{файлдар} other{файлдар}}.',
'the input value' => 'кіргізілген мағыналар',
'{attribute} "{value}" has already been taken.' => '{attribute} «{value}» Бұл бос емес.',
'{attribute} cannot be blank.' => 'Толтыруға қажет «{attribute}».',
'{attribute} is invalid.' => 'Мағына «{attribute}» дүрыс емес.',
'{attribute} is not a valid URL.' => 'Мағына «{attribute}» дұрыс URL емес.',
'{attribute} is not a valid email address.' => 'Мағына «{attribute}» дұрыс email адрес емес.',
'{attribute} must be "{requiredValue}".' => 'Мағына «{attribute}» тең болу керек «{requiredValue}».',
'{attribute} must be a number.' => 'Мағына «{attribute}» сан болу керек.',
'{attribute} must be a string.' => 'Мағына «{attribute}» әріп болу керек.',
'{attribute} must be an integer.' => 'Мағына «{attribute}» бүтін сан болу керек.',
'{attribute} must be either "{true}" or "{false}".' => 'Мағына «{attribute}» тең болу керек «{true}» немесе «{false}».',
'{attribute} must be greater than "{compareValue}".' => 'Мағына «{attribute}» мағынасынан үлкен болу керек «{compareValue}».',
'{attribute} must be greater than or equal to "{compareValue}".' => 'Мағына «{attribute}» үлкен болу керек немесе мағынасынан тең болу керек «{compareValue}».',
'{attribute} must be less than "{compareValue}".' => 'Мағына «{attribute}» мағынасынан кіші болу керек «{compareValue}».',
'{attribute} must be less than or equal to "{compareValue}".' => 'Мағына «{attribute}» кіші болу керек немесе мағынасынан тең болу керек «{compareValue}».',
'{attribute} must be no greater than {max}.' => 'Мағына «{attribute}» аспау керек {max}.',
'{attribute} must be no less than {min}.' => 'Мағына «{attribute}» көп болу керек {min}.',
'{attribute} must be repeated exactly.' => 'Мағына «{attribute}» дәлме-дәл қайталану керек.',
'{attribute} must not be equal to "{compareValue}".' => 'Мағына «{attribute}» тең болмау керек «{compareValue}».',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => 'Мағына «{attribute}» минимум болу керек {min, number} {min, plural, one{рәміз} few{рәміздер} many{рәміздер} other{рәміздер}}.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => 'Мағына «{attribute}» өте үлкен болу керек {max, number} {max, plural, one{рәміз} few{рәміздер} many{рәміздер} other{рәміздер}}.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => 'Мағынада «{attribute}» болу керек {length, number} {length, plural, one{рәміз} few{рәміздер} many{рәміздер} other{рәміздер}}.',
'Yes' => 'Иә',
'You are not allowed to perform this action.' => 'Сізге бұл әрекетті жасауға рұқсат жоқ',
'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Сіз {limit} файлдан көп жүктей алмайсыз.',
'the input value' => 'енгізілген мән',
'{attribute} "{value}" has already been taken.' => '{attribute} «{value}» Бұл бос емес мән.',
'{attribute} cannot be blank.' => '«{attribute}» толтыруды қажет етеді.',
'{attribute} is invalid.' => '«{attribute}» мәні жарамсыз.',
'{attribute} is not a valid URL.' => '«{attribute}» жарамды URL емес.',
'{attribute} is not a valid email address.' => '«{attribute}» жарамды email адрес емес.',
'{attribute} must be "{requiredValue}".' => '«{attribute}» мәні «{requiredValue}» болу керек.',
'{attribute} must be a number.' => '«{attribute}» мәні сан болуы керек.',
'{attribute} must be a string.' => '«{attribute}» мәні мәтін болуы керек.',
'{attribute} must be an integer.' => '«{attribute}» мәні бүтін сан болу керек.',
'{attribute} must be either "{true}" or "{false}".' => '«{attribute}» мәні «{true}» немесе «{false}» болуы керек.',
'{attribute} must be greater than "{compareValue}".' => '«{attribute}» мәні мынадан үлкен болуы керек: «{compareValue}».',
'{attribute} must be greater than or equal to "{compareValue}".' => '«{attribute}» мәні мынадан үлкен немесе тең болуы керек: «{compareValue}».',
'{attribute} must be less than "{compareValue}".' => '«{attribute}» мәні мынадан кіші болуы керек: «{compareValue}».',
'{attribute} must be less than or equal to "{compareValue}".' => '«{attribute}» мәні мынадан кіші немесе тең болуы керек: «{compareValue}».',
'{attribute} must be no greater than {max}.' => '«{attribute}» мәні мынадан аспауы керек: {max}.',
'{attribute} must be no less than {min}.' => '«{attribute}» мәні мынадан кем болмауы керек: {min}.',
'{attribute} must be repeated exactly.' => '«{attribute}» мәні дәлме-дәл қайталану керек.',
'{attribute} must not be equal to "{compareValue}".' => '«{attribute}» мәні мынаған тең болмауы керек: «{compareValue}».',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '«{attribute}» мәні кемінде {min} таңбадан тұруы керек.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '«{attribute}» мәні {max} таңбадан аспауы қажет.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '«{attribute}» {length} таңбадан тұруы керек.',
];