ArtboxSynonymBehavior.php 5.3 KB
<?php

namespace common\modules\rubrication\behaviors;

use common\modules\rubrication\models\TaxValueString;
use dosamigos\transliterator\TransliteratorHelper;
use yii\base\Behavior;
use yii\base\Exception;
use yii\db\ActiveRecord;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Inflector;
use yii\web\NotFoundHttpException;

class ArtboxSynonymBehavior extends Behavior {


    public $keyNameId;
    public $keyNameValue = 'default_value';
    /** @var  ActiveRecord $valueModel */
    public $valueModel = '\common\modules\rubrication\models\TaxValueString';
    public $valuePKey;
    public $valueOptionId = 'tax_option_id';
    public $valueFields = [];

    public $values = [];

    public $slug = null;

    /**
     * @param ActiveRecord $owner
     * @throws Exception
     */
    public function attach($owner)
    {
        parent::attach($owner);

        if ($this->keyNameId === null) {
            $primaryKey = $owner->primaryKey();
            if (!isset($primaryKey[0])) {
                throw new Exception('"' . $owner->className() . '" must have a primary key.');
            }
            $this->keyNameId = $primaryKey[0];
        }
    }

    /*
     * Inicialize behavior (read and prepare params)
     */
    public function init() {
        if (empty($this->valueModel)) {
            $this->valueModel = TaxValueString::className();
        }
        if (empty($this->valuePKey)) {
            $vm = $this->valueModel;
            $primaryKey = $vm::primaryKey();
            if (!isset($primaryKey[0])) {
                throw new Exception('"' . $this->valueModel . '" must have a primary key.');
            }
            if (count($primaryKey) > 1) {
                throw new Exception('"' . $this->valueModel . '" is contains multiple keys.');
            }
            $this->valuePKey = $primaryKey[0];
        }
    }

    /*
     * Events for auto-drive default value
     */
    public function events() {
        return [
            ActiveRecord::EVENT_AFTER_INSERT    => 'afterInsert',
            ActiveRecord::EVENT_AFTER_UPDATE    => 'beforeUpdate',
            ActiveRecord::EVENT_BEFORE_DELETE   => 'beforeDelete',
        ];
    }

    public function getAutoValue() {
        return $this->owner->hasOne($this->valueModel, [$this->valuePKey => $this->keyNameValue]);
    }

    public function afterInsert() {
        /** @var ActiveRecord $valueModel */
        $valueModel = new $this->valueModel;
        foreach ($this->valueFields as $key => $field) {
            $valueModel->setAttribute($field, $this->$key);
        }
        $valueModel->setAttribute($this->valueOptionId, $this->owner->getAttribute($this->keyNameId));
        $valueModel->save();
        $this->owner->setAttribute($this->keyNameValue, $valueModel->getAttribute($this->valuePKey));
        $this->owner->{$this->slug['slugKeyName']} = $this->slugify($valueModel->{$this->slug['valueKeyName']});
        $this->owner->save(false);
    }

    public function beforeUpdate() {
        if ($this->owner->getIsNewRecord()) {
            throw new NotSupportedException('Method "' . $this->owner->className() . '::insert" is not supported for inserting new entitys.');
        }

        if (!$this->owner->getAttribute($this->keyNameValue)) {
            return;
        }

        /** @var ActiveRecord $valueModel */
        $valueModelName = $this->valueModel;
        $valueModel = $valueModelName::findOne($this->owner->getAttribute($this->keyNameValue));

        $isave = false;
        foreach ($this->valueFields as $key => $field) {
            if ($valueModel->getAttribute($field) == $this->$key) {
                continue;
            }
            $isave = true;
            $valueModel->setAttribute($field, $this->$key);
        }
        if ($isave) {
            $valueModel->setAttribute($this->valueOptionId, $this->owner->getAttribute($this->keyNameId));
            $valueModel->save();
            if (!empty($this->slug) && empty($this->owner->{$this->slug['slugKeyName']})) {
                $this->owner->{$this->slug['slugKeyName']} = $this->slugify($valueModel->{$this->slug['valueKeyName']});
            }
        }
    }

    public function beforeDelete() {
        /** @var ActiveRecord $valueModel */
        $valueModelName = $this->valueModel;
        $valueModelName::deleteAll([
            $this->valueOptionId => $this->owner->getAttribute($this->keyNameId)
        ]);
    }

    private function slugify( $slug )
    {
        return  Inflector::slug( TransliteratorHelper::process( $slug ), '-', true );
    }

    /**
     * @inheritdoc
     */
    public function canSetProperty($key, $checkVars = true)
    {
        return array_key_exists($key, $this->valueFields) ?
            true : parent::canSetProperty($key, $checkVars = true);
    }

    /**
     * @inheritdoc
     */
    public function __set($key, $value) {
        if (isset($this->valueFields[$key])) {
            $this->values[$key] = $value;
        }
    }

    /**
     * @inheritdoc
     */
    public function __get($key) {
        return $this->_getValue($key);
    }

    public function _getValue($key) {
        if (isset($this->values[$key])) {
            return $this->values[$key];
        }
    }
}