Documentation

Оглавление

Предыдущий раздел

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

Следующий раздел

Отношения модели >

Эта страница

Работа с моделями

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

Phalcon\Mvc\Model является родительским классом. Когда процесс выполняет несколько операций для всех моделей в вашем приложении Phalcon. Он обеспечивает независимость данных от вашей базы, основные CRUD операции, расширенные поисковые возможности, а также возможность построения зависимостей между моделями. Phalcon\Mvc\Model исключает необходимость использования SQL запросов, потому как данный класс динамически переводит методы на соответствующие им операции СУБД.

Модели предназначены для работы с базой данных на высшем уровне абстракции. Если вы испытваете потребность в работе с базой данных на низшем уровне, обратитесь к документации компонента Phalcon\Db.

Создание модели

Модель это класс, который расширяет Phalcon\Mvc\Model. Его имя должно быть записано в CamelCase стиле:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class RobotParts extends Model
{

}
Если вы используете PHP 5.4/5.5 рекомендовано объявлять каждый столбец базы данных, который входит в модель в целях экономии памяти и уменьшения общего выделения памяти на выполнение.

По умолчанию модель “Store\Toys\RobotParts” будет ссылаться на таблицу ‘robot_parts’. Если вы захотите вручную указать другое имя для маппинга таблицы, вы можете использовать метод setSource():

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class RobotParts extends Model
{
    public function initialize()
    {
        $this->setSource("toys_robot_parts");
    }
}

Теперь модель RobotParts отображается на таблицу “toys_robot_parts”. Метод initialize() помогает в создании модели с пользовательским поведением, т.е. использовании другой таблицы.

Метод initialize() вызывается один раз при обработке запроса к приложению и предназначен для инициализации экземпляров модели в приложении. Если вам необходимо произвести некоторые настройки экземпляра объекта после того, как он создан, вы можете использовать метод onConstruct():

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class RobotParts extends Model
{
    public function onConstruct()
    {
        // ...
    }
}

Публичные свойства и сеттеры/геттеры

Модели могут быть реализованы с помощью свойств с общим доступом (public), при этом свойства модели доступны для чтения/изменения из любой части кода без ограничений:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public $price;
}

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

<?php

namespace Store\Toys;

use InvalidArgumentException;
use Phalcon\Mvc\Model;

class Robots extends Model
{
    protected $id;

    protected $name;

    protected $price;

    public function getId()
    {
        return $this->id;
    }

    public function setName($name)
    {
        // Имя слишком короткое?
        if (strlen($name) < 10) {
            throw new InvalidArgumentException(
                "Имя слишком короткое"
            );
        }

        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPrice($price)
    {
        // Не разрешаем отрицательные цены
        if ($price < 0) {
            throw new InvalidArgumentException(
                "Цена не может быть отрицательной"
            );
        }

        $this->price = $price;
    }

    public function getPrice()
    {
        // Преобразование значение в double (формат числа с плавающей запятой), прежде чем использовать
        return (double) $this->price;
    }
}

Публичные свойства облегчают создание кода. Напротив, применение геттеров/сеттеров делает ваш код тестируемым, расширяемым и удобным в сопровождении. Разработчик вправе сам определить способ описания модели. ORM совместим с обоими способами.

Underscores in property names can be problematic when using getters and setters.

If you use underscores in your property names, you must still use camel case in your getter/setter declarations for use with magic methods. (e.g. $model->getPropertyName instead of $model->getProperty_name, $model->findByPropertyName instead of $model->findByProperty_name, etc.). As much of the system expects camel case, and underscores are commonly removed, it is recommended to name your properties in the manner shown throughout the documentation. You can use a column map (as described above) to ensure proper mapping of your properties to their database counterparts.

Понимание записей в объектах

Каждый экземпляр объекта модели представляет собой строку таблицы базы данных. Вы можете легко получить доступ к любой записи, считывая свойство объекта. К примеру, для таблицы “robots” с записями:

mysql> select * from robots;
+----+------------+------------+------+
| id | name       | type       | year |
+----+------------+------------+------+
|  1 | Robotina   | mechanical | 1972 |
|  2 | Astro Boy  | mechanical | 1952 |
|  3 | Terminator | cyborg     | 2029 |
+----+------------+------------+------+
3 rows in set (0.00 sec)

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

<?php

use Store\Toys\Robots;

// Найти запись с id = 3
$robot = Robots::findFirst(3);

// Печатать "Terminator"
echo $robot->name;

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

<?php

use Store\Toys\Robots;

$robot = Robots::findFirst(3);

$robot->name = "RoboCop";

$robot->save();

Как вы можете видеть, нет никакой необходимости в использовании необработанных SQL запросов. Phalcon\Mvc\Model предоставляет высший уровень абстракции базы данных для веб-приложений.

Поиск записей

Phalcon\Mvc\Model также предлагает несколько методов для выборки записей. В следующем примере мы покажем вам как запросить одну или несколько записей из модели:

<?php

use Store\Toys\Robots;

// Сколько роботов есть?
$robots = Robots::find();
echo "Найдено роботов: ", count($robots), "\n";

// Сколько существует механических роботов?
$robots = Robots::find("type = 'mechanical'");
echo "Найдено роботов: ", count($robots), "\n";

// Получить и распечатать виртуальных роботов упорядоченные по имени
$robots = Robots::find(
    [
        "type = 'virtual'",
        "order" => "name",
    ]
);
foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Получить первые 100 виртуальных роботов упорядоченных по имени
$robots = Robots::find(
    [
        "type = 'virtual'",
        "order" => "name",
        "limit" => 100,
    ]
);
foreach ($robots as $robot) {
   echo $robot->name, "\n";
}
Для исключения SQL-инъекций при поиске записей на основе пользовательского ввода или переменных вы должны использовать привязку параметров (см. ниже).

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

<?php

use Store\Toys\Robots;

// Первый робот в таблице роботов
$robot = Robots::findFirst();
echo "Название робота: ", $robot->name, "\n";

// Первый  механический робот в таблице роботов
$robot = Robots::findFirst("type = 'mechanical'");
echo "Название первого механического робота: ", $robot->name, "\n";

// Получим первого виртуального робота, упорядочив результат по имени
$robot = Robots::findFirst(
    [
        "type = 'virtual'",
        "order" => "name",
    ]
);
echo "Название первого виртуального робота: ", $robot->name, "\n";

Оба метода find() и findFirst() принимают ассоциативный массив, определяющий критерии поиска:

<?php

use Store\Toys\Robots;

$robot = Robots::findFirst(
    [
        "type = 'virtual'",
        "order" => "name DESC",
        "limit" => 30,
    ]
);

$robots = Robots::find(
    [
        "conditions" => "type = ?1",
        "bind"       => [
            1 => "virtual",
        ]
    ]
);

Доступные параметры запроса:

Параметр Описание Пример
conditions Условие поиска. Он используется для выделения только тех записей, которые полностью удовлетворяют условиям поиска. По умолчанию Phalcon\Mvc\Model предполагает что первый параметр является условием поиска "conditions" => "name LIKE 'steve%'"
columns Используется для указания списка столбцов возвращаемого в модели. Объект будет не полным при использовании этого параметра "columns" => "id, name"
bind Используется вместе с условием поиск, он заменяет указатели, освобождает значения для увеличения безопасности "bind" => ["status" => "A", "type" => "some-time"]
bindTypes При использовании связующих указателей вы можете использовать этот параметр, для указания типа данных, что еще больше увеличит безопасность "bindTypes" => [Column::BIND_PARAM_STR, Column::BIND_PARAM_INT]
order Используется для сортировки результатов. Можно использовать несколько полей через запятую "order" => "name DESC, status"
limit Ограничивает результаты запроса "limit" => 10
offset Смещает результаты запроса на определенное значение "offset" => 5
group Позволяет собирать данные на несколько записей и групп результатов по одному или нескольким столбцам "group" => "name, status"
for_update С этой опцией, Phalcon\Mvc\Model читает последние доступные данные, устанавливает исключительные блокировки на каждую прочтенную запись "for_update" => true
shared_lock С этой опцией, Phalcon\Mvc\Model читает последние доступные данные, устанавливает общие блокировки на каждую прочтенную запись "shared_lock" => true
cache Кэширует результаты, уменьшая нагрузку на реляционную систему. "cache" => ["lifetime" => 3600, "key" => "my-find-key"]
hydration Устанавливает режим гидратации для представления каждой записи в результате "hydration" => Resultset::HYDRATE_OBJECTS

Существует еще один вариант записи запросов поиска, в объектно-ориентированном стиле:

<?php

use Store\Toys\Robots;

$robots = Robots::query()
    ->where("type = :type:")
    ->andWhere("year < 2000")
    ->bind(["type" => "mechanical"])
    ->order("name")
    ->execute();

Статический метод query() возвращает Phalcon\Mvc\Model\Criteria объект, который нормально работает с автокомплитом среды разработки.

Все запросы внутри обрабатываются как PHQL запросы. PHQL это высокоуровневый, объектно-ориентированный, SQL подобный язык. Этот язык предоставляет вам больше возможностей для выполнения запросов, таких как объединение с другими моделями, определение группировок, добавление агрегации и т.д.

Наконец, имеется метод findFirstBy<название-свойства>(). Данный метод расширяет упомянутый ранее findFirst(). Он позволяет вам выполнять поиск по таблице, используя название свойства в самом методе, и, передавая ему параметр, содержащий информацию по которой вы хотите произвести поиск в столбце. В качестве примера возьмем упомянутую ранее модель Robots:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public $price;
}

Мы имеем три свойства, с которыми можно работать: $id, $name и $price. Допустим, вы хотите получить первую запись с именем ‘Terminator’. Можно сделать это следующим образом:

<?php

use Store\Toys\Robots;

$name = "Terminator";

$robot = Robots::findFirstByName($name);

if ($robot) {
    echo "Первый робот с именем " . $name . " стоит " . $robot->price . ".";
} else {
    echo "В нашей таблице не найдено роботов с именем " . $name . ".";
}

Заметьте, что мы используем ‘Name’ в вызове метода, а также передаем ему переменную $name, содержащую имя, которое мы ищем в таблице. Также обратите внимание, что если по запросу была найдена запись, то и все остальные свойства тоже доступны.

Возвращение результатов моделью

В то время как findFirst() возвращает непосредственно экземпляр вызванного класса (когда это возвращаемые данные), метод find() возвращает Phalcon\Mvc\Model\Resultset\Simple. Этот объект включает в себя весь функционал такой как, обходы, поиск определенных записей, подсчет и прочее.

Эти объекты являются более мощными, чем стандартные массивы. Одной из важнейших особенностей Phalcon\Mvc\Model\Resultset является то, что в любой момент времени в памяти содержится только одна запись. Это очень помогает в управлении памятью, особенно при работе с большими объемами данных.

<?php

use Store\Toys\Robots;

// Получить всех роботов
$robots = Robots::find();

// Обход в foreach
foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Обход в while
$robots->rewind();

while ($robots->valid()) {
    $robot = $robots->current();

    echo $robot->name, "\n";

    $robots->next();
}

// Посчитать количество роботов
echo count($robots);

// Альтернативный способ посчитать количество записей
echo $robots->count();

// Перемещение внутреннего курсора к третьему роботу
$robots->seek(2);

$robot = $robots->current();

// Получить робота по его позиции в наборе результатов
$robot = $robots[5];

// Проверка существования записи с соответствующим индексом
if (isset($robots[3])) {
   $robot = $robots[3];
}

// Получить первую запись в наборе результатов
$robot = $robots->getFirst();

// Получить последнюю запись
$robot = $robots->getLast();

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

Хранение больших результатов запроса в памяти может потребовать много ресурсов, из-за этого наборы результатов получаются из базы данных блоками по 32 строки, снижая потребность в повторном выполнении запроса, в ряде случаев экономя память.

Обратите внимание, что наборы результатов могут быть сериализованы и храниться в кэше бэкэнда. Phalcon\Cache может помочь с этой задачей. Тем не менее, сериализация данных заставляет Phalcon\Mvc\Model получить все данные из базы данных в массив, таким образом, в процессе потребляя больше памяти.

<?php

// Запрос всех записей из модели Parts
$parts = Parts::find();

// Сериализуем  результат и сохраняем в файл
file_put_contents(
    "cache.txt",
    serialize($parts)
);

// Достаём parts из файла
$parts = unserialize(
    file_get_contents("cache.txt")
);

// Обходим parts в foreach
foreach ($parts as $part) {
    echo $part->id;
}

Фильтрация результатов

Самый эффективный способ фильтрации данных - задание поисковых критериев. База данных сможет использовать индексирование, чтобы быстрее вернуть результат. В дополнение, Phalcon позволяет вам производить фильтрацию данных с помощью PHP, расширяя тем самым возможности базы данных:

<?php

$customers = Customers::find();

$customers = $customers->filter(
    function ($customer) {
        // Вернуть клиентов только с корректным e-mail адресом
        if (filter_var($customer->email, FILTER_VALIDATE_EMAIL)) {
            return $customer;
        }
    }
);

Привязка параметров

Привязка параметров также поддерживается в Phalcon\Mvc\Model. Использование привязки параметров рекомендуется, чтобы исключить возможность SQL инъекции. Привязка параметров поддерживает строки и числа:

<?php

use Store\Toys\Robots;

// Запрос роботов с параметрами, привязанными к строковым заполнителям
// Параметры с ключами, идентичными заполнителям
$robots = Robots::find(
    [
        "name = :name: AND type = :type:",
        "bind" => [
            "name" => "Robotina",
            "type" => "maid",
        ],
    ]
);

// Запрос роботов с параметрами, привязанными к числовым заполнителям
$robots = Robots::find(
    [
        "name = ?1 AND type = ?2",
        "bind" => [
            1 => "Robotina",
            2 => "maid",
        ],
    ]
);

// Запрос роботов с параметрами, привязанными к строковым и числовым заполнителям
// Параметры с ключами, идентичными заполнителям
$robots = Robots::find(
    [
        "name = :name: AND type = ?1",
        "bind" => [
            "name" => "Robotina",
            1      => "maid",
        ],
    ]
);

При использовании цифровых указателей, необходимо определить их как целые числа, то есть 1 или 2. В этом случае “1” или “2” считаются строками, а не числами, поэтому указатель не может быть успешно заменен.

Строки автоматически изолируются используя PDO. Эта функция принимает во внимание кодировку соединения с базой данных, поэтому рекомендуется определять корректную кодировку в параметрах соединения или в конфигурации базы данных, так как неправильная кодировка приведет к некорректному хранению и извлечению данных.

Кроме того, вы можете установить параметр “bindTypes”, что позволит определить, каким образом параметры должны быть связаны в соответствии с их типами данных:

<?php

use Phalcon\Db\Column;
use Store\Toys\Robots;

// Привязка параметров
$parameters = [
    "name" => "Robotina",
    "year" => 2008,
];

// Привязка типов параметров
$types = [
    "name" => Column::BIND_PARAM_STR,
    "year" => Column::BIND_PARAM_INT,
];

// Запрос роботов с параметрами, привязанными к строковым заполнителям и типам
$robots = Robots::find(
    [
        "name = :name: AND year = :year:",
        "bind"      => $parameters,
        "bindTypes" => $types,
    ]
);
Поскольку тип связывания по умолчанию Phalcon\Db\Column::BIND_PARAM_STR, нет необходимости указывать параметр “bindTypes”, если все столбцы этого типа.

Если вы связываете массивы с параметрами, то помните, что нумерация ключей должна начинаться с нуля:

<?php

use Store\Toys\Robots;

$array = ["a","b","c"]; // $array: [[0] => "a", [1] => "b", [2] => "c"]

unset($array[1]); // $array: [[0] => "a", [2] => "c"]

// Теперь необходимо перенумеровать ключи
$array = array_values($array); // $array: [[0] => "a", [1] => "c"]

$robots = Robots::find(
    [
        'letter IN ({letter:array})',
        'bind' => [
            'letter' => $array
        ]
    ]
);
Привязка параметров доступна для всех запросов метода, таких как find() и findFirst(), а так же для методов count(), sum(), average() и т.д.

Если вы используете “find” методы, то привязка параметров происходит автоматически:

<?php

use Store\Toys\Robots;

// Запрос с явной привязкой параметров
$robots = Robots::find(
    [
        "name = ?0",
        "bind" => [
            "Ultron",
        ],
    ]
);

// Запрос с неявной привязкой параметров
$robots = Robots::findByName("Ultron");

Инициализация/изменение полученных записей

Бывают случаи, что после получения записи из базы данных необходимо инициализировать данные перед их использованием остальной частью приложения. Вы можете определить в модели метод afterFetch(). Этот метод будет выполнен сразу после создания экземпляра записи и получения им данных:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    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);
    }
}

Независимо от того, используете вы геттеры/сеттеры или публичные свойства, вы можете реализовать обработку поля при получении доступа к последнему:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public $status;

    public function getStatus()
    {
        return explode(",", $this->status);
    }
}

Использование расчетов

Расчеты являются помощниками для часто используемых функций СУБД, таких как COUNT, SUM, MAX, MIN или AVG. Phalcon\Mvc\Model позволяет использовать эти функции непосредственно с доступными методами.

Пример подсчета:

<?php

// Сколько сотрудников работает?
$rowcount = Employees::count();

// Сколько уникальных сфер деятельности рабочих?
$rowcount = Employees::count(
    [
        "distinct" => "area",
    ]
);

// Сколько сотрудников работает в сфере тестирования?
$rowcount = Employees::count(
    "area = 'Testing'"
);

// Посчитать сотрудников, сгруппировав результаты по сфере деятельности
$group = Employees::count(
    [
        "group" => "area",
    ]
);
foreach ($group as $row) {
   echo $row->rowcount, " сотрудников в ", $row->area;
}

// Посчитать сотрудников, сгруппировав результаты по сфере деятельности, и упорядочив их по количеству
$group = Employees::count(
    [
        "group" => "area",
        "order" => "rowcount",
    ]
);

// Избегайте SQL инъекции, используя связанные параметры
$group = Employees::count(
    [
        "type > ?0",
        "bind" => [
            $type
        ],
    ]
);

Пример суммы:

<?php

// Какая заработная плата всех сотрудников?
$total = Employees::sum(
    [
        "column" => "salary",
    ]
);

// Какая заработная плата всех сотруднииков в сфере продаж?
$total = Employees::sum(
    [
        "column"     => "salary",
        "conditions" => "area = 'Sales'",
    ]
);

// Группирует заработные платы по каждой сфере деятельности
$group = Employees::sum(
    [
        "column" => "salary",
        "group"  => "area",
    ]
);
foreach ($group as $row) {
   echo "Сумма заработной платы ", $row->area, " составляет ", $row->sumatory;
}

// Группирует заработные платы по каждой сферы деятельности
// и упорядочивает их от большего к меньшему
$group = Employees::sum(
    [
        "column" => "salary",
        "group"  => "area",
        "order"  => "sumatory DESC",
    ]
);

// Избегайте SQL инъекции, используя связанные параметры
$group = Employees::sum(
    [
        "conditions" => "area > ?0",
        "bind"       => [
            $area
        ],
    ]
);

Пример поиска среднего:

<?php

// Какая средняя зарплата среди всех сотрудников?
$average = Employees::average(
    [
        "column" => "salary",
    ]
);

// Какая средняя зарплата среди сотрудников сферы продаж?
$average = Employees::average(
    [
        "column"     => "salary",
        "conditions" => "area = 'Sales'",
    ]
);

// Избегайте SQL инъекции, используя связанные параметры
$average = Employees::average(
    [
        "column"     => "age",
        "conditions" => "area > ?0",
        "bind"       => [
            $area
        ],
    ]
);

Пример нахождения максимального/минимального:

<?php

// Какой максимальный возраст среди всех сотрудников?
$age = Employees::maximum(
    [
        "column" => "age",
    ]
);

// Какой максимальный возраст среди сотрудников сферы продаж?
$age = Employees::maximum(
    [
        "column"     => "age",
        "conditions" => "area = 'Sales'",
    ]
);

// Какая минимальная зарплата среди сотрудников?
$salary = Employees::minimum(
    [
        "column" => "salary",
    ]
);

Создание/обновление записей

Метод Phalcon\Mvc\Model::save() позволяет создавать/обновлять записи в зависимости от того, существуют ли они уже в таблице, связанной с моделью. Метод save вызывается методами create и update класса Phalcon\Mvc\Model. Для этого необходимо иметь в таблице должным образом установленный первичный ключ, чтобы можно было определить, должна ли запись быть обновлена или создана.

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

<?php

use Store\Toys\Robots;

$robot = new Robots();

$robot->type = "mechanical";
$robot->name = "Astro Boy";
$robot->year = 1952;

if ($robot->save() === false) {
    echo "Мы не можем сохранить робота прямо сейчас: \n";

    $messages = $robot->getMessages();

    foreach ($messages as $message) {
        echo $message, "\n";
    }
} else {
    echo "Отлично, новый робот был успешно сохранен!";
}

В метод “save” может быть передан массив, чтобы избежать назначения каждого столбца вручную. Phalcon\Mvc\Model проверит, есть ли сеттеры, реализованные для столбцов, для значений переданных в массиве, отдавая приоритет им, вместо непосредственно назначения значений свойствам:

<?php

use Store\Toys\Robots;

$robot = new Robots();

$robot->save(
    [
        "type" => "mechanical",
        "name" => "Astro Boy",
        "year" => 1952,
    ]
);

Значения, назначеные непосредственно через атрибуты или через массив, экранируются/проверяются в соответствии с типом данных атрибута. Таким образом, вы можете передать ненадежный массив, не беспокоясь о возможных SQL инъекциях:

<?php

use Store\Toys\Robots;

$robot = new Robots();

$robot->save($_POST);
Без каких-либо мер предосторожности передача массива в данный метод позволит злоумышленникам установить значение любого столбца базы данных. Используйте эту возможность только в том случае, если вы хотите позволить пользователю добавлять/обновлять каждый столбец в модели, даже если этих полей нет в отправленной форме.

Вы можете передать дополнительный параметр в метод ‘save’, чтобы установить список полей, которые должны быть прининяты во внимание при массовом присваивании:

<?php

use Store\Toys\Robots;

$robot = new Robots();

$robot->save(
    $_POST,
    [
        "name",
        "type",
    ]
);

Создание/обновление с уверенностью

При разработке мы можем столкнуться с ситуацией, когда две идентичные записи происходят одновременно. Это может произойти, если мы используем Phalcon\Mvc\Model::save() для сохранения элемента в БД. Если мы хотим быть абсолютно уверены, что запись будет создана или обновлена, мы можем заменить save() на вызов create() или update():

<?php

use Store\Toys\Robots;

$robot = new Robots();

$robot->type = "mechanical";
$robot->name = "Astro Boy";
$robot->year = 1952;

// Эта запись только должна быть создана
if ($robot->create() === false) {
    echo "Мы не можем сохранить робота прямо сейчас: \n";

    $messages = $robot->getMessages();

    foreach ($messages as $message) {
        echo $message, "\n";
    }
} else {
    echo "Отлично, новый робот был успешно создан!";
}

Методы “create” и “update” также принимают массив значений в качестве параметра.

Удаление записей

Метод Phalcon\Mvc\Model::delete() позволяет удалить запись. Вы можете использовать его следующим образом:

<?php

use Store\Toys\Robots;

$robot = Robots::findFirst(11);

if ($robot !== false) {
    if ($robot->delete() === false) {
        echo "К сожалению, мы не можем удалить робота прямо сейчас: \n";

        $messages = $robot->getMessages();

        foreach ($messages as $message) {
            echo $message, "\n";
        }
    } else {
        echo "Робот был успешно удален!";
    }
}

Вы также можете удалить несколько записей путем обхода набора результатов в цикле foreach:

<?php

use Store\Toys\Robots;

$robots = Robots::find(
    "type = 'mechanical'"
);

foreach ($robots as $robot) {
    if ($robot->delete() === false) {
        echo "К сожалению, мы не можем удалить робота прямо сейчас: \n";

        $messages = $robot->getMessages();

        foreach ($messages as $message) {
            echo $message, "\n";
        }
    } else {
        echo "Робот был успешно удален!";
    }
}

Следующие события, доступные для определения пользовательской бизнес-логики, вызываются при выполнении операции удаления:

Операция Название Можно остановить операцию? Пояснение
Удаление beforeDelete ДА Выполняется до операции удаления
Удаление afterDelete НЕТ Выполняется после операции удаления

В событиях, указанных выше, также можно определять бизнес-логику модели:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public function beforeDelete()
    {
        if ($this->status === "A") {
            echo "Робот активен, он не может быть удален";

            return false;
        }

        return true;
    }
}
Follow along: