04 Работа с моделями
Обзор
Модель Phalcon\Mvc\Model - это M
в MVC. Это класс, который соединяет бизнес-объекты и таблицы базы данных, чтобы создать постоянную модель домена, где логика и данные объединены в одно целое. Это реализация объектно-реляционного отображения (ORM).
Модель представляет информацию (данные) приложения и правила для управления этими данными. Модели в основном используются для управления правилами взаимодействия с соответствующей таблицей базы данных. В большинстве случаев каждая таблица в базе данных будет соответствовать одной модели в приложении. Основная часть бизнес-логики вашего приложения будет сосредоточена в моделях.
Phalcon\Mvc\Model - это первый ORM, написанный на языках Zephir/C для PHP, дающий разработчикам высокую производительность при взаимодействии с базами данных, а также Простой в использовании.
Примечание: модели предназначены для работы с базой данных на высоком уровне абстракции. Если вам необходимо работать с базами данных на более низком уровне, ознакомьтесь с документацией компонента Phalcon\Db.
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { }
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->save(); if (false === $result) { echo 'Error saving Invoice: '; $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Saved'; }
Примечание: для получения информации о том, как создать модель, пожалуйста, проверьте раздел создание моделей
Константы
Константа | Значение |
---|---|
DIRTY_STATE_DETACHED | 2 |
DIRTY_STATE_PERSISTENT | 0 |
DIRTY_STATE_TRANSIENT | 1 |
OP_CREATE | 1 |
OP_DELETE | 3 |
OP_NONE | 0 |
OP_UPDATE | 2 |
TRANSACTION_INDEX | ‘transaction’ |
Методы
final public function __construct( mixed $data = null, DiInterface $container = null, ManagerInterface $modelsManager = null )
Создает объект модели. Метод принимает массив данных, которые используются для заполнения объекта с помощью внутреннего использования assign
. При желании вы можете пройти контейнеру и объектные модели менеджера. Если они не будут переданы, будут использоваться значения по умолчанию.
public function __call(string $method, array $arguments): mixed
Обрабатывает вызовы методов, когда метод не реализован. Создает исключение Phalcon\Mvc\Model\Exception, если метод не существует
public static function __callStatic( string $method, array $arguments ): mixed
Обрабатывает вызовы методов, когда статический метод не реализован. Выбрасывает Phalcon\Mvc\Model\Exception, если метод не существует
public function __get(string $property)
Магический метод получения связанных записей с использованием псевдонима отношения в качестве свойства
public function __isset(string $property): bool
Магический метод проверки, является ли свойство допустимым отношением
public function __set(string $property, mixed $value)
Магический метод присвоения значений модели
public function addBehavior( BehaviorInterface $behavior ): void
Настройка поведения в модели
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; use Phalcon\Mvc\Model\Behavior\Timestampable; class Invoices extends Model { public function initialize() { $this->addBehavior( new Timestampable( [ 'onCreate' => [ 'field' => 'inv_created_at', 'format' => 'Y-m-d H:i:s', ], ] ) ); } }
public function appendMessage( MessageInterface $message ): ModelInterface
Добавляет настраиваемое сообщение о процессе проверки
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; use Phalcon\Messages\Message as Message; class Invoices extends Model { public function beforeSave() { if (0 === $this->inv_status_flag) { $message = new Message( 'Sorry, an invoice cannot be unpaid' ); $this->appendMessage($message); } } }
public function assign( mixed $data, array $whiteList = null, array $dataColumnMap = null ): ModelInterface
Присваивает модели данные. Параметр data
может быть массивом или строкой базы данных. Белый список whitelist
- это массив свойств модели, которые будут обновлены в процессе назначения. Пропущенные свойства не будут приняты, даже если они включены в массив или строку базы данных; тем не менее, если один из них требуется моделью, данные не будут сохранены, и модель выдаст ошибку. dataColumnMap
-это массив, который отображает столбцы из данных в фактическую модель. Это помогает, когда требуется сопоставить входные данные из массива, такого как $_POST
, с полями в базе данных.
Назначение значений модели из массива
<?php $invoice->assign( [ 'inv_cst_id' => 1, 'inv_status_flag' => 1, 'inv_title' => 'Invoice for ACME Inc.', 'inv_total' => 100, 'inv_created_at' => '2019-12-25 01:02:03', ] );
assign
с помощью строки базы данных. - Требуется карта столбцов
<?php $invoice->assign( $row, null, [ 'inv_cst_id' => 'customerId', 'inv_status_flag' => 'status', 'inv_title' => 'title', 'inv_total' => 'total', ] );
Обновите только поля inv_status_flag
, inv_title
, inv_total
.
<?php $invoice->assign( $_POST, [ 'inv_status_flag', 'inv_title', 'inv_total', ] );
По умолчанию assign
будет использовать сеттеры, если они существуют, вы можете отключить его, используя ini_set
для прямого использования свойств
ini_set('phalcon.orm.disable_assign_setters', true);
<?php $invoice->assign( $_POST, null, [ 'inv_status_flag', 'inv_title', 'inv_total', ] );
public static function average( mixed $parameters = null ): float
Возвращает среднее значение столбца для результирующего набора строк, соответствующих указанным условиям
<?php use MyApp\Models\Invoices; $average = Invoices::average( [ 'column' => 'inv_total', ] ); echo 'AVG: ', $average, PHP_EOL; $average = Invoices::average( [ 'inv_cst_id = 1', 'column' => 'inv_total', ] ); echo 'AVG [Customer: 1] ', $average, PHP_EOL;
public static function cloneResult( ModelInterface $base, array $data, int $dirtyState = 0 ): ModelInterface
Присваивает модели значения из массива, возвращая новую модель
<?php use MyApp\Models\Invoices; $invoice = Invoices::cloneResult( new Invoices(), [ 'inv_cst_id' => 1, 'inv_status_flag' => 0, 'inv_title' => 'Invoice for ACME Inc. #2', 'inv_total' => 400, 'inv_created_at' => '2019-12-25 01:02:03', ] );
public static function cloneResultMap( mixed $base, array $data, array $columnMap, int $dirtyState = 0, bool $keepSnapshots = null ): ModelInterface
Присваивает модели значения из массива, возвращая новую модель, используя карту столбцов.
<?php use MyApp\Models\Invoices; $invoice = Invoices::cloneResultMap( new Invoices(), [ 'customerId' => 1, 'status' => 0, 'title' => 'Invoice for ACME Inc. #2', 'total' => 400, 'created' => '2019-12-25 01:02:03', ] );
<?php use MyApp\Models\Invoices; $invoice = Invoices::cloneResultMap( new Invoices(), [ 'customerId' => 1, 'status' => 0, 'title' => 'Invoice for ACME Inc. #2', 'total' => 400, 'created' => '2019-12-25 01:02:03', ] );
public static function cloneResultMapHydrate( array $data, array $columnMap, int $hydrationMode ): mixed
Возвращает гидратированный результат на основе данных и карты столбцов
public static function count( mixed $parameters = null ): int
Возвращает количество записей, соответствующих указанным условиям.
<?php use MyApp\Models\Invoices; $average = Invoices::count(); echo 'COUNT: ', $average, PHP_EOL; $average = Invoices::count( 'inv_cst_id = 1' ); echo 'COUNT [Customer: 1] ', $average, PHP_EOL;
public function create(): bool
Вставляет модель в базу данных. Если запись существует в базе данных, функция create()
выдаст исключение. Он возвратит true
в случае успеха, false
-в противном случае.
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->assign( [ 'inv_cst_id' => 1, 'inv_status_flag' => 1, 'inv_title' => 'Invoice for ACME Inc.', 'inv_total' => 100, 'inv_created_at' => '2019-12-25 01:02:03', ] ); $result = $invoice->create();
public function delete(): bool
Удаляет экземпляр модели. Возврат true в случае успеха или false в противном случае.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('inv_id = 4'); $result = $invoice->delete(); $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 1, ] ] ); foreach ($invoices as $invoice) { $invoice->delete(); }
public function dump(): array
Возвращает простое представление объекта, которое можно использовать с var_dump()
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('inv_id = 4'); var_dump( $invoice->dump() );
public static function find( mixed $parameters = null ): ResultsetInterface
Запрос набора записей, соответствующих указанным условиям. функция find()
является достаточно гибким, чтобы принимать различные параметры для поиска требуемых данных. Дополнительные сведения см. в разделе Поиск записей.
<?php use MyApp\Models\Invoices; $invoice = Invoices::find();
public static function findFirst( mixed $parameters = null ): ModelInterface | null
Запрос первой записи, соответствующей указанным условиям. Если запись не найдена, она возвращает результирующий набор или значение null
.
ПРИМЕЧАНИЕ:
findFirst()
больше не возвращает значениеfalse
, если записи не найдены.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst();
public function fireEvent(string $eventName): bool
Инициирует событие, неявно вызывает поведение, и прослушиватели в диспетчере событий уведомляются
public function fireEventCancel(string $eventName): bool
Инициирует событие, неявно вызывает поведение, и прослушиватели в диспетчере событий уведомляются. Этот метод останавливается, если один из обратных вызовов/прослушивателей возвращает значение false
public function getChangedFields(): array
Возвращает список измененных значений.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst(); print_r( $invoice->getChangedFields() ); // [] $invoice->inv_total = 120;; $invoice->getChangedFields(); print_r( $invoice->getChangedFields() ); // ['inv_total']
public function getDirtyState(): int
Возвращает одну из констант DIRTY_STATE_*
, указывающую, существует ли запись в базе данных или нет
public function getMessages( mixed $filter = null ): MessageInterface[]
Возвращает массив сообщений проверки
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->save(); if (false === $result) { echo 'Error saving Invoice: '; $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Saved'; }
ПРИМЕЧАНИЕ:
save()
больше не принимает параметры для установки данных. Вместо этого можно использоватьassign
.
public function getModelsManager(): ManagerInterface
Возвращает диспетчер моделей, связанный с экземпляром сущности
public function getModelsMetaData(): MetaDataInterface
Возвращает службу метаданных модели, связанную с экземпляром сущности
public function getOperationMade(): int
Возвращает тип последней операции, выполняемой ORM. Возвращает одну из констант класса OP_*
public function getOldSnapshotData(): array
Возвращает внутренние старые данные моментального снимка
final public function getReadConnection(): AdapterInterface
Получение соединения, используемого для чтения данных для модели
final public function getReadConnectionService(): string
Возвращает имя службы подключения DependateInjection, используемое для чтения данных, связанных с моделью
public function getRelated( string $alias, mixed $arguments = null ): Phalcon\Mvc\Model\Resultset\Simple | null
Возвращает связанные записи, основанные на определенных уравнениях. Если отношение "один к одному" и записи не найдены, возвращается значение null
ПРИМЕЧАНИЕ:
getRelated()
больше не возвращает значениеfalse
, если запись не найдена в связи "один к одному".
<?php use MyApp\Models\Customers; $customer = Customers::findFirst('cst_id = 1'); $invoices = $customer->getRelated('invoices');
public function isRelationshipLoaded( string $relationshipAlias ): bool
Проверяет, были ли уже загружены сохраненные связанные записи. Возвращает значение true
только в том случае, если записи были ранее извлечены из модели без каких-либо дополнительных параметров.
<?php use MyApp\Models\Customers; $customer = Customers::findFirst('cst_id = 1'); $invoices = $customer->isRelationshipLoaded('invoices'); // false $invoices = $customer->getRelated('invoices'); $invoices = $customer->isRelationshipLoaded('invoices'); // true
final public function getSchema(): string
Возвращает имя схемы, в которой находится сопоставленная таблица
public function getSnapshotData(): array
Возвращает внутренние данные моментального снимка
final public function getSource(): string
Возвращает имя таблицы, сопоставленной в модели
public function getUpdatedFields(): array
Возвращает список обновленных значений.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst(); print_r( $invoice->getChangedFields() ); // [] $invoice->inv_total = 120;; $invoice->getChangedFields(); print_r( $invoice->getChangedFields() ); // ['inv_total'] $invoice->save(); print_r( $invoice->getChangedFields() ); // [] print_r( $invoice->getUpdatedFields() ); // ['inv_total']
final public function getWriteConnection(): AdapterInterface
Получение соединения, используемого для записи данных в модель
final public function getWriteConnectionService(): string
Возвращает имя службы подключения DependateInjection, используемое для записи данных, связанных с моделью
public function hasChanged( string | array $fieldName = null, bool $allFields = false ): bool
Проверьте, изменился ли конкретный атрибут. Это работает только в том случае, если модель сохраняет снимки данных
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->create(); $invoice->inv_total = 120; $hasChanged = $invoice->hasChanged('inv_title'); // false $hasChanged = $invoice->hasChanged( [ 'inv_total', ] ); // true $hasChanged = $invoice->hasChanged( [ 'inv_title', 'inv_total' ], true ); // false
public function hasSnapshotData(): bool
Проверка наличия у объекта внутренних данных моментального снимка
public function hasUpdated( string | array $fieldName = null, bool $allFields = false ): bool
Проверьте, был ли обновлен определенный атрибут. Это работает только в том случае, если модель сохраняет снимки данных.
public function jsonSerialize(): array
Сериализация объекта для json_encode
echo json_encode($invoice);
public static function maximum( mixed $parameters = null ): mixed
Возвращает максимальное значение столбца для результирующего набора строк, соответствующих указанным условиям
<?php use MyApp\Models\Invoices; $id = Invoices::maximum( [ 'column' => 'inv_id', ] ); echo 'MAX: ', $id, PHP_EOL; $max = Invoices::maximum( [ 'inv_cst_id = 1', 'column' => 'inv_total', ] ); echo 'MAX [Customer: 1] ', $max, PHP_EOL;
public static function minimum( mixed parameters = null ): mixed
Возвращает минимальное значение столбца для результирующего набора строк, соответствующих указанным условиям
<?php use MyApp\Models\Invoices; $id = Invoices::minimum( [ 'column' => 'inv_id', ] ); echo 'MIN: ', $id, PHP_EOL; $max = Invoices::minimum( [ 'inv_cst_id = 1', 'column' => 'inv_total', ] ); echo 'MIN [Customer: 1] ', $max, PHP_EOL;
public static function query( DiInterface $container = null ): CriteriaInterface
Создание критериев для конкретной модели
public function readAttribute( string $attribute ): mixed | null
Считывает значение атрибута по его имени
echo $invoice->readAttribute('inv_title');
public function refresh(): ModelInterface
Обновление атрибутов модели, повторно запрашивающих запись из базы данных
public function save(): bool
Вставка или обновление экземпляра модели. Возвращает true
при успехе или false
в противном случае.
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->save(); $invoice = Invoices::findFirst('inv_id = 100'); $invoice->inv_total = 120; $invoice->save();
ПРИМЕЧАНИЕ:
save()
больше не принимает параметры для установки данных. Вместо этого можно использоватьassign
.
public function serialize(): string
Сериализует объект, игнорируя соединения, службы, связанные объекты или статические свойства
public function unserialize(mixed $data)
Несериализует объект из сериализованной строки
final public function setConnectionService( string $connectionService ): void
Задает имя службы подключения DependateInjection
public function setDirtyState( int $dirtyState ): ModelInterface | bool
Устанавливает грязное состояние объекта с помощью одной из констант DIRTY_STATE_*
public function setEventsManager( EventsManagerInterface $eventsManager )
Задает имя службы подключения DependateInjection, используемое для чтения данных
public function setOldSnapshotData( array $data, array $columnMap = null )
Устанавливает старые данные моментального снимка записи. Этот метод используется внутри для настройки старых данных моментального снимка, когда модель была настроена на сохранение данных моментального снимка
public function setSnapshotData( array $data, array $columnMap = null ): void
Устанавливает данные моментального снимка записи. Этот метод используется внутри для настройки данных моментального снимка, когда модель была настроена на сохранение данных моментального снимка
public function setTransaction( TransactionInterface $transaction ): ModelInterface
Задает транзакцию, связанную с экземпляром модели
<?php use MyApp\Models\Customers; use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Transaction\Manager; use Phalcon\Mvc\Model\Transaction\Failed; try { $txManager = new Manager(); $transaction = $txManager->get(); $customer = new Customers(); $customer->setTransaction($transaction); $customer->cst_name_last = 'Vader'; $customer->cst_name_first = 'Darth'; if (false === $customer->save()) { $transaction->rollback('Cannot save Customer'); } $invoice = new Invoices(); $invoice->setTransaction($transaction); $invoice->inv_cst_id = $customer->cst_id; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; if (false === $invoice->save()) { $transaction->rollback('Cannot save record'); } $transaction->commit(); } catch (Failed $ex) { echo 'ERROR: ', $ex->getMessage(); }
public static function setup( array $options ): void
Включает/отключает параметры в ORM, такие как события, переименование столбцов и т.д.
final public function setWriteConnectionService( string $connectionService ): void
Задает имя службы подключения DependateInjection, используемое для записи данных
public function skipOperation(bool $skip): void ```php Skips the current operation forcing a success state ```php public static function sum( array $parameters = null ): float
Вычисляет сумму по столбцу для результирующего набора строк, соответствующих указанным условиям
<?php use MyApp\Models\Invoices; $total = Invoices::sum( [ 'column' => 'inv_total', ] ); echo 'SUM: ', $total, PHP_EOL; $total = Invoices::sum( [ 'inv_cst_id = 1', 'column' => 'inv_total', ] ); echo 'SUM [Customer: 1] ', $total, PHP_EOL;
public function toArray( array $columns = null ): array
Возвращает экземпляр в виде представления массива. Принимает массив с именами столбцов для включения в результат
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('inv_id = 4'); print_r( $invoice->toArray() ); // [ // 'inv_id' => 4, // 'inv_cst_id' = $customer->cst_id, // 'inv_status_flag' = 1, // 'inv_title' = 'Invoice for ACME Inc.', // 'inv_total' = 100, // 'inv_created_at' = '2019-12-25 01:02:03', // ] print_r( $invoice->toArray( [ 'inv_status_flag', 'inv_title', 'inv_total', ] ) ); // [ // 'inv_status_flag' = 1, // 'inv_title' = 'Invoice for ACME Inc.', // 'inv_total' = 100, // ]
public function update(): bool
Обновление экземпляра модели. Если экземпляр не существует в сохраняемости, будет создано исключение. Возврат true при успехе или false
в противном случае.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('inv_id = 4'); $invoice->inv_total = 120; $invoice->update();
public function writeAttribute( string $attribute, mixed $value ): void
Записывает значение атрибута по его имени
$invoice->writeAttribute('inv_total', 120);
protected function allowEmptyStringValues( array $attributes ): void
Задает список атрибутов, которые должны быть пропущены из созданной инструкции UPDATE
<?php use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->allowEmptyStringValues( [ 'inv_created_at', ] ); } }
protected function belongsTo( string | array $fields, string $referenceModel, string | array $referencedFields, array options = null ): Relation
Настройка обратного отношения 1-1 или n-1 между двумя моделями
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class InvoicesXProducts extends Model { public function initialize() { $this->belongsTo( 'ixp_inv_id', Invoices::class, 'inv_id' ); } }
protected function hasMany( string | array $fields, string $referenceModel, string | array $referencedFields, array options = null ): Relation
Настройка отношения 1-n между двумя моделями
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Customers extends Model { public function initialize() { $this->hasMany( 'cst_id', Invoices::class, 'inv_cst_id' ); } }
protected function hasManyToMany( string | array $fields, string $intermediateModel, string | array $intermediateFields, string | array $intermediateReferencedFields, string $referenceModel, string | array $referencedFields, array $options = null ): Relation
Настройка отношения n-n между двумя моделями через промежуточное отношение
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->hasManyToMany( 'inv_id', InvoicesXProducts::class, 'ixp_inv_id', 'ixp_prd_id', Products::class, 'prd_id' ); } }
protected function hasOne( string | array $fields, string $referenceModel, string | array $referencedFields, array options = null ): Relation
Настройка отношения 1-1 между двумя моделями
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->hasOne( 'inv_cst_id', Customers::class, 'cst_id' ); } }
protected function keepSnapshots( bool $keepSnapshot ): void
Устанавливает, должна ли модель сохранять исходный снимок записи в памяти
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->keepSnapshots(true); } }
final protected function setSchema( string $schema ): ModelInterface
Задает имя схемы, в которой находится сопоставленная таблица
final protected function setSource( string $source ): ModelInterface
Задает имя таблицы, с которой должна быть сопоставлена модель
protected function skipAttributes(array $attributes)
Задает список атрибутов, которые должны быть пропущены из созданной инструкции INSERT
/UPDATE
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->skipAttributes( [ 'inv_created_at', ] ); } }
protected function skipAttributesOnCreate( array $attributes ): void
Задает список атрибутов, которые должны быть пропущены из созданной инструкции INSERT
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->skipAttributesOnCreate( [ 'inv_created_at', ] ); } }
protected function skipAttributesOnUpdate( array $attributes ): void
Задает список атрибутов, которые должны быть пропущены из созданной инструкции UPDATE
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->skipAttributesOnUpdate( [ 'inv_modified_at', ] ); } }
protected function useDynamicUpdate( bool dynamicUpdate ): void
Задает, должна ли модель использовать динамическое обновление вместо обновления всех полей
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->useDynamicUpdate(true); } }
protected function validate( ValidationInterface $validator ): bool
Выполняет средства проверки при каждом вызове проверки
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; use Phalcon\Validation; use Phalcon\Validation\Validator\ExclusionIn; class Invoices extends Model { public function validation() { $validator = new Validation(); $validator->add( 'inv_status_flag', new ExclusionIn( [ 'domain' => [ 0, 1, ], ] ) ); return $this->validate($validator); } }
public function validationHasFailed(): bool
Проверка того, что процесс проверки создал какие-либо сообщения
Создание моделей
Модель-это класс, который расширяется от Phalcon\Mvc\Model. Его имя класса должно быть в случае верблюда нотация:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { }
По умолчанию модель MyApp\Models\Invoices
будет сопоставлена с таблицей invoices
. Если вы хотите вручную указать другое имя для сопоставленной таблицы, вы можете использовать методsetSource()
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->setSource('co_invoices'); } }
Теперь модель Invoices
сопоставлена с таблицей co_invoices
. Метод initialize()
помогает настроить эту модель с помощью пользовательского поведения, т.е. другой таблицы.
Метод initialize()
вызывается только один раз во время запроса. Этот метод предназначен для выполнения инициализации, которая применяется ко всем экземплярам модели, созданной в приложении. Если требуется выполнить задачи инициализации для каждого созданного экземпляра, можно использовать метод onConstruct()
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function onConstruct() { // ... } }
Свойства против сеттеров/геттеров
Модели могут быть реализованы с открытыми свойствами, что означает, что каждое свойство может быть прочитано и обновлено обновлено из любой части кода, которая создала экземпляр этого класса модели:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_id; public $inv_cst_id; public $inv_status_flag; public $inv_title; public $inv_total; public $inv_created_at; }
Другая реализация заключается в использовании функций getter и setter, которые управляют тем, какие свойства являются общедоступными для этой модели.
Преимущество использования геттеров и сеттеров заключается в том, что разработчик может выполнять преобразования и проверки достоверности значений, заданных или извлеченных для модели, что невозможно при использовании общих свойств.
Кроме того, геттеры и сеттеры позволяют вносить будущие изменения без изменения интерфейса класса модели. Таким образом, если имя поля изменяется, единственное необходимое изменение будет в частной собственности модели, на которую ссылается соответствующий геттер/сеттер, и нигде больше в коде.
<?php namespace MyApp\Models; use InvalidArgumentException; use Phalcon\Mvc\Model; class Invoices extends Model { private $inv_id; private $inv_cst_id; private $inv_status_flag; private $inv_title; private $inv_total; private $inv_created_at; public function getId(): int { return (int) $this->inv_id; } public function getCustomerId(): int { return (int) $this->inv_cst_id; } public function getStatus(): int { return (int) $this->inv_status_flag; } public function getTitle(): string { return (string) $this->inv_title; } public function getTotal(): float { return (float) $this->inv_total; } public function getCreatedAt(): string { return (string) $this->inv_created_at; } public function setCustomerId(int $customerId): Invoices { $this->inv_cst_id = $customerId; return $this; } public function setStatus(int $status): Invoices { $this->inv_status_flag = $status; return $this; } public function setTitle(string $title): Invoices { $this->inv_title = $title; return $this; } public function setTotal(float $total): Invoices { if ($total < 0) { throw new InvalidArgumentException( 'Incorrect total' ); } $this->inv_total = $total; return $this; } public function setCreatedAt(string $date): Invoices { $this->inv_created_at = $date; return $this; } }
Публичные свойства обеспечивают меньшую сложность в разработке. Однако геттеры / сеттеры могут значительно повысить тестируемость, расширяемость и ремонтопригодность приложений. Вам нужно будет решить, какая стратегия лучше для вас в зависимости от потребностей приложения. ORM совместим с обеими схемами определения свойств.
ПРИМЕЧАНИЕ: подчеркивания в именах свойств могут быть проблематичными при использовании геттеров и сеттеров.
Если вы используете подчеркивания в именах свойств, вы все равно должны использовать Camel case в объявлениях getter/setter для использования с магическими методами. (например, $model->getPropertyName
вместо $model->getProperty_name
, $model->findByPropertyName
вместо $model->findByProperty_name
, и т. д.).
ОРМ ожидает регистр имен и знаков подчеркивания, как правило, удалены. Поэтому рекомендуется называть свойства так, как показано в документации. Вы можете использовать карту столбцов (как описано выше), чтобы обеспечить правильное сопоставление ваших свойств с их аналогами в базе данных.
Записи В Объекты
Каждый экземпляр модели представляет собой строку в таблице. Вы можете легко получить доступ к записанным данным, прочитав свойства объекта. Например, для таблицы ' co_customers’ с записями:
mysql> select * from co_customers; +--------+---------------+----------------+ | cst_id | cst_name_last | cst_name_first | +--------+---------------+----------------+ | 1 | Vader | Darth | | 2 | Skywalker | Like | | 3 | Skywalker | Leia | +--------+---------------+----------------+ 3 rows in set (0.00 sec)
Вы можете найти определенную запись по ее первичному ключу и затем распечатать ее имя:
<?php use MyApp\Models\Customers; // cst_id = 3 $customer = Customers::findFirst(3); // 'Leia' echo $customer->cst_name_first;
После того, как запись находится в памяти, вы можете внести изменения в ее данные, а затем Сохранить изменения:
<?php use MyApp\Models\Customers; // cst_id = 3 $customer = Customers::findFirst(3); $customer->cst_name_last = 'Princess'; $customer->save();
Как вы можете видеть, нет необходимости использовать необработанные инструкции SQL. Phalcon\Mvc\Model обеспечивает высокую абстракцию баз данных для веб-приложений, упрощая операции с базами данных.
Поиск Записей
Phalcon\Mvc\Model также предлагает несколько методов для запроса записей.
find
Метод возвращает набор записей Phalcon\Mvc\Model\Resultset, Phalcon\Mvc\Model\Resultset\Complex или Phalcon\Mvc\Model\Resultset\Simple , даже если возвращаемый результат является только одной записью.
Метод принимает различные параметры для извлечения данных:
<?php use MyApp\Models\Customers; $invoice = Invoices::findFirst('inv_id = 3');
Вы также можете передать строку с предложением WHERE
. В приведенном выше примере мы получаем одну и ту же запись, поручив ОРМ, чтобы дать нам записать с inv_cst_id = 3
Наиболее гибкий синтаксис заключается в передаче массива с различными параметрами:
<?php use MyApp\Models\Customers; $invoice = Invoices::findFirst( [ 'inv_id = 3', ] );
Первый параметр массива (без ключа) обрабатывается так же, как и приведенный выше пример (передача строки). Массив принимает дополнительные параметры, которые предлагают дополнительные опции для настройки операции поиска.
findFirst
Вы также можете использовать метод findFirst()
, чтобы получить только первую запись, соответствующую заданным критериям:
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst();
Вызов findFirst
без параметра вернет первую запись, которую найдет ORM. Обычно это первая запись в таблице.
<?php use MyApp\Models\Invoices; // cst_id = 3 $invoice = Invoices::findFirst(3);
Передавая число, будет запрашивать базовую модель, используя первичный ключ, соответствующий переданному параметру number. Если первичный ключ не определен или есть составной ключ, вы не получите никаких результатов.
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('inv_id = 3');
Вы также можете передать строку с предложением WHERE
. В приведенном выше примере мы получаем одну и ту же запись, поручив ОРМ, чтобы дать нам записать с inv_cst_id = 3
Примечание: если первичный ключ таблицы не числовой, используйте условие. Смотрите примеры ниже.
$uuid = '5741bfd7-6870-40b7-adf6-cbacb515b9a9'; $invoice = Invoices::findFirst([ 'uuid = ?0', 'bind' => [$uuid], ]); // OR $uuid = '5741bfd7-6870-40b7-adf6-cbacb515b9a9'; $invoice = Invoices::findFirst([ 'uuid = :primary:', 'bind' => ['primary' => $uuid], ]);
ПРИМЕЧАНИЕ: Если в ваших условиях не используются связанные параметры, PHQL создает новый план внутри компании, поэтому потребляет больше памяти. Рекомендуется использовать привязанные параметры!
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('uuid = "5741bfd7-6870-40b7-adf6-cbacb515b9a9"');
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst('uuid = "5741bfd7-6870-40b7-adf6-cbacb515b9a9"');
Параметры
ПРИМЕЧАНИЕ: настоятельно рекомендуется использовать синтаксис массива с условиями и привязкой, чтобы защитить себя от SQL-инъекций, особенно когда критерий исходит из пользовательского ввода. Дополнительную информацию смотрите в разделе Параметры привязки.
Оба метода find()
и findFirst()
принимают ассоциативный массив, задающий критерии поиска.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'inv_cst_id = 3', 'order' => 'inv_total desc' ] );
Вы можете (и должны) использовать элементы массива conditions
и bind
, которые связывают параметры с параметрами запроса. Использование этой реализации гарантирует, что ваши параметры привязаны и, таким образом, уменьшает возможность SQL-инъекций:
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'order' => 'inv_total desc', ] );
Доступные параметры запроса::
bind
BIND
используется вместе с conditions
, заменяя заполнители и экранируя значения, таким образом повышая безопасность
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst( [ 'conditions' => 'inv_id = :inv_id:', 'bind' => [ 'inv_id' => 3, ], ] );
bindTypes
При привязке параметров этот параметр можно использовать для определения дополнительного приведения к связанным параметрам, что еще больше повышает безопасность запроса.
<?php use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Column; $invoice = Invoices::findFirst( [ 'conditions' => 'inv_id = :inv_id:', 'bind' => [ 'inv_id' => 3, ], 'bindTypes' => [ Column::BIND_PARAM_INT, ], ] );
cache
Кэширование результирующего набора, уменьшая непрерывный доступ к реляционной системе.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'cache' => [ 'key' => 'customer.3', 'lifetime' => 84600, ], 'order' => 'inv_total desc', ] );
columns
Возвращает определенные столбцы в модели.
ПРИМЕЧАНИЕ: При использовании этого параметра возвращается неполный объект, поэтому нельзя вызывать такие методы, как
update()
,getRelated()
и т.д.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'columns' => [ 'inv_id', 'total' => 'inv_total' ], 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], ] );
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'columns' => [ 'inv_id', 'total' => 'inv_total' ], 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], ] );
Массив столбцов может возвращать столбцы непосредственно, если для одного из элементов массива задано только значение. Однако если указать ключ, он будет использоваться в качестве псевдонима для этого поля. В вышеприведенном примере cst_name_first
называется first
.
conditions
Условия поиска для операции поиска. Используется для извлечения только тех записей, которые соответствуют указанному критерию. По умолчанию Phalcon\Mvc\Model предполагает, что первым параметром являются условия.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], ] );
for_update
С помощью этого параметра Phalcon\Mvc\Model считывает последние доступные данные, устанавливая монопольные блокировки для каждой считываемой строки
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'for_update' => true, ] );
group
Позволяет собирать данные по нескольким записям и группировать результаты по одному или нескольким столбцам 'group' => 'name, status'
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'group' => 'inv_status_flag', ] );
hydration
Задает стратегию гидратации для представления каждой возвращенной записи в результате
<?php use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Resultset; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'hydration' => Resultset::HYDRATE_OBJECTS, ] );
limit
Ограничить результаты запроса определенным диапазоном
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'limit' => 10, ] );
offset
Смещение результатов запроса на определенную сумму
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'limit' => 10, 'offset' => 100, ] );
order
Используется для сортировки результирующего набора. Используйте одно или несколько полей, разделенных запятыми.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'order' => 'inv_status_flag, inv_total desc', ] );
shared_lock
С помощью этого параметра Phalcon\Mvc\Model считывает последние доступные данные, устанавливая общие блокировки для каждой считываемой строки
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], 'shared_lock' => true, ] );
query
При желании также доступен способ создания запросов объектно-ориентированным способом, вместо использования массива параметров:
<?php use MyApp\Models\Invoices; $invoices = Invoices::query() ->where('inv_cst_id = :cst_id:') ->andWhere('inv_total > :total:') ->bind( [ 'cst_id' => 3, 'total' => 1000, ] ) ->orderBy('inv_status_flag, inv_total desc') ->execute() ;
Статический метод query()
возвращает объект Phalcon\Mvc\Model\Criteria, дружественный к IDE auto complete.
Все запросы внутренне обрабатываются как запросы PHQL. PHQL-это высокоуровневый, объектно-ориентированный и SQL-подобный язык. Этот язык предлагает больше возможностей для выполнения запросов, таких как объединение других моделей, групповые записи, агрегации и т. д.
findBy*
Можно использовать метод findBy<property-name>()
. Этот метод расширяется на вышеупомянутом методе find()
. Он позволяет быстро выполнить выбор записей из таблицы, используя имя свойства в самом методе и передавая ему параметр, содержащий данные, которые нужно искать в этом столбце.
Для следующей модели:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_cst_id; public $inv_id; public $inv_status_flag; public $inv_title; public $inv_created_at; }
У нас есть свойства inv_cst_id
, inv_id
, inv_status_flag
, inv_title
, inv_created_at
. Если мы хотим найти все счета с inv_total = 100
, мы можем использовать:
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_total = :total:', 'bind' => [ 'total' => 100, ], ] );
но мы также можем использовать:
<?php use MyApp\Models\Invoices; $invoices = Invoices::findByInvTotal(100);
ПРИМЕЧАНИЕ: имена свойств изменяются на camel case, если они имеют подчеркивания.
inv_total
становитсяInvTotal
Вы также можете передавать параметры в массиве в качестве второго параметра. Эти параметры совпадают с теми, которые вы можете передать в методе find
.
<?php use MyApp\Models\Invoices; $invoices = Invoices::findByInvTotal( 100, [ 'order' => `inv_cst_id, inv_created_at` ] );
findFirstBy*
Наконец, можно использовать метод findFirstBy<property-name>()
. Этот метод расширяется на вышеупомянутом методе findFirst()
. Он позволяет быстро выполнить выбор из таблицы, используя имя свойства в самом методе и передавая ему параметр, содержащий данные, которые нужно искать в этом столбце.
Для следующей модели:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Guestbook extends Model { public $id; public $email; public $name; public $text; }
У нас есть свойства id
, email
, name
и text
. Если мы хотим найти запись гостевой книги для Darth Vader
, мы можем:
<?php use MyApp\Models\Guestbook; $guest = Guestbook::findFirst( [ 'conditions' => 'name = :name:', 'bind' => [ 'name' => 'Darth Vader', ], ] );
Но мы также можем использовать:
<?php use MyApp\Models\Guestbook; $name = 'Darth Vader'; $guest = Guestbook::findFirstByName($name);
ПРИМЕЧАНИЕ: Обратите внимание, что мы использовали
Name
в вызове метода и передали ему переменную$name
содержащую имя, которое мы ищем в нашей таблице. Обратите внимание, что при поиске соответствия с нашим запросом все остальные свойства также доступны нам.
Модель Результирующих Наборов
В то время как findFirst()
возвращает непосредственно экземпляр вызываемого класса (когда есть данные, которые должны быть возвращены), метод find()
возвращает Phalcon\Mvc\Model\Resultset\Simple. Это объект, который инкапсулирует все функциональные возможности результирующего набора, такие как поиск, обход, подсчет и т. д.
Эти объекты более мощные, чем стандартные массивы. Одна из самых больших особенностей Phalcon\Mvc\Model\Resultset заключается в том, что в любой момент времени в памяти остается только одна запись. Это очень помогает в управлении памятью, особенно при работе с большими объемами данных.
Некоторые примеры обхода результирующих наборов:
<?php use MyApp\Models\Invoices; $invoices = Invoices::find(); // инструкция foreach foreach ($invoices as $invoice) { echo $invoice->inv_title, PHP_EOL; } // пока $invoices->rewind(); while ($invoices->valid()) { $invoice = $invoices->current(); echo $invoice->inv_title, PHP_EOL; $invoices->next(); } // считать echo count($invoices); echo $invoices->count(); // искать $invoices->seek(2); $invoice = $invoices->current(); // массив $invoice = $invoices[5]; // array - isset if (true === isset($invoices[3])) { $invoice = $invoices[3]; } // Первый $invoice = $invoices->getFirst(); // Последний $invoice = $invoices->getLast();
Результирующие наборы Phalcon эмулируют прокручиваемые курсоры. Вы можете получить любую строку, просто обратившись к ее позиции или отыскав внутренний указатель на определенную позицию.
ПРИМЕЧАНИЕ: некоторые системы баз данных не поддерживают прокручиваемые курсоры. Это заставляет Phalcon повторно выполнить запрос, чтобы перемотать курсор в начало и получить запись в требуемой позиции. Аналогично, если результирующий набор был пройден несколько раз, запрос должен быть выполнен столько же раз.
Сохранение больших результатов запросов в памяти потребит много ресурсов. Однако можно указать Phalcon извлекать данные в порциях строк, тем самым уменьшая необходимость повторного выполнения запроса во многих случаях. Для этого можно задать значение настройки orm.resultset_prefetch_records
. Это можно сделать либо в php.ini
или в методе модели setup()
. Более подробную информацию об этом можно найти в разделе функции.
Обратите внимание, что результирующие наборы могут быть сериализованы и сохранены в бэкэнде кэша. Phalcon\Cache может помочь с этой задачей. Однако сериализация данных приводит к тому, что Phalcon\Mvc\Model извлекает все данные из базы данных в массиве, что потребляет больше памяти во время этого процесса.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find(); file_put_contents( 'invoices.cache', serialize($invoices) ); $invoices = unserialize( file_get_contents('invoices.cache') ); foreach ($invoices as $invoice) { echo $invoice->inv_title; }
Пользовательские Результирующие Наборы
Иногда логика приложения требует дополнительных манипуляций с данными, полученными из базы данных. Ранее мы просто расширяли модель и инкапсулировали функциональность в классе в модели или черте, возвращая вызывающему объекту обычно массив преобразованных данных.
При использовании пользовательских наборов результатов это больше не требуется. Пользовательский результирующий набор инкапсулирует функциональные возможности, которые в противном случае были бы в модели, и может быть повторно использован другими моделями, таким образом сохраняя код DRY. Таким образом, метод find()
больше не возвращает значение по умолчанию Phalcon\Mvc\Model\Resultset, а настраивается. Phalcon позволяет сделать это с помощью getResultsetClass()
в модели.
Сначала необходимо определить класс результирующего набора:
<?php namespace MyApp\Mvc\Model\Resultset; use \Phalcon\Mvc\Model\Resultset\Simple; class Custom extends Simple { public function calculate() { // .... } }
В модели мы задаем класс в getResultsetClass()
следующим образом:
<?php namespace Phalcon\Test\Models\Statistics; use MyApp\Mvc\Model\Resultset\Custom; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->setSource('co_invoices'); } public function getResultsetClass() { return Custom::class; } }
и, наконец, в вашем коде будет что-то вроде этого:
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id = :cst_id:', 'bind' => [ 'cst_id' => 3, ], ] ); $calculated = $invoices->calculate();
Фильтрация Результирующих Наборов
Наиболее эффективным способом фильтрации данных является установка некоторых критериев поиска, базы данных будут использовать индексы, установленные на таблицах, чтобы быстрее возвращать данные. Phalcon дополнительно позволяет фильтровать данные с помощью PHP:
<?php $invoices = Invoices::find(); $invoices = $invoices->filter( function ($invoice) { if (1 === $invoice->inv_status_flag) { return $invoice; } } );
Приведенный выше пример возвращает только оплаченные счета из нашей таблицы (inv_status_flag = 1
);
Обязательные Параметры
вязанные параметры также поддерживаются в Phalcon\Mvc\Model. Рекомендуется использовать эту методологию, чтобы исключить возможность того, что ваш код будет подвержен атакам SQL-инъекций. Поддерживаются как строковые, так и целочисленные заполнители.
Примечание:при использовании целочисленных заполнителей вы должны префиксировать их
?
(?0
,?1
). При использовании заполнителей строк необходимо заключить строку в:
(:name:
,:total:
).
Примеры:
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( [ 'conditions' => 'inv_title LIKE :title: AND ' . 'inv_total > :total:', 'bind' => [ 'title' => '%ACME%', 'total' => 1000, ], ] ); $invoices = Invoices::find( [ 'conditions' => 'inv_title LIKE ?0 = ?0 AND ' . 'inv_total > ?1', 'bind' => [ 0 => '%ACME%', 1 => 1000, ], ] ); $invoices = Invoices::find( [ 'conditions' => 'inv_title = ?0 AND ' . 'inv_total > :total:', 'bind' => [ 0 => '%ACME%', 'total' => 1000, ], ] );
троки автоматически экранируются с помощью PDO. Эта функция учитывает кодировку соединения, поэтому рекомендуется определить правильную кодировку в параметрах соединения или в конфигурации базы данных, так как неправильная кодировка будет производить нежелательные эффекты при хранении или извлечении данных.
Кроме того, вы можете задать параметры bindTypes
, что позволяет определить, как параметры должны быть привязаны в соответствии с их типом данных:
<?php use MyApp\Models\Invoices; use Phalcon\Db\Column; $parameters = [ 'title' => '%ACME%', 'total' => 1000, ]; $types = [ 'title' => Column::BIND_PARAM_STR, 'total' => Column::BIND_PARAM_INT, ]; $invoices = Invoices::find( [ 'conditions' => 'inv_title LIKE :title: AND ' . 'inv_total > :total:', 'bind' => $parameters, 'bindTypes' => $types, ] );
ПРИМЕЧАНИЕ: Поскольку типом привязки по умолчанию является
Phalcon\Db\Column::BIND_PARAM_STR
, нет необходимости указывать параметр bindTypes, если все столбцы являются строками
Можно также связать массивы в параметрах, особенно при использовании ключевого слова IN
SQL.
ПРИМЕЧАНИЕ: Вы должны использовать нулевой массив для массивов без пропущенных элементов
<?php use MyApp\Models\Invoices; $customerIds = [1, 3, 4]; // $array: [[0] => 1, [1] => 2, [2] => 4] $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id IN ({customerId:array})', 'bind' => [ 'customerId' => $customerIds, ], ] ); unset($customerIds[1]); // $array: [[0] => 1, [2] => 4] $customerIds = array_values($customerIds); // $array: [[0] => 1, [1] => 4] $invoices = Invoices::find( [ 'conditions' => 'inv_cst_id IN ({customerId:array})', 'bind' => [ 'customerId' => $customerIds, ], ] );
Примечание: Связанные параметры доступны для всех методов запроса, таких как
find()
иfindFirst()
, а также для таких методов вычисления, какcount()
,sum()
,average()
и т.д.
Если вы используете finders , например find()
, findFirst()
, и т. д., вы можете ввести связанные параметры при использовании синтаксиса строки для первого параметра вместо использования элемента массива условий conditions
. Также при использовании findFirstBy*
параметры привязываются автоматически.
<?php use MyApp\Models\Invoices; $invoices = Invoices::find( 'inv_total > ?0', 'bind' => [ 1000, ] ); $invoices = Invoices::findByInvTotal(1000);
До/После Извлечения
Есть случаи, когда нам нужно манипулировать данными после того, как они были извлечены из базы данных, чтобы наша модель содержала то, что нам нужно на прикладном уровне. Как видно из документа события, модели действуют как слушатели, поэтому мы можем реализовать некоторые события в качестве методов в модели.
Такие методы включают в себя beforeSave
, afterSave
и afterFetch
, как показано в нашем примере ниже. Метод afterFetch
будет выполняться сразу после заполнения модели данными из базы данных. Мы можем использовать этот метод для изменения или преобразования данных в модели.
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_id; public $inv_cst_id; public $inv_status_flag; public $inv_total; public $status; public function beforeSave() { $this->status = join(',', $this->status); } public function afterFetch() { $this->status = explode(',', $this->status); } public function afterSave() { $this->status = explode(',', $this->status); } }
In the example above, we get a comma-separated string from the database and explode it to an array so that it can be used from our application. After that, you can add or remove elements in the array; before the model saves it, implode will be called to store the array as a string in the database.
Если вы используете getters / setters вместо / или вместе с public properties, вы можете инициализировать поле, как только оно будет доступно:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_id; public $inv_cst_id; public $inv_status_flag; public $inv_total; public $status; public function getStatus() { return explode(',', $this->status); } }
Вычисления
Вычисления (или агрегации) являются помощниками для часто используемых функций систем базы данных, таких как COUNT
, SUM
, MAX
, MIN
или AVG
. Phalcon\Mvc\Model позволяет использовать эти функции непосредственно из открытых методов.
COUNT
<?php $rowcount = Invoices::count(); // inv_cst_id = 3 $rowcount = Invoices::count( [ 'inv_cst_id = ?0', 'bind' => [ 3, ], ] );
Для группирования результатов также можно использовать параметр group
. Результаты подсчета отображаются в свойстве rowcount
каждого объекта в возвращенной коллекции.
<?php $group = Invoices::count( [ 'group' => 'inv_cst_id', ] ); foreach ($group as $row) { echo 'Count: ', $row->rowcount, ' - Customer: ', $row->inv_cst_id; } $group = Invoices::count( [ 'group' => 'inv_cst_id', 'order' => 'rowcount', ] );
SUM
<?php $total = Invoices::sum( [ 'column' => 'inv_total', ] ); $total = Invoices::sum( [ 'column' => 'total', 'conditions' => 'inv_cst_id = ?0', 'bind' => [ 3 ] ] );
Можно также сгруппировать результаты. Результаты подсчета отображаются в свойстве sumatory
каждого объекта в возвращенной коллекции.
<?php $group = Invoices::sum( [ 'column' => 'inv_total', 'group' => 'inv_cst_id', ] ); foreach ($group as $row) { echo 'Customer: ', $row->inv_cst_id, ' - Total: ', $row->sumatory; } $group = Invoices::sum( [ 'column' => 'inv_total', 'group' => 'inv_cst_id', 'order' => 'sumatory DESC', ] );
AVERAGE
<?php $average = Invoices::average( [ 'column' => 'inv_total', ] ); $average = Invoices::average( [ 'column' => 'inv_total', 'conditions' => 'inv_status_flag = ?0', 'bind' => [ 0 ] ] );
MAX
- MIN
<?php $max = Invoices::maximum( [ 'column' => 'inv_total', ] ); $max = Invoices::maximum( [ 'column' => 'inv_total', 'conditions' => 'inv_status_flag = ?0', 'bind' => [ 0 ], ] ); $min = Invoices::minimum( [ 'column' => 'inv_total', ] ); $min = Invoices::minimum( [ 'column' => 'inv_total', 'conditions' => 'inv_status_flag = ?0', 'bind' => [ 0 ], ] );
Создание-Обновление
Метод Phalcon\Mvc\Model::save()
позволяет создавать / обновлять записи в соответствии с тем, существуют ли они уже в таблице, связанной с моделью. Метод save вызывается внутренне методами create и update из Phalcon\Mvc\Model. Чтобы это работало должным образом, необходимо правильно определить первичный ключ в сущности, чтобы определить, следует ли создавать или обновлять запись.
Метод также выполняет связанные валидаторы, виртуальные внешние ключи и события, определенные в модели:
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->save(); if (false === $result) { echo 'Error saving Invoice: '; $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Saved'; }
Вы также можете использовать метод assign()
и передать массив элементов field => value
, чтобы избежать назначения каждого столбца вручную. Phalcon\Mvc\Model будет проверять, есть ли задатчики, реализованные для столбцов, передаваемых в массив, отдавая им приоритет, вместо того, чтобы назначать непосредственно значения атрибутов:
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->assign( [ 'inv_cst_id' => 1, 'inv_status_flag' => 1, 'inv_title' => 'Invoice for ACME Inc.', 'inv_total' => 100, 'inv_created_at' => '2019-12-25 01:02:03', ] ); $result = $invoice->save();
Значения, присвоенные непосредственно или через массив атрибутов, экранируются / очищаются в соответствии с типом данных соответствующего атрибута. Таким образом, вы можете передать небезопасный массив, не беспокоясь о возможных SQL-инъекциях:
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->assign($_POST); $result = $invoice->save();
ПРИМЕЧАНИЕ: Без мер предосторожности массовое назначение может позволить злоумышленникам установить значение любого столбца базы данных. Используйте эту функцию, только если требуется разрешить пользователю вставлять/обновлять каждый столбец в модели, даже если эти поля не находятся в отправленной форме.
Вы можете установить дополнительный параметр в assign
, чтобы установить белый список полей, которые только должны учитываться при выполнении массового назначения:
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->assign( $_POST, [ 'inv_cst_id', 'inv_status_flag', 'inv_title', 'inv_total', ] ); $result = $invoice->save();
ПРИМЕЧАНИЕ: в действительно загруженных приложениях вы можете использовать
create
илиupdate
для соответствующих операций. Используя эти два метода вместоsave
, мы гарантируем, что данные будут сохранены или нет в базе данных, так как они вызывают исключения Наcreate
, если запись уже существует, и наupdate
, если запись не существует.
<?php use MyApp\Models\Invoices; $invoice = new Invoices(); $invoice->inv_id = 1234; $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $result = $invoice->update(); if (false === $result) { echo 'Error saving Invoice: '; $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Updated'; }
Методы create
и update
также принимают массив значений в качестве параметра.
Удаление
Метод delete()
позволяет удалить запись. Он возвращает логическое значение, означающее успех или неудачу
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst( [ 'conditions' => 'inv_id = :id:', 'bind' => [ 'id' => 4, ] ] ); if (false !== $invoice) { if (false === $invoice->delete()) { $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Deleted'; } }
Вы также можете удалить много записей, пройдя по результирующему набору с помощью foreach
:
<?php use MyApp\Models\Invoices; $invoice = Invoices::find( [ 'conditions' => 'inv_cst_id = :id:', 'bind' => [ 'id' => 3, ] ] ); foreach ($invoices as $invoice) { if (false === $invoice->delete()) { $messages = $invoice->getMessages(); foreach ($messages as $message) { echo $message . PHP_EOL; } } else { echo 'Record Deleted'; } }
ПРИМЕЧАНИЕ: смотрите раздел транзакции о том, как можно удалить все записи в цикле с помощью одной операции
Режимы Гидратации
Как уже упоминалось ранее, результирующие наборы - это коллекции полных объектов. Это означает, что каждый возвращаемый результат является объектом, представляющим строку в базе данных. Эти документы могут быть изменены и впоследствии сохранены для сохранения изменений в базе данных.
Однако бывают случаи, когда вам нужно будет получить данные в режиме только для чтения, например, в случае простого просмотра данных. В этих случаях полезно изменить способ возврата записей, чтобы сэкономить ресурсы и повысить производительность. Стратегия, используемая для представления этих объектов, возвращаемых в результирующем наборе, называется гидратацией hydration
.
Phalcon предлагает три способа гидратации данных:
- Массивы:
Phalcon\Mvc\Model\Resultset::HYDRATE_ARRAYS
- Объекты:
Phalcon\Mvc\Model\Resultset::HYDRATE_OBJECTS
- Записи:
Phalcon\Mvc\Model\Resultset::HYDRATE_RECORDS
Режим гидратации по умолчанию-возвращает записи (HYDRATE_RECORDS
). Мы можем легко изменить режим гидратации, чтобы получить массивы или объекты обратно. Изменение режима гидратации на что-либо другое, кроме HYDRATE_RECORDS
, вернет обратно объекты (или массивы), которые не имеют связи с базой данных, т. е. мы не сможем выполнять какие-либо операции с этими объектами, такие как save()
, create()
, delete()
и т. д.
<?php use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Resultset; $invoices = Invoices::findFirst( [ 'conditions' => 'inv_id = :id:', 'bind' => [ 'id' => 4, ] ] ); // Array $invoices->setHydrateMode( Resultset::HYDRATE_ARRAYS ); foreach ($invoices as $invoice) { echo $invoice['inv_total'], PHP_EOL; } // \stdClass $invoices->setHydrateMode( Resultset::HYDRATE_OBJECTS ); foreach ($invoices as $invoice) { echo $invoice->inv_total, PHP_EOL; } // Invoices $invoices->setHydrateMode( Resultset::HYDRATE_RECORDS ); foreach ($invoices as $invoice) { echo $invoice->inv_total, PHP_EOL; }
Режим гидратации также может быть передан в качестве параметра find
, findFirst
, findFirstBy*
и т. д.:
<?php use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Resultset; $invoices = Invoices::findFirst( [ 'hydration' => Resultset::HYDRATE_ARRAYS, 'conditions' => 'inv_id = :id:', 'bind' => [ 'id' => 4, ], ] ); foreach ($invoices as $invoice) { echo $invoice['inv_total'], PHP_EOL; }
Префиксы таблиц
Если все таблицы должны иметь определенный префикс и без задания источника во всех моделях, можно использовать Phalcon\Mvc\Model\Manager и метод setModelPrefix()
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model\Manager; use Phalcon\Mvc\Model; class Invoices extends Model { } $manager = new Manager(); $manager->setModelPrefix('co_'); $invoices = new Invoices(null, null, $manager); echo $invoices->getSource(); // возвратит co_invoices
Столбцы идентификации
Некоторые модели могут иметь столбцы идентификаторов. Эти столбцы обычно являются первичным ключом сопоставленной таблицы. Phalcon\Mvc\Model может распознать столбец идентификаторов, пропускающий его в сгенерированных инструкциях INSERT
SQL, чтобы позволить системе базы данных правильно создать новое значение для этого поля. После создания новой записи поле идентификатора всегда регистрируется со значением, сгенерированным для него в системе базы данных:
<?php $invoice->save(); echo $invoice->inv_id; // 4
Phalcon\Mvc\Model пытается распознать столбец идентификаторов из каждой таблицы. Однако в зависимости от системы базы данных эти столбцы могут быть последовательными столбцами, например, в случае PostgreSQL илиauto_increment
столбцами в случае MySQL.
PostgreSQL использует последовательности для автоматического генерирования числовых значений первичного ключа. Phalcon пытается получить сгенерированное значение из последовательности table_field_seq
, например: co_invoices_id_seq
. Если имя последовательности отличается, вы всегда можете использовать метод getSequenceName()
в модели, указывая Phalcon последовательность, которую он должен использовать для первичного ключа:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function getSequenceName() { return 'invoices_sequence_name'; } }
Пропуск Колонок
В зависимости от того, как вы реализуете бизнес-правила или правила модели в своей базе данных, некоторые поля вполне могут быть проигнорированы в операциях с базой данных. Например, если у нас есть inv_created_date
в нашей модели, мы можем поручить системе базы данных ввести в нее текущую метку времени:
CREATE TABLE co_invoices ( // ... inv_created_at datetime DEFAULT CURRENT_TIMESTAMP )
Приведенный выше код (для MySQL) предписывает СУБД назначить текущую метку времени в поле inv_created_at
при создании записи. Поэтому мы можем опустить это поле при создании записи. Точно так же мы можем игнорировать некоторые поля при обновлении записей.
Для решения этой задачи мы можем использовать skipAttributes
(для любой операции), skipAttributesOnCreate
(создать) или skipAttributesOnUpdate
(обновить)
Чтобы сообщить Phalcon\Mvc\Model, что всегда пропускает некоторые поля при создании и / или обновлении записей, чтобы делегировать системе базы данных назначение значений триггером или по умолчанию:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->skipAttributes( [ 'inv_total', 'inv_created_at', ] ); $this->skipAttributesOnCreate( [ 'inv_created_at', ] ); $this->skipAttributesOnUpdate( [ 'inv_modified_at', ] ); } }
Если вы хотите задать значения по умолчанию в свойствах модели (например, inv_created_at
) , вы можете использовать Phalcon\Db\RawValue:
<?php use MyApp\Models\Invoices; use Phalcon\Db\RawValue; $invoice = new Invoices(); $invoice->inv_id = 1234; $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = new RawValue('default'); $invoice->create();
Мы также можем воспользоваться преимуществом события beforeCreate
в модели, чтобы присвоить ему значение по умолчанию:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; use Phalcon\Db\RawValue; class Invoices extends Model { public function beforeCreate() { $this->inv_created_at = new RawValue('default'); } }
ПРИМЕЧАНИЕ: никогда не используйте Phalcon\Db\RawValue для назначения внешних данных (например, ввода пользователем) или переменных данных. Значение этих полей игнорируется при привязке параметров к запросу. Таким образом, он может быть использован для атак SQL-инъекций.
Динамические обновления
Инструкции SQL UPDATE
по умолчанию создаются с каждым столбцом, определенным в модели (полное обновление SQL для всех полей). Можно изменить определенные модели для выполнения динамических обновлений, в этом случае только измененные поля используются для создания последней инструкции SQL.
В некоторых случаях это может повысить производительность за счет уменьшения трафика между приложением и сервером базы данных, особенно когда целевая таблица имеет поля blob/text:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->useDynamicUpdate(true); } }
Сопоставление столбцов
ORM поддерживает независимую карту столбцов, которая позволяет разработчику использовать различные имена столбцов в модели по сравнению с именами в таблице. Phalcon распознает новые имена столбцов и переименует их соответственно, чтобы они соответствовали соответствующим столбцам в базе данных. Это отличная возможность, когда нужно переименовать поля в базе данных, не беспокоясь обо всех запросах в коде.
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_id; public $inv_cst_id; public $inv_status_flag; public $inv_title; public $inv_total; public $inv_created_at; public function columnMap() { return [ 'inv_id' => 'id', 'inv_cst_id' => 'customerId', 'inv_status_flag' => 'status', 'inv_title' => 'title', 'inv_total' => 'total', 'inv_created_at' => 'createdAt', ]; } }
ПРИМЕЧАНИЕ: В массиве, определенном в карте столбцов, ключи являются фактическими именами полей в базе данных, а значения - виртуальными полями, которые мы можем использовать в вашем коде
Теперь мы можем использовать эти виртуальные поля (или карту столбцов) в вашем коде:
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst( [ 'conditions' => 'inv_id = :id:', 'bind' => [ 'id' => 4, ] ] ); echo $invoice->customerId, PHP_EOL, $invoice->total, PHP_EOL, $invoice->createdAt, PHP_EOL; $invoices = Invoices::find( [ 'order' => 'createdAt DESC', ] ); foreach ($invoices as $invoice) { echo $invoice->customerId, PHP_EOL, $invoice->total, PHP_EOL, $invoice->createdAt, PHP_EOL; } $invoice = new Invoices(); $invoice->customerId = 1; $invoice->status = 1; $invoice->title = 'Invoice for ACME Inc.'; $invoice->total = 100; $invoice->createdAt = '2019-12-25 01:02:03'; $invoice->save();
Соображения
При переименовании столбцов учитывайте следующее:
- Ссылки на атрибуты в отношениях/валидаторах должны использовать виртуальные имена
- Ссылка на реальные имена столбцов приведет к исключению со стороны ORM
Независимая карта столбцов позволяет вам:
- Пишите приложения, используя свои собственные соглашения
- Исключите из кода префиксы/суффиксы поставщиков
- Изменение имен столбцов без изменения кода приложения
Запись Моментальных Снимков
Определенные модели могут быть настроены для сохранения моментального снимка записи, когда они запрашиваются. Вы можете использовать эту функцию для реализации аудита или просто для того, чтобы узнать, какие поля были изменены в модели по сравнению с данными в базе данных.
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->keepSnapshots(true); } }
При активации этой функции приложение потребляет немного больше памяти, чтобы отслеживать исходные значения, полученные из базы данных. В моделях, в которых эта функция активирована, вы можете проверить, какие поля изменились следующим образом:
<?php use MyApp\Models\Invoices; $invoice = Invoices::findFirst(); $invoice->inv_total = 120; var_dump($invoice->getChangedFields()); // ['inv_total'] var_dump($invoice->hasChanged('inv_total')); // true var_dump($invoice->hasChanged('inv_cst_id')); // false
Моментальные снимки обновляются при создании/обновлении модели. Используя hasUpdated()
и getUpdatedFields()
может использоваться, чтобы проверить, если поля были обновлены после создания/сохранения/обновления, но это может вызвать проблемы для вашего приложения, если вы выполните getChangedFields()
в afterUpdate()
, afterSave()
или afterCreate()
.
Вы можете отключить эту функцию с помощью:
<?php Phalcon\Mvc\Model::setup( [ 'updateSnapshotOnSave' => false, ] );
или, если вы предпочитаете установить это в вашем php.ini
phalcon.orm.update_snapshot_on_save = 0
Использование этой функции будет иметь следующий эффект:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public $inv_id; public $inv_cst_id; public $inv_status_flag; public $inv_title; public $inv_total; public $inv_created_at; public function initialize() { $this->keepSnapshots(true); } } $invoice = new Invoices(); $invoice->inv_id = 1234; $invoice->inv_cst_id = 1; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; $invoice->create(); var_dump( $invoice->getChangedFields() // [] ); $invoice->inv_total = 120; var_dump( $invoice->getChangedFields() // ['inv_total'] ); $invoice->update(); var_dump( $invoice->getChangedFields() // [] );
getUpdatedFields()
будет корректно возвращать обновленные поля или, как упоминалось выше, вы можете вернуться к предыдущему поведению, установив соответствующее значение ini.
События
Как упоминалось ранее, Phalcon\Mvc\Model действует как слушатель событий. Поэтому все события, которые прослушивает модель, могут быть реализованы как методы в самой модели. Вы можете проверить события документа для получения дополнительной информации.
Поддерживаемые события::
afterCreate
afterDelete
afterFetch
afterSave
afterUpdate
afterValidation
afterValidationOnCreate
afterValidationOnUpdate
beforeDelete
beforeCreate
beforeSave
beforeUpdate
beforeValidation
beforeValidationOnCreate
beforeValidationOnUpdate
notDeleted
notSaved
onValidationFails
prepareSave
validation
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; use Phalcon\Messages\Message as Message; class Invoices extends Model { public function beforeSave() { if (0 === $this->inv_status_flag) { $message = new Message( 'Sorry, an invoice cannot be unpaid' ); $this->appendMessage($message); } } }
Транзакции
Транзакции необходимы для обеспечения целостности данных, когда нам нужно вставить или обновить данные в нескольких таблицах во время одной и той же операции. Phalcon\Mvc\Model предоставляет метод setTransaction
, который позволяет привязать каждую модель к активной транзакции.
<?php use MyApp\Models\Customers; use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Transaction\Manager; use Phalcon\Mvc\Model\Transaction\Failed; try { $txManager = new Manager(); $transaction = $txManager->get(); $customer = new Customers(); $customer->setTransaction($transaction); $customer->cst_name_last = 'Vader'; $customer->cst_name_first = 'Darth'; if (false === $customer->save()) { $transaction->rollback('Cannot save Customer'); } $invoice = new Invoices(); $invoice->setTransaction($transaction); $invoice->inv_cst_id = $customer->cst_id; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100; $invoice->inv_created_at = '2019-12-25 01:02:03'; if (false === $invoice->save()) { $transaction->rollback('Cannot save record'); } $transaction->commit(); } catch (Failed $ex) { echo 'ERROR: ', $ex->getMessage(); }
Вы также можете включить результаты поиска в свои транзакции или даже иметь несколько транзакций, выполняемых одновременно:
<?php use MyApp\Models\Customers; use MyApp\Models\Invoices; use Phalcon\Mvc\Model\Transaction\Manager; use Phalcon\Mvc\Model\Transaction\Failed; try { $txManager = new Manager(); $transaction = $txManager->get(); $customer = new Customers(); $customer->setTransaction($transaction); $customer->cst_name_last = 'Vader'; $customer->cst_name_first = 'Darth'; if (false === $customer->save()) { $transaction->rollback('Cannot save Customer'); } $average = Invoices::average( [ Model::TRANSACTION_INDEX => $transaction, 'column' => 'inv_total', 'conditions' => 'inv_cst_id = :customerId:', 'bind' => [ 'customerId' => 3, ], ] ); $invoice = new Invoices(); $invoice->setTransaction($transaction); $invoice->inv_cst_id = $customer->cst_id; $invoice->inv_status_flag = 1; $invoice->inv_title = 'Invoice for ACME Inc.'; $invoice->inv_total = 100 + $average; $invoice->inv_created_at = '2019-12-25 01:02:03'; if (false === $invoice->save()) { $transaction->rollback('Cannot save record'); } $transaction->commit(); } catch (Failed $ex) { echo 'ERROR: ', $ex->getMessage(); }
Изменение Схемы
Если модель сопоставлена с таблицей, расположенной в схеме, отличной от схемы по умолчанию, можно использовать setSchema()
для указания правильного расположения:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->setSchema('invoices'); } }
Несколько баз данных
Модели Phalcon по умолчанию подключаются к тому же подключению к базе данных (службеdb
), которое было определено в контейнере внедрения зависимостей. Однако может потребоваться подключить определенные модели к различным соединениям, которые могут быть соединениями с различными базами данных.
Мы можем определить, какая модель подключается к какой базе данных в методе initialize
каждой модели:
<?php use Phalcon\Di\FactoryDefault; use Phalcon\Db\Adapter\Pdo\Mysql; use Phalcon\Db\Adapter\Pdo\PostgreSQL; $container = new FactoryDefault(); // MySQL $container->set( 'dbMysql', function () { return new Mysql( [ 'host' => 'localhost', 'username' => 'root', 'password' => 'secret', 'dbname' => 'tutorial', ] ); }, true ); // PostgreSQL $container->set( 'dbPostgres', function () { return new PostgreSQL( [ 'host' => 'localhost', 'username' => 'postgres', 'password' => '', 'dbname' => 'tutorial', ] ); } );
и в методе initialize()
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->setConnectionService('dbPostgres'); } }
Дополнительная гибкость доступна в отношении подключений к базе данных. Вы можете указать другое соединение для операций чтения и другое для операций записи. Это особенно полезно, когда у вас есть базы данных памяти, которые можно использовать для операций чтения, и другие, более мощные базы данных, которые используются для операций записи.
Вы можете установить два различных соединения и использовать каждую базу данных в каждой модели прозрачно
<?php use Phalcon\Di\FactoryDefault; use Phalcon\Db\Adapter\Pdo\Mysql; use Phalcon\Db\Adapter\Pdo\PostgreSQL; $container = new FactoryDefault(); // MySQL - read $container->set( 'mysqlRead', function () { return new Mysql( [ 'host' => '10.0.4.100', 'username' => 'root', 'password' => 'secret', 'dbname' => 'tutorial', ] ); }, true ); // MySQL - write $container->set( 'mysqlWrite', function () { return new Mysql( [ 'host' => '10.0.4.200', 'username' => 'root', 'password' => 'secret', 'dbname' => 'tutorial', ] ); }, true );
и в методе initialize()
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->setReadConnectionService('mysqlRead'); $this->setWriteConnectionService('mysqlWrite'); } }
ORM также предоставляет функции горизонтального сегментирования, позволяя реализовать выбор сегментов в соответствии с условиями запроса:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { /** * Dynamically selects a shard * * @param array $intermediate * @param array $bindParams * @param array $bindTypes * * @return Phalcon\Db\Adapter\AdapterInterface */ public function selectReadConnection( $intermediate, $bindParams, $bindTypes ) { if (true === isset($intermediate['where'])) { $conditions = $intermediate['where']; if ($conditions['left']['name'] === 'id') { $id = $conditions['right']['value']; if ($id > 0 && $id < 10000) { return $this->getDI()->get('dbShard1'); } if ($id > 10000) { return $this->getDI()->get('dbShard2'); } } } return $this->getDI()->get('dbShard0'); } }
В приведенном выше примере мы проверяем массив $intermediate
, который является массивом, построенным внутренне в Phalcon, предлагая промежуточное представление запроса. Мы проверяем, есть ли у нас какие-либо условия where
. Если нет, мы просто используем осколок dbShard0
по умолчанию.
Если условия были определены, мы проверяем, есть ли у нас id
в качестве поля в условиях, и получаем его значение. Если id
находится между 0
и 100000
, то мы используем dbShard1
, альтернативно dbShard2
.
Метод selectReadConnection()
вызывается каждый раз, когда нам нужно получить данные из базы данных, и возвращает правильное соединение, которое будет использоваться.
Инъекция Зависимостей
Phalcon\Mvc\Model плотно привязан к контейнеру DI. Контейнер можно извлечь с помощью метода getDI
. Таким образом, Вы имеете доступ ко всем сервисам, зарегистрированным в контейнере DI.
В следующем примере показано, как можно распечатать любые сообщения, созданные неудачной операцией сохранения в модели, и отобразить эти сообщения в программе flash messenger. Для этого мы используем событие notSaved
:
<?php namespace MyApp\Models; use Phalcon\Mvc\Model; class Invoices extends Model { public function notSaved() { $flash = $this->getDI()->getFlash(); $messages = $this->getMessages(); // Show validation messages foreach ($messages as $message) { $flash->error($message); } } }
Особенности Модели
У ORM есть несколько вариантов, которые управляют определенным поведением глобально. Вы можете включить или отключить эти функции, добавив определенные строки в свой php.ini
файл или используйте статический метод setup
для модели. Вы можете включить или отключить эти функции временно или навсегда.
phalcon.orm.column_renaming = false phalcon.orm.events = false
или с помощью модели:
<?php use Phalcon\Mvc\Model; Model::setup( [ 'columnRenaming' => false, 'events' => false, ] );
Доступные варианты::
Вариант | По умолчанию | Описание |
---|---|---|
caseInsensitiveColumnMap |
false |
Нечувствительность к регистру сопоставление столбцов |
castLastInsertIdToInt |
false |
Приводит lastInsertId к целому числу |
castOnHydrate |
false |
Автоматическое приведение к оригинальным типам при гидратации |
columnRenaming |
true |
Переименование столбцов |
disableAssignSetters |
false |
Отключить сеттеров |
enableImplicitJoins |
true |
Включить неявные соединения |
events |
true |
Обратные вызовы, крючки и уведомления о событиях от всех моделей |
exceptionOnFailedMetaDataSave |
false |
Создать исключение при неудачном сохранении метаданных |
exceptionOnFailedSave |
false |
Создать исключение при неудачном save() |
ignoreUnknownColumns |
false |
Игнорировать неизвестные столбцы в модели |
lateStateBinding |
false |
Поздняя привязка состояния метода Phalcon\Mvc\Model::cloneResultMap() |
notNullValidations |
true |
Автоматическая проверка имеющихся столбцов, отличных от null |
phqlLiterals |
true |
Литералы в синтаксическом анализаторе PHQL |
prefetchRecords |
0 |
Количество записей для предварительной выборки при получении данных из ORM |
updateSnapshotOnSave |
true |
Обновить моментальные снимки при save() |
virtualForeignKeys |
true |
Виртуальные внешние ключи |
ini
опции:
; phalcon..orm.ast_cache = null ; phalcon..orm.cache_level = 3 ; phalcon..orm.case_insensitive_column_map = false ; phalcon..orm.cast_last_insert_id_to_int = false ; phalcon..orm.cast_on_hydrate = false ; phalcon..orm.column_renaming = true ; phalcon..orm.disable_assign_setters = false ; phalcon..orm.enable_implicit_joins = true ; phalcon..orm.enable_literals = true ; phalcon..orm.events = true ; phalcon..orm.exception_on_failed_metadata_save = true ; phalcon..orm.exception_on_failed_save = false ; phalcon..orm.ignore_unknown_columns = false ; phalcon..orm.late_state_binding = false ; phalcon..orm.not_null_validations = true ; phalcon.orm.parser_cache = null, ; phalcon..orm.resultset_prefetch_records = 0 ; phalcon..orm.unique_cache_id = 3 ; phalcon..orm.update_snapshot_on_save = true ; phalcon..orm.virtual_foreign_keys = true
ПРИМЕЧАНИЕ
Phalcon\Mvc\Model::assign()
(который также используется при создании, обновлении/сохранении модели) всегда использует задатчики, если они существуют, когда передаются аргументы данных, даже если это необходимо или необходимо. Это добавит дополнительные накладные расходы в приложение. Вы можете изменить это поведение, добавивphalcon.orm.disable_assign_setters = 1
к вашему ini-файлу, он будет просто использовать$this->property = value
.
Отдельный Компонент
Вы можете использовать Phalcon\Mvc\Model самостоятельно, выполнив необходимую настройку самостоятельно, если хотите. Приведенный ниже пример демонстрирует, как этого можно достичь.
<?php use Phalcon\Di; use Phalcon\Mvc\Model; use Phalcon\Mvc\Model\Manager; use Phalcon\Db\Adapter\Pdo\Sqlite; use Phalcon\Mvc\Model\Metadata\Memory; $container = new Di(); $container->set( 'db', new Sqlite( [ 'dbname' => 'sample.db', ] ) ); $container->set( 'modelsManager', new Manager() ); $container->set( 'modelsMetadata', new Memory() ); class Invoices extends Model { } echo Invoices::count();