Ячейки Представления - это небольшие мини-контроллеры, которые могут вызывать логику представления и выводить результат в шаблоны. Данная идея позаимствована от ячеек в Ruby, где они играют схожую роль и приследуют схожие цели.
Ячейки идеально подходят для создания повторно используемых компонентов страницы, которые требуют взаимодействия с моделями, логикой представления и логикой визуализации. Простым примером может служить корзина в интернет-магазине или навигационное меню, зависящее от данных в CMS.
Чтобы создать ячейку, определите класс в src/View/Cell и шаблон в src/Template/Cell/. В этом примере мы создадим ячейку для отображения количества сообщений в почтовом ящике уведомлений пользователя. Сначала создайте файл класса. Его содержимое должно выглядеть так:
namespace App\View\Cell;
use Cake\View\Cell;
class InboxCell extends Cell
{
public function display()
{
}
}
Сохраните этот файл как src/View/Cell/InboxCell.php. Как вы можете заметить, подобно другим классам в CakePHP, Ячейки имеют несколько соглашений:
Ячейки располагаются в пространстве имен App\View\Cell
. Если вы создаете
ячейку в плагине, пространство имен должно быть вида PluginName\View\Cell
.
Имена классов должны оканчиваться на Cell
.
Классы должны наследоваться от Cake\View\Cell
.
Мы добавили пустой метод display()
в нашу ячейку; это традиционный метод
по умолчанию при рендеринге ячейки. Мы рассмотрим, как использовать другие методы
позже в документации. Теперь создайте файл src/Template/Cell/Inbox/display.ctp.
Это будет наш шаблон для нашей новой ячейки.
Мы можем быстро сгенерировать эту заготовку кода, используя bake
:
bin/cake bake cell Inbox
Это создаст код, аналогичный тому, что мы описали выше.
Предположим, что мы работаем над приложением, которое позволяет пользователям
отправлять сообщения друг другу. У нас есть модель Messages
, и мы хотим
показать количество непрочитанных сообщений, не засоряя AppController. Это
идеальный вариант использования для ячейки. В классе, который мы только что
создали, добавьте следующее:
namespace App\View\Cell;
use Cake\View\Cell;
class InboxCell extends Cell
{
public function display()
{
$this->loadModel('Messages');
$unread = $this->Messages->find('unread');
$this->set('unread_count', $unread->count());
}
}
Поскольку ячейки используют ModelAwareTrait
и ViewVarsTrait
, их поведение
очень схоже с поведением контроллера. Мы можем использовать методы
loadModel()
и set()
точно так же, как в контроллере. В нашем файле шаблона
добавьте следующее:
<!-- src/Template/Cell/Inbox/display.ctp -->
<div class="notification-icon">
У вас <?= $unread_count ?> непрочитанных сообщений.
</div>
Примечание
Шаблоны ячеек имеют изолированную область видимости, которая не использует тот же самый экземпляр Представления, который используется для визуализации шаблона и макета для текущего экшена контроллера или других ячеек. Следовательно, они не знают о каких-либо вызовах хелперов или блоках, установленных в шаблоне/макете экшена и наоборот.
Ячейки могут быть загружены из представлений с помощью метода cell()
, и работают
аналогично в обоих контекстах:
// Загрузка ячейки на уровне приложения
$cell = $this->cell('Inbox');
// Загрузка ячейки из плагина
$cell = $this->cell('Messaging.Inbox');
Приведенный выше код загрузит класс названной ячейки, и исполнит метод
display()
. Вы можете вызывать другие методы следующим образом:
// Выполнить метод expanded() ячейки Inbox
$cell = $this->cell('Inbox::expanded');
Если вам понадобится логика контроллера, чтобы решить какие ячейки загружать в
запросе, вы можете использовать CellTrait
в вашем контроллере, чтобы сделать
доступным метод cell()
:
namespace App\Controller;
use App\Controller\AppController;
use Cake\View\CellTrait;
class DashboardsController extends AppController
{
use CellTrait;
// Остальной код.
}
Часто вам может понадобиться использовать параметры в методах ячеек, чтобы
добиться большей гибкости при их использовании. Используя вотрой и третий
аргументы метода cell()
, вы можете передать параметры экшена и
дополнительные опции классам ваших ячеек в виде индексированного массива:
$cell = $this->cell('Inbox::recent', ['-3 days']);
Это будет соответствовавть следующей сигнатуре функции:
public function recent($since)
{
}
Как только ячейка будет загружена и выполнена, вы вероятно захотите отобразить
её. Простейший способ отобразить ячейку - использовать echo
:
<?= $cell ?>
Это выведет шаблон, соответствующий названию нашего экшена, записанному в нижнем регистре с разделением слов подчеркиваниями, например display.ctp.
Поскольку ячейки используют View
для отображения шаблона, вы можете загружать
дополнительные ячейки внутри шаблона текущей ячейки, если это потребуется.
Примечание
Вывод ячейки с помощью echo
использует магический метод PHP
__toString()
, который предотвращает вывод имени файла и номера строки для
появляющихся ошибок. Для получения более информативных сообщений об ошибках
рекомендуется использовать метод Cell::render()
, например
По соглашениям ячейки визуализируют шаблоны, которые соответствуют экшену, который они выполняют. Если вам нужно отобразить другой шаблон представления, вы можете указать желаемый для отображения шаблон ячейки:
// Явный вызов метода render()
echo $this->cell('Inbox::recent', ['-3 days'])->render('messages');
// Установка шаблона перед выводом ячейки.
$cell = $this->cell('Inbox');
$cell->viewBuilder()->setTemplate('messages');
// До версии 3.4
$cell->viewBuilder()->template('messages');
// До версии 3.1
$cell->template = 'messages';
echo $cell;
При выводе ячеек вы можете захотеть кэшировать их содержимое, если оно меняется
нечасто, или чтобы повысить производительность вашего приложения. Вы можете
определить опцию cache
при создании ячейки для активации и настройки
параметров кэширования:
// Кэширование с использованием стандартной конфигурации и со сгенерированным ключом
$cell = $this->cell('Inbox', [], ['cache' => true]);
// Кэширование с определенной конфигурацией и со сгенерированным ключом
$cell = $this->cell('Inbox', [], ['cache' => ['config' => 'cell_cache']]);
// Определены и ключ и конфигурация кэширования
$cell = $this->cell('Inbox', [], [
'cache' => ['config' => 'cell_cache', 'key' => 'inbox_' . $user->id]
]);
Если ключ сгенерирован автоматически, название ключа будет сформировано из имени класса ячейки и имени шаблона, разделенных подчеркиванием.
Примечание
Для обработки каждой ячейки используется новый экземпляр View
,
таким образом они не используют общий контекст с главным шаблоном/макетом.
Каждая ячейка изолирована, и может иметь доступ только к переменным,
переданным в качестве параметров при вызове метода View::cell()
.
Создание ячейки, которая выводит разбитый на страницы результат запроса, может
быть осуществлено с помощью класса ORM Paginator
. Пример постраничной
навигации по избранным сообщениям пользователя может выглядеть так:
namespace App\View\Cell;
use Cake\View\Cell;
use Cake\Datasource\Paginator;
class FavoritesCell extends Cell
{
public function display($user)
{
$this->loadModel('Messages');
// Создание пагинатора
$paginator = new Paginator();
// Разбиение модели на страницы
$results = $paginator->paginate(
$this->Messages,
$this->request->getQueryParams(),
[
// Use a parameterized custom finder.
'finder' => ['favorites' => [$user]],
// Use scoped query string parameters.
'scope' => 'favorites',
]
);
$paging = $paginator->getPagingParams() + (array)$request->getParam('paging');
$this->request = $this->request->withParam('paging', $paging));
$this->set('favorites', $results);
}
}
Описанная выше ячейка разбивает на страницы модель Messages
, используя
scoped pagination parameters.
Добавлено в версии 3.5.0: Cake\Datasource\Paginator
был добавлен в версии 3.5.0.
В ячейках могут быть объявлены параметры конструктора, которые конвертируются в свойства при создании объекта ячейки:
namespace App\View\Cell;
use Cake\View\Cell;
use Cake\Datasource\Paginator;
class FavoritesCell extends Cell
{
protected $_validCellOptions = ['limit'];
protected $limit = 3;
public function display($userId)
{
$this->loadModel('Users');
$result = $this->Users->find('friends', ['for' => $userId]);
$this->set('favorites', $result);
}
}
Здесь мы определили свойство $limit
и добавили параметр ячейки limit
.
Это позволит нам определять параметр при создании ячейки:
$cell = $this->cell('Favorites', [$user->id], ['limit' => 10])
Параметры ячеек удобны, когда вы хотите, чтобы доступные в виде свойств данные переопределяли значения по умолчанию.