|
@@ -0,0 +1,166 @@
|
|
|
+# Behavior
|
|
|
+
|
|
|
+**Behavior** - это объекты, которые позволяют расширять базовую функциональность классов **Yii2** без перенаследования оных, используя магические `__get` и `__call`.
|
|
|
+
|
|
|
+## Определение класса поведения
|
|
|
+
|
|
|
+```php
|
|
|
+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';
|
|
|
+ /**
|
|
|
+ * @inheritdoc
|
|
|
+ *
|
|
|
+ * In case, when the value is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
|
|
|
+ * will be used as value.
|
|
|
+ */
|
|
|
+ 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
|
|
|
+ *
|
|
|
+ * In case, when the [[value]] is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
|
|
|
+ * will be used as value.
|
|
|
+ */
|
|
|
+ protected function getValue($event)
|
|
|
+ {
|
|
|
+ if ($this->value === null) {
|
|
|
+ return time();
|
|
|
+ }
|
|
|
+ return parent::getValue($event);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Updates a timestamp attribute to the current timestamp.
|
|
|
+ *
|
|
|
+ * ```php
|
|
|
+ * $model->touch('lastVisit');
|
|
|
+ * ```
|
|
|
+ * @param string $attribute the name of the attribute to update.
|
|
|
+ * @throws InvalidCallException if owner is a new record (since version 2.0.6).
|
|
|
+ */
|
|
|
+ public function touch($attribute)
|
|
|
+ {
|
|
|
+ /* @var $owner BaseActiveRecord */
|
|
|
+ $owner = $this->owner;
|
|
|
+ if ($owner->getIsNewRecord()) {
|
|
|
+ throw new InvalidCallException('Updating the timestamp is not possible on a new record.');
|
|
|
+ }
|
|
|
+ $owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Пример выше - стандартное поведение `TimestampBehavior` из состава **Yii2**. Это поведение добавляет автоматическое заполнение полей `created_at` и `updated_at` при сохранении или изменении объектов `ActiveRecord` или унаследованных от `ActiveRecord`.
|
|
|
+
|
|
|
+Разберем свойства и методы этого класса:
|
|
|
+- `$createdAtAttribute` это имя свойства `ActiveRecord`, которое задается при создании записи в СУБД.
|
|
|
+- `$updatedAtAttribute` - стандартное имя свойства, которое заполняется при обновлении записи в СУБД.
|
|
|
+- `$value` - значение, которое используется для сохранении. По умолчанию значение времени, полученное через функцию `time()`
|
|
|
+- `init` - инициализирует обработку событий
|
|
|
+- `getValue` - возвращает `$value` или `time()`
|
|
|
+- `touch` - аналог POSIX-команды `touch`, которая "касается", т. е. обновляет время обновления записи.
|
|
|
+
|
|
|
+Определять включаемые в основной объект свойства можно слеюущим образом:
|
|
|
+
|
|
|
+```php
|
|
|
+class someBehavior
|
|
|
+ public $publicProperty; // свойство автоматически окажется в расширяемом объекте
|
|
|
+ private $getterSetterProperty; //свойство, как приватное, не доступно снаружи, однако доступно через геттеры и сеттеры:
|
|
|
+
|
|
|
+ public function getHiddenProperty(){
|
|
|
+ return $this->getterSetterProperty;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setHiddenProperty($value){
|
|
|
+ $this->getterSetterProperty = $value;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function funcFromBehavior(){ //публичная функция
|
|
|
+
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+## События
|
|
|
+
|
|
|
+Для обработки событий основного объекта нужно переопределить метод `events`:
|
|
|
+
|
|
|
+```php
|
|
|
+class someBehavior {
|
|
|
+ ...
|
|
|
+ public function events(){
|
|
|
+ return [
|
|
|
+ ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete'
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ public function beforeDelete($event){
|
|
|
+ //...
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+В конфигурации, указанной выше в `events`, при удалении будет вызван метод `beforeDelete`, который, например, может реализовывать каскадное удаление или удаление файлов на диске, связанных с записью (например, если запись о изображении, удалять файлы
|
|
|
+изображения разных размеров)
|
|
|
+
|
|
|
+## Прикрепление событий
|
|
|
+
|
|
|
+Для прикрепления в основном объекте задается метод `behaviors`, в котором указывается конфигурации в массиве с используемыми поведениями:
|
|
|
+
|
|
|
+```php
|
|
|
+class Img extends ActiveRecord
|
|
|
+{
|
|
|
+ public function behaviors()
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ someBehavior::className(),
|
|
|
+
|
|
|
+ [
|
|
|
+ 'class' => someBehavior::className(),
|
|
|
+ 'publicProperty' => 15,
|
|
|
+ 'hiddenProperty' => 100500
|
|
|
+ ]
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Так же можно задавать имена поведениям через ключи массива.
|
|
|
+
|
|
|
+### `attachBehavior` и `detachBehavior`
|
|
|
+
|
|
|
+Эти две функции позволяют подключать и отключать поведения "на горячую".
|
|
|
+
|
|
|
+## Использование поведений
|
|
|
+
|
|
|
+После подключения, публичные свойства, свойства, определенные через **геттеры** и **сеттеры**, а так же публичные методы становятся доступы *в основном объекте*.
|
|
|
+
|
|
|
+```php
|
|
|
+echo $someObjectWithBehavior->hiddenProperty;
|
|
|
+$someObjectWithBehavior->funcFromBehavior();
|
|
|
+```
|
|
|
+
|
|
|
+## Плюсы и минусы
|
|
|
+
|
|
|
+Это как трейты. но не трейты :-)
|
|
|
+
|