'getSlug', ActiveRecord::EVENT_AFTER_UPDATE => 'getSlug', ActiveRecord::EVENT_BEFORE_DELETE => 'deleteSlug', ]; } /** * @inheritdoc */ public function attach($owner) { parent::attach($owner); if (!$owner instanceof ActiveRecord) { throw new yii\base\InvalidConfigException( \Yii::t('core', 'SlugBeahvior can only be attached to the instance of ActiveRecord') ); } } /** * Generate slug * * @param yii\base\Event $event * * @return void */ public function getSlug($event) { /** * @var string $attribute_value */ $attribute_value = $this->owner->getAttribute($this->inAttribute); if (!empty($attribute_value)) { /** * @var string $alias_value */ $alias_value = $this->aliasValue; $this->currentAlias = $this->findCurrentAlias(); if (empty($alias_value)) { $result = $this->generateSlug($attribute_value); } else { $result = $this->generateSlug($alias_value); } $this->saveSlug($result); } } /** * Delete slug * * @param yii\base\Event $event * * @return void */ public function deleteSlug($event) { if (!empty($current = $this->findCurrentAlias())) { $current->delete(); } } /** * Get current Alias. Db query will be made first time or if $force flag is set. * * @param bool $force * * @return \artbox\core\models\Alias|null */ public function findCurrentAlias($force = false) { if ($force || !$this->executed) { /** * @var int $alias_id */ $alias_id = $this->owner->getAttribute($this->outAttribute); $currentAlias = null; if (!empty($alias_id)) { /** * @var Alias|null $currentAlias */ $currentAlias = Alias::find() ->where( [ 'id' => $alias_id, ] ) ->one(); } $this->executed = true; return $currentAlias; } else { return $this->currentAlias; } } /** * Generate unique slug. * * @param string $slug * * @return string */ private function generateSlug($slug) { $slug = $this->slugify($slug); $languageId = null; if ($this->owner->hasAttribute('language_id')) { $languageId = $this->owner->getAttribute('language_id'); } return SlugHelper::unify($slug, $this->currentAlias, $languageId); } /** * Generate slug from string according to $translit flag. * * @param string $slug * * @return string */ private function slugify($slug) { if ($this->translit) { return SlugHelper::slugify($slug); } else { return $this->slug($slug, '-', true); } } /** * Replace non-alphabetic symbols with $replcement symbol. * * @param string $string * @param string $replacement * @param bool $lowercase * * @return string */ private function slug($string, $replacement = '-', $lowercase = true) { $string = preg_replace('/[^\p{L}\p{Nd}]+/u', $replacement, $string); $string = trim($string, $replacement); return $lowercase ? strtolower($string) : $string; } /** * Check if $slug differs from current Alias value * * @param $slug * * @return bool */ private function hasChanged($slug) { if (!empty($this->currentAlias) && $this->currentAlias->value === $slug) { return false; } else { return true; } } /** * If $slug differs from Db Alias value, updates current if exists or create new Alias row. * * @param $slug * * @throws \yii\base\ErrorException */ protected function saveSlug($slug) { if (!$this->hasChanged($slug)) { return; } else { $route = $this->buildRoute(); $owner = $this->owner; if (empty($alias = $this->findCurrentAlias())) { /** * @var Alias $alias */ $alias = \Yii::createObject( Alias::className(), [ [ 'value' => $slug, 'route' => $route, 'entity' => $owner::className(), 'title' => $owner->getAttribute($this->inAttribute), 'h1' => $owner->getAttribute($this->inAttribute), 'fields' => Json::encode($this->fields), 'language_id' => $owner->getAttribute('language_id'), ], ] ); } else { $alias->value = $slug; $alias->route = $route; $alias->entity = $owner::className(); $alias->language_id = $owner->getAttribute('language_id'); } if ($alias->save()) { $owner->{$this->outAttribute} = $alias->id; $this->detach(); $owner->save(false, [ $this->outAttribute ]); } else { $alias = Alias::find() ->where( [ 'route' => $alias->route, 'language_id' => $alias->language_id, ] ) ->one(); if ($alias) { $owner->{$this->outAttribute} = $alias->id; $this->detach(); $owner->save(false, [ $this->outAttribute ]); } else { throw new ErrorException( \Yii::t( 'core', 'Alias cannot be saved: ' . Json::encode($alias) . '. Errors: ' . Json::encode( $alias->getErrors() ) ) ); } } } } /** * Get $aliasValue. Try to get from cached value and tries to get from Db if empty. * * @return string */ public function getAliasValue() { if (empty($this->aliasValue) && !$this->executed) { $currentAlias = $this->findCurrentAlias(); if (!empty($currentAlias)) { $this->aliasValue = $currentAlias->value; return $currentAlias->value; } } return $this->aliasValue; } /** * Set $aliasValue * * @param $value */ public function setAliasValue($value) { $this->aliasValue = $value; } /** * Build Json route from $action and $params fields. * * @return null|string */ protected function buildRoute() { $owner = $this->owner; $route = []; $action = $this->action; if (empty($action)) { return null; } else { $route[ 0 ] = $action; } $params = $this->params; if (!empty($params) && is_array($params)) { foreach ($params as $param => $attribute) { $attributeValue = $owner->getAttribute($attribute); if (!empty($attributeValue)) { $route[ $param ] = $attributeValue; } } } return Json::encode($route); } }