Cake\ORM\TableТабличные объекты получают доступ к коллекции сущностей, хранящихся в конкретной
таблице. Для взаимодействия с каждой таблицей, в вашем приложение, необходимо
использовать соответствующий класс Table. Если вам не нужно настраивать
поведение данной таблицы, можно полностью положиться на CakePHP, который
сгенерирует необходимый класс.
Перед попыткой использовать табличные объекты и ORM, вы должны убедиться в правильной конфигурации соединения с базой данных.
Для начала создайте класс Table. Подобные классы располагаются в
src/Model/Table. Классы Table это коллекция типовых моделей реляционной
базы данных, представляющие основной интерфейс для взаимодействия с вашей базой
данных в CakePHP ORM. Самый простой класс таблицы будет выглядеть следующим
образом:
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
}
Обратите внимание, мы не сообщили ORM какую таблицу использует наш класс. При
соблюдение соглашения о базе данных в
этом нет необходимости. В приведённом выше примере будет использоваться таблица
с именем articles. Если, например, имя таблицы будет blog_posts, то
класс, отвечающий за взаимодействие с ней, будет именоваться BlogPostsTable.
Вы можете указать другое имя таблицы, воспользовавшись методом setTable():
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->setTable('my_table');
// До 3.4.0
$this->table('my_table');
}
}
При явном указание таблицы, ORM будет продолжать следовать соглашениям, ожидая
первичного ключа с именем id. Если вам нужно изменить и это, можете
воспользоваться методом setPrimaryKey():
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->setPrimaryKey('my_id');
// До 3.4.0
$this->primaryKey('my_id');
}
}
По умолчанию, табличные объекты используют класс Entity, основываясь на
соглашение об именование моделей. Например, если ваш класс таблицы называется
ArticlesTable, то класс Entity должен называться Article. Если класс
таблицы с именем PurchaseOrdersTable, то Entity класс PurchaseOrder.
Если, однако, вы хотите использовать имя класса Entity идущее вразрез с
соглашением, вы можете воспользоваться методом setEntityClass() для смены
имени:
class PurchaseOrdersTable extends Table
{
public function initialize(array $config)
{
$this->setEntityClass('App\Model\Entity\PO');
// До 3.4.0
$this->entityClass('App\Model\Entity\PO');
}
}
Как видно из приведенных выше примеров, табличные объекты имеют метод
initialize(), который вызывается после метода конструктора. Рекомендуется
использовать этот метод для выполнения логики инициализации, вместо
переопределения конструктора.
Для взаимодействия с таблицами вашей базы данных, необходимо получить экземпляр
таблицы. Этого можно добиться, используя класс TableRegistry:
// В контроллере и методе.
use Cake\ORM\TableRegistry;
// Prior to 3.6 use TableRegistry::get('Articles')
$articles = TableRegistry::getTableLocator()->get('Articles');
Класс TableRegistry предоставляет различные зависимости для построения
таблицы и ведёт реестр всех созданных экземпляров таблиц, что упрощает
построение отношений и настройку ORM. Смотрите раздел Использование TableRegistry,
для получения дополнительной информации.
Если ваш класс таблицы находится в плагине, необходимо использовать корректное имя класса. Не соблюдение этого правила может привезти к ошибкам. Чтобы этого не допустить, следуйте следующим примерам:
// Таблица плагина
// Prior to 3.6 use TableRegistry::get('PluginName.Articles')
$articlesTable = TableRegistry::getTableLocator()->get('PluginName.Articles');
// Таблица плагина с префиксом vendor'а
// Prior to 3.6 use TableRegistry::get('VendorName/PluginName.Articles')
$articlesTable = TableRegistry::getTableLocator()->get('VendorName/PluginName.Articles');
Как можно видеть выше, табличные объекты запускают несколько событий. События полезны, если вы хотите подключиться к ORM и добавить логику без подклассов или методов переопределения. Слушатели событий могут быть определены в классах таблиц и поведений. Вы также можете использовать диспетчер событий таблицы для привязки прослушивателей.
При использовании методов обратного вызова в методе initialize(), они будут
активированы слушателями до срабатывания методов обратного вызова таблицы.
Аналогичная ситуация с контроллерами и компонентами.
Чтобы добавить прослушиватель события в класс Table или Behavior, просто
реализуйте сигнатуры метода как описано ниже. Для ознакомления с дополнительной
информацией, по использованию подсистемы событий, см. Система событий.
Model.initialize
Model.beforeMarshal
Model.beforeFind
Model.buildValidator
Model.buildRules
Model.beforeRules
Model.afterRules
Model.beforeSave
Model.afterSave
Model.afterSaveCommit
Model.beforeDelete
Model.afterDelete
Model.afterDeleteCommit
Cake\ORM\Table::initialize(Event $event, ArrayObject $data, ArrayObject $options)¶Событие Model.initialize запускается после вызова методов конструктора и
инициализации. Классы Table, по умолчанию, не слушают это событие, используя
вместо этого метод initialize.
Для прослушивания и ответа на событие Model.initialize, вы можете
создать класс слушателя, реализующий интерфейс EventListenerInterface:
use Cake\Event\EventListenerInterface;
class ModelInitializeListener implements EventListenerInterface
{
public function implementedEvents()
{
return array(
'Model.initialize' => 'initializeEvent',
);
}
public function initializeEvent($event)
{
$table = $event->getSubject();
// сделаем что-нибудь здесь
}
}
и присоединить слушателя к глобальному диспетчеру EventManager:
use Cake\Event\EventManager;
$listener = new ModelInitializeListener();
EventManager::instance()->attach($listener);
Это вызовет вызов initializeEvent любого класса Table.
Cake\ORM\Table::beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)¶Событие Model.beforeMarshal запускается до преобразования данных запроса в
объекты. Дополнительная информация, об модификации данных запроса перед преобразованием в объекты,
доступна в документации.
Cake\ORM\Table::beforeFind(Event $event, Query $query, ArrayObject $options, $primary)¶Событие Model.beforeFind запускается перед каждой операцией поиска. Остановив
событие и предоставив возвращаемое значение, вы можете полностью обойти операцию
поиска. Любые изменения, сделанные для экземпляра $query, будут сохранены для
остальной части поиска. Параметр $primary служит признаком корневого
запроса, либо связанного с ним запроса. Все ассоциации, участвующие в запросе,
будут запускать событие Model.beforeFind. Для ассоциаций, которые используют
объединения, будет предоставлен mock-запрос. В вашем слушателе событий вы
можете установить дополнительные поля, условия, или объединения. Эти
параметры/функции будут скопированы в корневой запрос.
Вы можете использовать Model.beforeFind для ограничения операций поиска, на
основе прав пользователя, или принимать решение о кэширование, на основе текущей
нагрузки.
В предыдущих версиях CakePHP присутствовало событие afterFind, заменённое с
помощью изменения результатов с помощью Map/Reduce и
конструкторов объекта.
Cake\ORM\Table::buildValidator(Event $event, Validator $validator, $name)¶Событие Model.buildValidator срабатывает после вызова именованных правил
проверки $name, например, validationDefault. Можно использовать эту
функцию для добавления методов проверки.
Cake\ORM\Table::buildRules(Event $event, RulesChecker $rules)¶Событие Model.buildRules срабатывает после создания экземпляра правил
проверки и после вызова табличного метода buildRules().
Cake\ORM\Table::beforeRules(Event $event, EntityInterface $entity, ArrayObject $options, $operation)¶Событие Model.beforeRules вызывается до применения правил проверки.
Остановив событие, вы можете завершить проверку и вернуть результат применения
правил.
Cake\ORM\Table::afterRules(Event $event, EntityInterface $entity, ArrayObject $options, $result, $operation)¶Событие Model.afterRules вызывается после применения правил проверки.
Остановив это событие, вы можете вернуть итоговый результат проверки правил.
Cake\ORM\Table::beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие Model.beforeSave вызывается перед каждым сохранением объекта.
Остановка данной функции прервёт операцию сохранения, вернув результат события.
Остановка событий описано в соответствующем разделе
книги.
Cake\ORM\Table::afterSave(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие Model.afterSave запускается после сохранения объекта.
Cake\ORM\Table::afterSaveCommit(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие Model.afterSaveCommit запускается после транзакции, в которой прошла
операция сохранения. Оно также срабатывает для неатомарных сохранений, где
операции с базой данных неявно совершены. Событие запускается только для
первичной таблицы, для которой непосредственно вызывается метод save().
Событие не запускается, если транзакция началась до вызова сохранения.
Cake\ORM\Table::beforeDelete(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие запускается перед удалением объекта. Остановка этого события прервёт операцию удаления. Когда событие остановлено, возвратится её результат выполнения. Остановка событий описано в соответствующем разделе книги.
Cake\ORM\Table::afterDelete(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие Model.afterDelete запускается после удаления объекта.
Cake\ORM\Table::afterDeleteCommit(Event $event, EntityInterface $entity, ArrayObject $options)¶Событие Model.afterDeleteCommit запускается после транзакции, в которой прошла
операция удаления. Оно также срабатывает для неатомарных удаления, где операции с
базой данных неявно совершены. Событие запускается только для первичной таблицы,
для которой непосредственно вызывается метод delete(). Событие не
запускается, если транзакция началась до вызова удаления.
Cake\ORM\Table::addBehavior($name, array $options = [])¶Поведения обеспечивают простой способ использования повторяемых фрагментов кода, связанных с табличными классами. Возможно, вам интересно почему поведения это обычные классы, а не трейты. Основная причина в прослушивателях событий. Хотя трейты позволяют использовать повторно фрагменты логики, они усложнят связанные события.
Для добавления поведения в таблицу, необходимо вызвать метод addBehavior().
Как правило, наилучшим местом для этого является метод initialize():
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
}
Как и в случае с ассоциациями, вы можете использовать синтаксис плагина для указания дополнительных параметров конфигурации:
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp', [
'events' => [
'Model.beforeSave' => [
'created_at' => 'new',
'modified_at' => 'always'
]
]
]);
}
}
Вы можете узнать больше о поведениях, включая тех, что входят в ядро CakePHP, из соответствующего раздела о поведениях.
По умолчанию, все экземпляры таблицы используют default соединение с базой
данных. Если ваше приложение использует несколько подключений к базе данных, вам
необходимо указать соответствующее соединение, воспользовавшись методом
defaultConnectionName():
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public static function defaultConnectionName() {
return 'replica_db';
}
}
Примечание
Метод defaultConnectionName() должен быть статическим.
Cake\ORM\TableRegistry¶Как мы видели ранее, класс TableRegistry предоставляет простой способ
использования реестра для доступа к экземплярам таблиц ваших приложений. Он
также предоставляет несколько других полезных функций.
Cake\ORM\TableRegistry::get($alias, $config)¶При загрузке таблиц из реестра, вы можете изменить их зависимости или
использовать mock-объекты, предоставляя массив $options:
$articles = TableRegistry::getTableLocator()->get('Articles', [
'className' => 'App\Custom\ArticlesTable',
'table' => 'my_articles',
'connection' => $connectionObject,
'schema' => $schemaObject,
'entityClass' => 'Custom\EntityClass',
'eventManager' => $eventManager,
'behaviors' => $behaviorRegistry
]);
Обратите внимание на параметры конфигурации connection и schema. Они
принимают не строковые значения, а объекты. Соединение будет принимать объект
Cake\Database\Connection и схему Cake\Database\Schema\Collection.
Примечание
Если ваша таблица также выполняет дополнительные настройки, в своём методе
initialize(), то эти значения будут перезаписывать те, что были внесены
в реестр.
Вы также можете предварительно настроить реестр с помощью метода config().
Данные конфигурации сохраняются для каждого псевдонима и могут быть
переопределены методом объекта initialize():
TableRegistry::config('Users', ['table' => 'my_users']);
Примечание
Настройка таблицы возможна только до или во время первого доступа к псевдониму. Выполнение этого после заполнения реестра не приведёт к желаемому результату.
Примечание
Статический API CakeORMTableRegistry устарел в CakePHP 3.6.0. Вместо этого используйте локатор таблицы.
Cake\ORM\TableRegistry::clear¶Во время тестов вам может понадобиться очистить реестр. Это часто полезно, когда вы используете mock-объекты или изменяете зависимости таблиц:
TableRegistry::clear();
Если вы не соблюдали соглашения, вероятней всего CakePHP не сможет найти ваши
классы Table и Entity. Чтобы исправить это, вы можете установить
пространство имён с помощью метода Cake\Core\Configure::write. Например:
/src
/App
/My
/Namespace
/Model
/Entity
/Table
Для схемы выше будет следующая настройка:
Cake\Core\Configure::write('App.namespace', 'App\My\Namespace');