Активная запись - это отображение сущности базы данных на объект PHP. Проще говоря, если у вас есть таблица пользователей в вашей базе данных, вы можете "перевести" строку в этой таблице в класс User и объект $user в вашем коде. Смотрите простой пример.
User
$user
Нажмите здесь для репозитория на GitHub.
Допустим, у вас есть следующая таблица:
CREATE TABLE users ( id INTEGER PRIMARY KEY, name TEXT, password TEXT );
Теперь вы можете создать новый класс, чтобы представить эту таблицу:
/** * Класс ActiveRecord обычно в единственном числе * * Для наглядности рекомендуется добавить свойства таблицы в виде комментариев здесь * * @property int $id * @property string $name * @property string $password */ class User extends flight\ActiveRecord { public function __construct($database_connection) { // можно установить так parent::__construct($database_connection, 'users'); // или так parent::__construct($database_connection, null, [ 'table' => 'users']); } }
Теперь посмотрите, как это легко!
// для sqlite $database_connection = new PDO('sqlite:test.db'); // это просто пример, обычно вы бы использовали реальное соединение с базой данных // для mysql $database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password'); // или mysqli $database_connection = new mysqli('localhost', 'username', 'password', 'test_db'); // или mysqli с созданием не на основе объекта $database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db'); $user = new User($database_connection); $user->name = 'Бобби Тейблз'; $user->password = password_hash('какой-то крутой пароль'); $user->insert(); // или $user->save(); echo $user->id; // 1 $user->name = 'Джозеф Мамма'; $user->password = password_hash('крутой пароль снова!!!'); $user->insert(); // здесь нельзя использовать $user->save(), иначе он подумает, что это обновление! echo $user->id; // 2
И это было настолько легко добавить нового пользователя! Теперь, когда есть строка пользователя в базе данных, как ее извлечь?
$user->find(1); // найдите id = 1 в базе данных и верните его. echo $user->name; // 'Бобби Тейблз'
Что, если вы хотите найти всех пользователей?
$users = $user->findAll();
А что насчет определенного условия?
$users = $user->like('name', '%мамма%')->findAll();
Вот как это весело! Установим его и начнем!
Просто установите с помощью Composer
composer require flightphp/active-record
Эту библиотеку можно использовать как автономно, так и с фреймворком Flight PHP. Полностью на ваше усмотрение.
Убедитесь, что вы передаете соединение PDO в конструктор.
$pdo_connection = new PDO('sqlite:test.db'); // это просто пример, обычно вы бы использовали реальное соединение с базой данных $User = new User($pdo_connection);
Вы не хотите всегда устанавливать соединение с базой данных в конструкторе? См. Управление соединением с базой данных для других идей!
Если вы используете фреймворк Flight PHP, вы можете зарегистрировать класс ActiveRecord как службу, но честно говоря, это не обязательно.
Flight::register('user', 'User', [ $pdo_connection ]); // затем вы можете использовать его так в контроллере, функции и т. д. Flight::user()->find(1);
runway - это инструмент командной строки для Flight, который имеет пользовательскую команду для этой библиотеки.
# Использование php runway make:record имя_таблицы_базы_данных [имя_класса] # Пример php runway make:record users
Это создаст новый класс в каталоге app/records/ под названием UserRecord.php со следующим содержанием:
app/records/
UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Класс ActiveRecord для таблицы пользователей. * @link https://docs.flightphp.com/awesome-plugins/active-record * * @property int $id * @property string $username * @property string $email * @property string $password_hash * @property string $created_dt */ class UserRecord extends \flight\ActiveRecord { /** * @var array $relations Установите отношения для модели * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = [ // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ], ]; /** * Конструктор * @param mixed $databaseConnection Соединение с базой данных */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
find($id = null) : boolean|ActiveRecord
Находит одну запись и присваивает ее текущему объекту. Если вы передаете $id, он выполнит поиск по первичному ключу с этим значением. Если ничего не передается, он просто найдет первую запись в таблице.
$id
Кроме того, вы можете передавать другие вспомогательные методы для запроса вашей таблицы.
// найти запись с некоторыми условиями заранее $user->notNull('password')->orderBy('id DESC')->find(); // найти запись по конкретному id $id = 123; $user->find($id);
findAll(): array<int,ActiveRecord>
Находит все записи в указанной таблице.
$user->findAll();
isHydrated(): boolean
Возвращает true, если текущая запись была считана с базы данных.
true
$user->find(1); // если запись найдена с данными... $user->isHydrated(); // true
insert(): boolean|ActiveRecord
Вставляет текущую запись в базу данных.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->insert();
Если у вас есть первичный ключ на основе текста (например, UUID), вы можете установить значение первичного ключа перед вставкой одним из двух способов.
$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]); $user->uuid = 'some-uuid'; $user->name = 'demo'; $user->password = md5('demo'); $user->insert(); // или $user->save();
или вы можете автоматически сгенерировать первичный ключ через события.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]); // вы также можете установить primaryKey таким образом, а не в массиве выше. $this->primaryKey = 'uuid'; } protected function beforeInsert(self $self) { $self->uuid = uniqid(); // или как иначе нужно создавать уникальные идентификаторы } }
Если вы не установите первичный ключ перед вставкой, он будет установлен на rowid, и база данных сгенерирует его для вас, но он не сохранится, потому что это поле может отсутствовать в вашей таблице. Поэтому рекомендуется использовать событие для автоматической обработки этого для вас.
rowid
update(): boolean|ActiveRecord
Обновляет текущую запись в базе данных.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@example.com'; $user->update();
save(): boolean|ActiveRecord
Вставляет или обновляет текущую запись в базе данных. Если у записи есть идентификатор, он будет обновлен, в противном случае он будет вставлен.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->save();
Примечание: Если у вас в классе определены отношения, они также будут рекурсивно сохраняться, если они были определены, инициализированы и имеют данные для обновления. (v0.4.0 и выше)
delete(): boolean
Удаляет текущую запись из базы данных.
$user->gt('id', 0)->orderBy('id desc')->find(); $user->delete();
Вы также можете удалить несколько записей, выполнив поиск заранее.
$user->like('name', 'Bob%')->delete();
dirty(array $dirty = []): ActiveRecord
Грязные данные относятся к данным, которые были изменены в записи.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); // на данный момент ничего не является "грязным". $user->email = 'test@example.com'; // теперь электронная почта считается "грязной", так как она изменилась. $user->update(); // теперь нет грязных данных, потому что они были обновлены и сохранены в базе данных $user->password = password_hash()'newpassword'); // теперь это грязные данные $user->dirty(); // передача ничего не очистит все грязные записи. $user->update(); // ничего не обновится, потому что ничего не было помечено как грязное. $user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // обновятся и имя и пароль.
copyFrom(array $data): ActiveRecord
Это псевдоним для метода dirty(). Это немного более ясно, чем вы это делаете.
dirty()
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // обновятся и имя и пароль.
isDirty(): boolean
Возвращает true, если текущая запись была изменена.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@email.com'; $user->isDirty(); // true
reset(bool $include_query_data = true): ActiveRecord
Сбрасывает текущую запись в начальное состояние. Это действительно хорошо использовать в циклических поведениях. Если передать true, он также сбросит данные запроса, которые были использованы для нахождения текущего объекта (поведение по умолчанию).
$users = $user->greaterThan('id', 0)->orderBy('id desc')->find(); $user_company = new UserCompany($pdo_connection); foreach($users as $user) { $user_company->reset(); // начнем с чистого листа $user_company->user_id = $user->id; $user_company->company_id = $some_company_id; $user_company->insert(); }
getBuiltSql(): string
После выполнения методов find(), findAll(), insert(), update() или save() вы можете получить построенный SQL и использовать его в целях отладки.
find()
findAll()
insert()
update()
save()
select(string $field1 [, string $field2 ... ])
Вы можете выбирать только несколько столбцов из таблицы (это более производительно на очень широких таблицах с множеством столбцов).
$user->select('id', 'name')->find();
from(string $table)
Технически вы можете выбрать другую таблицу тоже! Почему бы и нет?!
$user->select('id', 'name')->from('user')->find();
join(string $table_name, string $join_condition)
Вы даже можете присоединиться к другой таблице в базе данных.
$user->join('contacts', 'contacts.user_id = users.id')->find();
where(string $where_conditions)
Вы можете установить некоторые пользовательские условия where (в этом where вы не можете устанавливать параметры)
$user->where('id=1 AND name="demo"')->find();
Примечание по безопасности - Вас может увлечь что-то вроде $user->where("id = '{$id}' AND name = '{$name}'")->find();. ПОЖАЛУЙСТА, НЕ ДЕЛАЙТЕ ЭТО!!! Это уязвимо для так называемых атак SQL-инъекций. В интернете есть много статей, пожалуйста, загуглите "sql injection attacks php", и вы найдете много статей по этой теме. Правильный способ обработки этого с использованием этой библиотеки заключается в том, что вместо этого метода where() вы бы сделали что-то вроде $user->eq('id', $id)->eq('name', $name)->find();. Если вам действительно нужно это сделать, библиотека PDO имеет $pdo->quote($var), чтобы экранировать его для вас. Только после использования quote() вы можете использовать его в операторе where().
$user->where("id = '{$id}' AND name = '{$name}'")->find();
where()
$user->eq('id', $id)->eq('name', $name)->find();
PDO
$pdo->quote($var)
quote()
group(string $group_by_statement)/groupBy(string $group_by_statement)
Группируйте ваши результаты по определенному условию.
$user->select('COUNT(*) as count')->groupBy('name')->findAll();
order(string $order_by_statement)/orderBy(string $order_by_statement)
Сортируйте возвращенный запрос определенным способом.
$user->orderBy('name DESC')->find();
limit(string $limit)/limit(int $offset, int $limit)
Ограничивают количество возвращаемых записей. Если передан второй int, это смещение, ограничение также как в SQL.
$user->orderby('name DESC')->limit(0, 10)->findAll();
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Где field = $value
field = $value
$user->eq('id', 1)->find();
notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Где `self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
CppI"родитель"hasMany`表示一对多关系。`self::HAS_ONE`表示一对一关系。`self::BELONGS_TO`表示从属关系。