17 changed files with 261 additions and 26 deletions
			
			
		@ -0,0 +1,137 @@ | 
				
			|||||||
 | 
					<?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(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue