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
						
					
					
				| <?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(); | |
| 	} | |
| } |