Статьи

Как программировать с Yii2: ActiveRecord

Конечный продукт
Что вы будете создавать

Если вы спрашиваете: «Что такое Yii?» Посмотрите мой предыдущий учебник: Введение в Yii Framework , который рассматривает преимущества Yii и содержит обзор изменений в Yii 2.0, выпущенном в октябре 2014 года.

В этой серии «Программирование с Yii2» я расскажу читателям, как использовать Yii2 Framework для PHP. В сегодняшнем уроке я расскажу вам об использовании объектно-реляционного отображения Yii, известного как ORM, для работы с базами данных. Он называется Active Record и является ключевым аспектом эффективного программирования приложений баз данных в Yii.

Yii предлагает различные способы программной работы с вашей базой данных, такие как прямые запросы и построитель запросов , но использование Active Record предлагает полный набор преимуществ для объектно-ориентированного программирования баз данных. Ваша работа становится более эффективной, более безопасной, работает в архитектуре контроллера представления модели Yii и переносима, если вы решите переключить платформы баз данных (например, MySQL на PostgreSQL).

Следуйте, как я подробно излагаю основы Active Record в Yii.

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

Контроллер представления модели Yii — одно из его ключевых преимуществ. Active Record предоставляет объектно-ориентированное решение для работы с базами данных, которое тесно интегрировано с моделями Yii. Согласно Wikipedia , общий термин Active Record был назван Мартином Фаулером в его книге 2003 года « Шаблоны архитектуры корпоративных приложений ».

В документации по Yii это краткое изложение:

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

Интеграция паттернов Active Record в Yii является сильной стороной фреймворка, но она характерна для большинства фреймворков, таких как Ruby on Rails.

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

Поддержка Active Record в Yii также обеспечивает переносимость между несколькими базами данных. Вы можете переключать базы данных без необходимости менять много кода:

  • MySQL 4.1 или более поздняя версия
  • PostgreSQL 7.3 или более поздняя версия
  • SQLite 2 и 3
  • Microsoft SQL Server 2008 или более поздняя версия
  • CUBRID 9,3 или позже
  • оракул
  • Сфинкс: через yii \ sphinx \ ActiveRecord , требуется расширение yii2-sphinx
  • ElasticSearch: через yii \asticsearch \ ActiveRecord , требуется расширение yii2-elasticsearch

И следующие базы данных NoSQL:

В предыдущем выпуске « Как программировать на Yii2: работа с базой данных и активной записью» я прошел через создание базы данных, как Yii подключается к ней для каждого сеанса, с помощью миграции для создания таблиц базы данных и с помощью Gii (полезный код Yii). генератор строительных лесов) для создания кода модели по умолчанию. Если вы не знакомы с этим, просмотрите этот эпизод.

В этом выпуске я сосредоточусь больше на использовании Active Record в вашем коде.

Во-первых, давайте рассмотрим, как преобразовать модель Yii для использования Active Record. Я буду использовать пример модели, которую я создал в серии Building Your Startup . Из этой серии вы узнаете, как я создаю свой стартап, Meeting Planner , в Yii2.

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

Программирование активной записи Yii2 - пример сбора электронной почты при запуске домашней страницы

Использовать Active Record с моделью довольно просто; обратите внимание, что class Launch extends \yii\db\ActiveRecord :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
 
namespace frontend\models;
 
use Yii;
use yii\db\ActiveRecord;
 
 
/**
 * This is the model class for table «launch».
 *
 * @property integer $id
 * @property string $email
 * @property string $ip_addr
 * @property integer $status
 * @property integer $created_at
 * @property integer $updated_at
 */
class Launch extends \yii\db\ActiveRecord
{
  const STATUS_REQUEST =0;
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return ‘launch’;
    }

Вот и все.

Давайте посмотрим на некоторые распространенные запросы Active Record.

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

1
2
3
public function actionSomething($id)
{
  $model = Launch::findOne($id);

Это идентично:

1
2
3
$model = Launch::find()
   ->where([‘id’ => $id])
   ->one();

Вы также можете расширить массив ->where дополнительными полями или логическими условиями:

01
02
03
04
05
06
07
08
09
10
$model = Launch::find()
    ->where([‘id’ => $id,’status’=>Launch::ACTIVE_REQUEST])
    …
     
//equivalent to
$model = Launch::find()
    ->where([‘id’ => $id)
    ->andWhere([‘status’=>Launch::ACTIVE_REQUEST])
    ->orWhere([‘status’=>Launch::FUTURE_REQUEST])
    …

Вот пример поиска всех записей, которые соответствуют определенному status отсортированных по $id :

1
2
3
4
$people = Launch::find()
 ->where([‘status’ => Launch::STATUS_REQUEST])
 ->orderBy(‘id’)
 ->all();

->all(); находит все записи вместо одной. Переменная $people возвращается как массив объектов модели. Кроме того, когда нет условий, вы можете получить доступ ко всем записям с помощью ->findAll();

Использование indexBy возвращает массив элементов, проиндексированных по их id :

1
2
3
$people = Launch::find()
   ->indexBy(‘id’)
   ->all();

Кроме того, вы можете вернуть ассоциативный массив с помощью ->asArray() :

1
2
3
$people = Launch::find()
   ->asArray()
   ->all();

Примечание. Документация Yii гласит: «Хотя этот метод экономит память и повышает производительность, он ближе к нижнему уровню абстракции БД, и вы потеряете большинство функций Active Record».

Вы также можете вернуть только count из запроса:

1
2
3
$count = Launch::find()
   ->where([‘status’ => Launch::STATUS_REQUEST])
   ->count();

Например, я часто использую счетчики в Meeting Planner для статистики; узнать больше в нашем эпизоде ​​Dashboard :

1
2
3
4
5
6
7
8
// calculate $count_meetings_completed
$hd->count_meetings_completed = Meeting::find()->where([‘status’=>Meeting::STATUS_COMPLETED])->andWhere(‘created_at<‘.$since)->count();;
// calculate $count_meetings_expired
$hd->count_meetings_expired = Meeting::find()->where([‘status’=>Meeting::STATUS_EXPIRED])->andWhere(‘created_at<‘.$since)->count();;
// calculate $count_meetings_planning
$hd->count_meetings_planning = Meeting::find()->where(‘status<‘.Meeting::STATUS_COMPLETED)->andWhere(‘created_at<‘.$since)->count();;
// calculate $count_places
$hd->count_places = Place::find()->where(‘created_at>’.$after)->andWhere(‘created_at<‘.$since)->count();

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

1
2
3
$model = Launch::findOne($id);
$id = $model->id;
$email = $model->email;

Я часто обрабатываю массивы так:

1
2
3
4
$users = User::findAll();
foreach ($users as $u) {
 $id = $u->id;
 $email = $u->email;

Вы также можете быстро назначить массив записи модели через ActiveRecord:

1
2
3
4
5
6
7
$values = [
    ‘name’ => ‘James’,
    ’email’ => ‘james@example.com’,
];
$customer = new Customer();
$customer->attributes = $values;
$customer->save();

Это часто используется для заполнения данных модели после отправки формы :

1
2
3
4
5
6
if (isset($_POST[‘FormName’])) {
    $model->attributes = $_POST[‘FormName’];
    if ($model->save()) {
        // handle success
    }
}

Или вы можете использовать ->load() для этого:

1
2
3
if ($model->load(Yii::$app->request->post()) && $model->save()) {
}

Генератор кода Gii из Yii прекрасно подходит для генерации моделей с использованием ActiveRecord, которые делают это за вас, например, модели, контроллеры, формы, представления и т. Д.

Как вы можете видеть выше, сохранение данных с помощью Active Record также легко. В этом примере из документации по Yii создается и сохраняется новая запись, а затем запись загружается по id и сохраняются обновления:

01
02
03
04
05
06
07
08
09
10
// insert a new row of data
$customer = new Customer();
$customer->name = ‘James’;
$customer->email = ‘james@example.com’;
$customer->save();
 
// update an existing row of data
$customer = Customer::findOne(123);
$customer->email = ‘james@newexample.com’;
$customer->save();

Удалить запись еще проще:

1
2
$u = User::findOne(99);
$u->delete();

Yii также предлагает простой счетчик приращений. Допустим, пользователь планирует другое собрание, и я отслеживаю, сколько в пользовательской таблице:

1
2
3
4
$u = User::findOne(99);
$u->updateCounters([‘meeting_count’=>1]);
// equivalent to
// UPDATE `User` SET `meeting_count` = `meeting_count` + 1 WHERE `id` = 99

Соединение таблиц между индексами — одна из самых мощных возможностей Active Record. Например, в Планировщике собраний каждое собрание может иметь 0 или более мест MeetingPlaces . Модель Meeting.php определяет для этого реляционный ActiveQuery:

1
2
3
4
5
6
7
8
* @property MeetingPlace[] $meetingPlaces
/**
 * @return \yii\db\ActiveQuery
 */
public function getMeetingPlaces()
{
    return $this->hasMany(MeetingPlace::className(), [‘meeting_id’ => ‘id’]);
}

Затем я могу получить доступ ко всем местам встречи с $meetingPlaces свойства $meetingPlaces . Ниже я загружаю собрание и перебираю все его meetingPlaces довольно легко, как если бы это был встроенный массив meetingPlaces :

1
2
3
4
$mtg=Meeting::find()->where([‘id’=>$meeting_id])->one();
foreach ($mtg->meetingPlaces as $mp) {
  …
}

Конечно, это зависит от создания внешнего ключа при создании таблицы при ее миграции:

01
02
03
04
05
06
07
08
09
10
11
12
$this->createTable(‘{{%meeting_place}}’, [
         ‘id’ => Schema::TYPE_PK,
         ‘meeting_id’ => Schema::TYPE_INTEGER.’
         ‘place_id’ => Schema::TYPE_INTEGER.’
         ‘suggested_by’ => Schema::TYPE_BIGINT.’
         ‘status’ => Schema::TYPE_SMALLINT .
         ‘created_at’ => Schema::TYPE_INTEGER .
         ‘updated_at’ => Schema::TYPE_INTEGER .
     ], $tableOptions);
     $this->addForeignKey(‘fk_meeting_place_meeting’,
       ‘{{%meeting_place}}’, ‘meeting_id’, ‘{{%meeting}}’,
       ‘id’, ‘CASCADE’, ‘CASCADE’);

Я надеюсь, что это дало легкое введение в удивительность Active Record. Сюда также входят жизненные циклы, транзакции и блокировки, о которых я могу написать в будущем. Если вы хотите двигаться вперед, Yii2 предлагает две отличные области для получения дополнительной информации в своей документации: Руководство по активной записи Yii2 и функциональные спецификации активной записи Yii2 . Это хорошо написанные введения.

Следите за будущими уроками в серии « Программирование с Yii2», поскольку мы продолжаем изучать различные аспекты фреймворка. Вы также можете проверить вышеупомянутую серию «Создание стартапа на PHP» .

Если вы хотите узнать, когда появится следующий учебник по Yii2, следуйте за мной @reifman в Твиттере или зайдите на страницу моего инструктора .