Статьи

Как программировать с Yii2: поведение метки времени

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

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

В этой серии «Программирование с Yii2» я расскажу читателям, как использовать обновленную версию Yii2 Framework для PHP. В этом руководстве мы рассмотрим поведение временных меток, которое сокращает объем кода, который необходимо писать для каждой новой модели, для общей операции создания временных меток для вставок и обновлений. Мы также погрузимся в исходный код Yii2, исследуя, как реализовано поведение.

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

Просто напоминание, я участвую в комментариях ниже. Мне особенно интересно, если у вас есть другие подходы, дополнительные идеи или вы хотите предложить темы для будущих уроков.

Yii2 Поведения по сути являются миксинами . Википедия описывает миксины как «класс, который содержит комбинацию методов из других классов. То, как такая комбинация выполняется, зависит от языка, но не от наследования».

Yii описывает их так:

Присоединение поведения к компоненту «внедряет» методы и свойства поведения в компонент, делая эти методы и свойства доступными, как если бы они были определены в самом классе компонента.

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

Поведение Timestamp позволяет нам легко реализовать часто необходимую задачу назначения текущей даты и времени для вставок и обновлений в модели ActiveRecord, автоматически устанавливая свойства для created_at и updated_at .

Ранее в этой серии мы реализовали временную метку вручную. Всякий раз, когда модели состояния были опубликованы пользователем, отправляющим форму, мы назначали текущую временную метку Unix обоим полям:

01
02
03
04
05
06
07
08
09
10
11
12
13
public function actionCreate()
   {
       $model = new Status();
 
       if ($model->load(Yii::$app->request->post())) {
         $model->created_at = time();
         $model->updated_at = time();
          if ($model->save()) {
            return $this->redirect([‘view’, ‘id’ => $model->id]);
          } else {
            var_dump ($model->getErrors());
          }
       }

Реализация поведения Timestamp сделает это автоматически для нас и может быть легко добавлена ​​ко всем моделям ActiveRecord в веб-приложении.

Почти у каждой модели, которую я создаю в Yii, есть поля created_at и updated_at . Это хорошая практика. Таким образом, поведение Timestamp полезно практически в каждой модели.

В models/Status.php мы добавляем TimestampBehavior после Sluggable и Blameable :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function behaviors()
         {
             return [
                 [
                     ‘class’ => SluggableBehavior::className(),
                     ‘attribute’ => ‘message’,
                     ‘immutable’ => true,
                     ‘ensureUnique’=>true,
                 ],
                 [
                     ‘class’ => BlameableBehavior::className(),
                     ‘createdByAttribute’ => ‘created_by’,
                     ‘updatedByAttribute’ => ‘updated_by’,
                 ],
                 ‘timestamp’ => [
                     ‘class’ => ‘yii\behaviors\TimestampBehavior’,
                     ‘attributes’ => [
                         ActiveRecord::EVENT_BEFORE_INSERT => [‘created_at’, ‘updated_at’],
                         ActiveRecord::EVENT_BEFORE_UPDATE => [‘updated_at’],
                     ],
                 ],
             ];
         }

Мы также должны включить класс ActiveRecord в начало нашей модели (я всегда забываю эту часть):

1
2
3
4
5
6
7
8
<?php
 
namespace app\models;
 
use Yii;
use yii\db\ActiveRecord;
use yii\behaviors\SluggableBehavior;
use yii\behaviors\BlameableBehavior;

Затем мы удаляем обязательное правило для created_at и updated_at в правилах модели:

1
2
3
4
5
6
7
8
public function rules()
   {
       return [
           [[‘message’, ‘created_at’, ‘updated_at’], ‘required’],
           [[‘message’], ‘string’],
           [[‘permissions’, ‘created_at’, ‘updated_at’,’created_by’], ‘integer’]
       ];
   }

Как это:

1
2
3
4
5
6
7
8
public function rules()
   {
       return [
           [[‘message’], ‘required’],
           [[‘message’], ‘string’],
           [[‘permissions’, ‘created_at’, ‘updated_at’,’created_by’], ‘integer’]
       ];
   }

Это позволяет валидации пройти успешно и перейти к поведению.

Нам также необходимо удалить назначения StatusController create_at и updated_at в действии create:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public function actionCreate()
   {
       $model = new Status();
 
       if ($model->load(Yii::$app->request->post())) {
          if ($model->save()) {
            return $this->redirect([‘view’, ‘id’ => $model->id]);
          } else {
            var_dump ($model->getErrors());
          }
       }
       return $this->render(‘create’, [
           ‘model’ => $model,
       ]);
   }

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

Создание записи Status теперь, когда мы прикрепили поведение Timestamp

И результирующее представление показывает настройки созданного и updated_at , сделанные поведением Timestamp.

Просмотр результатов Timestamp Behavior на нашей модели статуса

Поведение Timestamp также предоставляет метод с именем touch() который позволяет назначать текущую метку времени указанным атрибутам и сохранять их в базе данных.

1
$model->touch(‘updated_at’);

Например, если у вас есть фоновое задание cron, которое выполняет некоторую обработку таблицы состояния, у вас может быть last_processed_at времени last_processed_at которой вы прикрепляете поведение. Каждый раз, когда запускается задание cron, вы должны коснуться этого поля

1
$model->touch(‘last_processed_at’);

Поскольку Yii2 теперь поддерживает соглашения об именах PSR-4 , проще погрузиться в код инфраструктуры, чтобы увидеть, как он работает. Давайте посмотрим на код TimestampBehavior чтобы понять, как он реализован.

Код связан с GitHub со страницы документации :

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class TimestampBehavior extends AttributeBehavior
{
    /**
     * @var string the attribute that will receive timestamp value
     * Set this property to false if you do not want to record the creation time.
     */
    public $createdAtAttribute = ‘created_at’;
    /**
     * @var string the attribute that will receive timestamp value.
     * Set this property to false if you do not want to record the update time.
     */
    public $updatedAtAttribute = ‘updated_at’;
    /**
     * @var callable|Expression The expression that will be used for generating the timestamp.
     * This can be either an anonymous function that returns the timestamp value,
     * or an [[Expression]] object representing a DB expression (eg `new Expression(‘NOW()’)`).
     * If not set, it will use the value of `time()` to set the attributes.
     */
    public $value;
    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        if (empty($this->attributes)) {
            $this->attributes = [
                BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
                BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
            ];
        }
    }
    /**
     * @inheritdoc
     */
    protected function getValue($event)
    {
        if ($this->value instanceof Expression) {
            return $this->value;
        } else {
            return $this->value !== null ?
        }
    }
    /**
     * Updates a timestamp attribute to the current timestamp.
     *
     * «`php
     * $model->touch(‘lastVisit’);
     * «`
     * @param string $attribute the name of the attribute to update.
     */
    public function touch($attribute)
    {
        $this->owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
    }
}

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

1
2
public $createdAtAttribute = ‘created_at’;
public $updatedAtAttribute = ‘updated_at’;

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

01
02
03
04
05
06
07
08
09
10
public function init()
   {
       parent::init();
       if (empty($this->attributes)) {
           $this->attributes = [
               BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
               BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
           ];
       }
   }

Вы можете прочитать больше о событиях Yii2 ActiveRecord здесь .

Метод getValue возвращает текущую метку времени для атрибута, если он не определен:

1
2
3
4
5
6
7
8
protected function getValue($event)
   {
       if ($this->value instanceof Expression) {
           return $this->value;
       } else {
           return $this->value !== null ?
       }
   }

По умолчанию TimestampBehavior будет заполнять атрибуты created_at и updated_at текущей отметкой времени при вставке связанного объекта. Он будет заполнять атрибут updated_at отметкой времени при обновлении объекта. Если пользовательская функция не назначена, она использует функцию PHP time() , которая возвращает текущую временную метку Unix.

Он также реализует touch метод для определенных атрибутов:

01
02
03
04
05
06
07
08
09
10
11
12
/**
    * Updates a timestamp attribute to the current timestamp.
    *
    * «`php
    * $model->touch(‘lastVisit’);
    * «`
    * @param string $attribute the name of the attribute to update.
    */
   public function touch($attribute)
   {
       $this->owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
   }

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

Надеюсь, вам понравилось изучать поведение меток времени Yii2 и изучать исходный код Yii2.

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

Я приветствую тематические и тематические запросы. Вы можете опубликовать их в комментариях ниже или написать мне по электронной почте на моем сайте Lookahead Consulting .

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