You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					137 lines
				
				2.5 KiB
			
		
		
			
		
	
	
					137 lines
				
				2.5 KiB
			| 
											7 years ago
										 | <?php
 | ||
|  | /**
 | ||
|  |  * Created by Error202
 | ||
|  |  * Date: 28.08.2018
 | ||
|  |  */
 | ||
|  | 
 | ||
|  | namespace core\behaviors;
 | ||
|  | 
 | ||
|  | 
 | ||
|  | use yii\base\Behavior;
 | ||
|  | use yii\db\ActiveRecord;
 | ||
|  | use yii\validators\UniqueValidator;
 | ||
|  | use yii\helpers\Inflector;
 | ||
|  | use Yii;
 | ||
|  | 
 | ||
|  | class SluggableRelationBehavior extends Behavior
 | ||
|  | {
 | ||
|  | 	/**
 | ||
|  | 	 * Source attribute for generate slug
 | ||
|  | 	 * @var string
 | ||
|  | 	 */
 | ||
|  | 	public $attribute;
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Field name for slug
 | ||
|  | 	 * @var string
 | ||
|  | 	 */
 | ||
|  | 	public $slugAttribute = 'slug';
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Relation name, if attribute from relative table
 | ||
|  | 	 * @var string
 | ||
|  | 	 */
 | ||
|  | 	public $relation;
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * Generate slug if slugAttribute is empty
 | ||
|  | 	 * @var bool
 | ||
|  | 	 */
 | ||
|  | 	public $slugIfEmpty = true;
 | ||
|  | 
 | ||
|  | 	public function events()
 | ||
|  | 	{
 | ||
|  | 		return [
 | ||
|  | 			ActiveRecord::EVENT_AFTER_UPDATE => 'afterUpdate',
 | ||
|  | 			ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert',
 | ||
|  | 		];
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	public function afterInsert()
 | ||
|  | 	{
 | ||
|  | 		$this->addSlug();
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	public function afterUpdate()
 | ||
|  | 	{
 | ||
|  | 		if (!$this->owner->{$this->slugAttribute}) {
 | ||
|  | 			$this->addSlug();
 | ||
|  | 		}
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	private function addSlug()
 | ||
|  | 	{
 | ||
|  | 		/** @var ActiveRecord $owner */
 | ||
|  | 		$owner = $this->owner;
 | ||
|  | 
 | ||
|  | 		if (!$this->isNewSlugNeeded()) {
 | ||
|  | 			$slug =  $owner->{$this->slugAttribute};
 | ||
|  | 		}
 | ||
|  | 		else {
 | ||
|  | 			if ($this->relation) {
 | ||
|  | 				$attribute = $owner->{$this->relation}->{$this->attribute};
 | ||
|  | 				$slug = $this->generateSlug($attribute);
 | ||
|  | 				$slug = $this->makeUnique($slug);
 | ||
|  | 			}
 | ||
|  | 			else {
 | ||
|  | 				$attribute = $owner->{$this->attribute};
 | ||
|  | 				$slug = $this->generateSlug($attribute);
 | ||
|  | 				$slug = $this->makeUnique($slug);
 | ||
|  | 			}
 | ||
|  | 		}
 | ||
|  | 		$owner->{$this->slugAttribute} = $slug;
 | ||
|  | 		$owner->save();
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	protected function generateSlug($attribute)
 | ||
|  | 	{
 | ||
|  | 		return Inflector::slug($attribute);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	protected function isNewSlugNeeded()
 | ||
|  | 	{
 | ||
|  | 		if (empty($this->owner->{$this->slugAttribute})) {
 | ||
|  | 			return true;
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if (!empty($this->owner->{$this->slugAttribute}) && !$this->slugIfEmpty) {
 | ||
|  | 			return true;
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		return false;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	protected function makeUnique($slug)
 | ||
|  | 	{
 | ||
|  | 		$uniqueSlug = $slug;
 | ||
|  | 		$iteration = 0;
 | ||
|  | 		while (!$this->validateSlug($uniqueSlug)) {
 | ||
|  | 			$iteration++;
 | ||
|  | 			$uniqueSlug = $this->generateUniqueSlug($slug, $iteration);
 | ||
|  | 		}
 | ||
|  | 		return $uniqueSlug;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	protected function generateUniqueSlug($baseSlug, $iteration)
 | ||
|  | 	{
 | ||
|  | 		return $baseSlug . '-' . ($iteration + 1);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	protected function validateSlug($slug)
 | ||
|  | 	{
 | ||
|  | 		/* @var $validator UniqueValidator */
 | ||
|  | 		/* @var $model ActiveRecord */
 | ||
|  | 		$validator = Yii::createObject(array_merge(
 | ||
|  | 			[
 | ||
|  | 				'class' => UniqueValidator::class,
 | ||
|  | 			]
 | ||
|  | 		));
 | ||
|  | 
 | ||
|  | 		$model = clone $this->owner;
 | ||
|  | 		$model->clearErrors();
 | ||
|  | 		$model->{$this->slugAttribute} = $slug;
 | ||
|  | 
 | ||
|  | 		$validator->validateAttribute($model, $this->slugAttribute);
 | ||
|  | 		return !$model->hasErrors();
 | ||
|  | 	}
 | ||
|  | }
 |