Компоненты

Компоненты представляют собой пакеты логики, которые совместно используются контроллерами. CakePHP поставляется с фантастическим набором основных компонентов, которые вы можете использовать для различных общих задач. Вы также можете создавать свои собственные компоненты. Если у вас есть одинаковые участки кода, которые нужно скопировать и вставить в разные контроллеры, то, вы должны подумать над созданием своего собственного компонента для обеспечения этой функциональности. Создание компонента сохраняет код контроллера чистым и позволяет повторно использовать код в разных контроллерах.

Для получения дополнительной информации о компонентах, включенных в CakePHP, посмотрите главы для каждого компонента:

Настройка компонентов

Многие из основных компонентов требуют конфигурации. Вот некоторые примеры компонентов требующие конфигурации Аутентификация и Куки. Конфигурация для этих компонентов, и для компонентов в целом обычно выполняется с помощью loadComponent() в методе initialize() вашего контроллера или в массиве $components:

class PostsController extends AppController
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Auth', [
            'authorize' => 'Controller',
            'loginAction' => ['controller' => 'Users', 'action' => 'login']
        ]);
        $this->loadComponent('Cookie', ['expires' => '1 day']);
    }

}

Вы можете настроить компоненты во время выполнения с помощью метода config(). Часто, это делается в методе beforeFilter() вашего контроллера. Вышеизложенное может выражаться так:

public function beforeFilter(Event $event)
{
    $this->Auth->config('authorize', ['controller']);
    $this->Auth->config('loginAction', ['controller' => 'Users', 'action' => 'login']);

    $this->Cookie->config('name', 'CookieMonster');
}

Как и помощники(хелперы), компоненты реализуют метод config(), который используется для установики и получения любых данных конфигурации для компонента:

// Чтение данных конфигурации.
$this->Auth->config('loginAction');

// Установка конфигурации
$this->Csrf->config('cookieName', 'token');

Как и с помощниками, компоненты автоматически объединяют своё свойство $_defaultConfig с конфигурацией конструктора для создания свойства $_config, которое доступно с помощью метода config().

Псевдонимы компонентов

Одной из общих настроек для использования является опция className, которая позволяет вам использовать псевдонимы. Эта функция полезна, если вы хотите заменить $this->Auth или другую общую ссылку на компонент - своей пользовательской реализацией:

// src/Controller/PostsController.php
class PostsController extends AppController
{
    public function initialize()
    {
        $this->loadComponent('Auth', [
            'className' => 'MyAuth'
        ]);
    }
}

// src/Controller/Component/MyAuthComponent.php
use Cake\Controller\Component\AuthComponent;

class MyAuthComponent extends AuthComponent
{
    // Добавьте сюда свой код для переопределения ядра AuthComponent
}

Вышеупомянутый псевдоним MyAuthComponent для $this->Auth бедет доступен во всех ваших контроллерах.

Примечание

Псевдоним компонента заменяет этот экземпляр в любом месте этого компонента, включая другие компоненты.

Загрузка компонентов на лету

Возможно, вам не нужно, чтобы все ваши компоненты, были доступны во всех методах(экшенах) контроллера. В таких ситуациях вы можете загрузить компонент во время выполнения, используя метод loadComponent() в вашем контроллере:

// В определённом методе контроллера
$this->loadComponent('OneTimer');
$time = $this->OneTimer->getTime();

Примечание

Имейте в виду, что компоненты, загруженные «на лету», не будут пропущены через обратные вызовы. Если вы нуждаетесь в обратных вызовах (колбэках) beforeFilter или startup, вам может потребоваться вызвать их вручную, в зависимости от того, когда вы загружаете свой компонент.

Использование компонентов

После того, как вы подключили некоторые компоненты в свой контроллер, использование их довольно просто. Каждый компонент, который вы используете, отображается как свойство в вашем контроллере. Если вы загрузили Cake\Controller\Component\FlashComponent в вашем контроллере, вы можете получить доступ к нему следующим образом:

class PostsController extends AppController
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Flash');
    }

    public function delete()
    {
        if ($this->Post->delete($this->request->getData('Post.id')) {
            $this->Flash->success('Post deleted.');
            return $this->redirect(['action' => 'index']);
        }
    }

Примечание

Поскольку как модель, так и компонент добавляются к контроллерам как свойства и имеют одно и то же „namespace“ (пространство имён), важно не дать компоненту и модели одинаковое имя.

Создание компонента

Предположим, что нашему приложению необходимо выполнить сложную и одинаковую математическую операцию во многих разных частях приложения. Мы можем создать компонент для размещения этой общей логики для использования во многих разных контроллерах.

Первый шаг - создать новый компонентный файл и класс. Создайте файл в src/Controller/Component/MathComponent.php. Основная структура компонента будет выглядеть примерно так:

namespace App\Controller\Component;

use Cake\Controller\Component;

class MathComponent extends Component
{
    public function doComplexOperation($amount1, $amount2)
    {
        return $amount1 + $amount2;
    }
}

Примечание

Все компоненты должны размещаться в Cake\Controller\Component. Ошибка размещения компонента вызовет исключение.

Подключение вашего компонента в контроллеры

Как только ваш компонент будет закончен, вы сможем использовать его в контроллерах, загрузив его в методе initialize(). После загрузки контроллеру будет присвоен новый атрибут, названный в честь компонента, через который мы можем получить доступ к его экземпляру:

// В контроллере
// Создаем новый компонент в $this->Math,
// а также стандартный $this->Csrf
public function initialize()
{
    parent::initialize();
    $this->loadComponent('Math');
    $this->loadComponent('Csrf');
}

При включении компонентов в контроллер, вы также можете объявить набор параметров, которые будут переданы компоненту конструктором. Эти параметры затем могут обрабатываться компонентом:

// В вашем контроллере
public function initialize()
{
    parent::initialize();
    $this->loadComponent('Math', [
        'precision' => 2,
        'randomGenerator' => 'srand'
    ]);
    $this->loadComponent('Csrf');
}

Вышеизложенное передало бы массив, содержащий точность и randomGenerator в метод MathComponent::initialize(), в параметре $config.

Использование других компонентов в вашем компоненте

Иногда, одному из ваших компонентов может понадобиться использование другого компонента. В этом случае вы можете включить другие компоненты в свой компонент точно так же, как вы включаете их в контроллеры - с помощью переменной $components:

// src/Controller/Component/CustomComponent.php
namespace App\Controller\Component;

use Cake\Controller\Component;

class CustomComponent extends Component
{
    // Другой компонент, используемый вашим компонентом
    public $components = ['Existing'];

    // Выполните любую другую дополнительную настройку для своего компонента.
    public function initialize(array $config)
    {
        $this->Existing->foo();
    }

    public function bar()
    {
        // ...
    }
}

// src/Controller/Component/ExistingComponent.php
namespace App\Controller\Component;

use Cake\Controller\Component;

class ExistingComponent extends Component
{

    public function foo()
    {
        // ...
    }
}

Примечание

В отличие от компонента, включенного в контроллер, никакие обратные вызовы не будут инициированы на компоненте компонента.

Доступ к компонентам контроллера

Внутри компонента вы можете получить доступ к текущему контроллеру через „реестр“:

$controller = $this->_registry->getController();

Вы можете получить доступ к контроллеру в любом методе обратного вызова из события объекта:

$controller = $event->getSubject();

Обратные вызовы компонента

Компоненты также предлагают несколько обратных вызовов жизненного цикла запроса, которые позволяют им увеличить цикл запроса.

beforeFilter(Event $event)

Вызывается перед методом beforeFilter() контроллеров, но после метода initialize().

startup(Event $event)

Вызывается после метода beforeFilter() контроллеров, но до того, как контроллер выполнит текущее действие обработчика.

beforeRender(Event $event)

Вызывается после того, как контроллер выполняет логику запрошенного действия, но до того, как контроллер отобразит представления и макет.

shutdown(Event $event)

Вызывается до вывода в браузер.

beforeRedirect(Event $event, $url, Response $response)

Вызывается когда методом контроллера осуществляет перенаправление, но перед любым дальнейшим действием. Если этот метод возвращает false, контроллер не будет продолжать перенаправлять запрос. Параметры $url и $response позволяют вам проверять и изменять местоположение или любые другие заголовки в ответе.