Slug.php 2.81 KB
<?php
    
    namespace common\behaviors;
    
    use yii;
    use yii\base\Behavior;
    use yii\db\ActiveRecord;
    use dosamigos\transliterator\TransliteratorHelper;
    
    class Slug extends Behavior
    {
        
        public $in_attribute = 'name';
        
        public $out_attribute = 'alias';
        
        public $translit = true;
        
        public function events()
        {
            return [
                ActiveRecord::EVENT_BEFORE_INSERT => 'getSlug',
                ActiveRecord::EVENT_BEFORE_UPDATE => 'getSlug',
            ];
        }
        
        public function getSlug($event)
        {
            if(!empty( $this->owner->{$this->in_attribute} )) {
                if(empty( $this->owner->{$this->out_attribute} )) {
                    $this->owner->{$this->out_attribute} = $this->generateSlug($this->owner->{$this->in_attribute});
                } else {
                    $this->owner->{$this->out_attribute} = $this->generateSlug($this->owner->{$this->out_attribute});
                }
            }
            
        }
        
        private function generateSlug($slug)
        {
            $slug = $this->slugify($slug);
            if($this->checkUniqueSlug($slug)) {
                return $slug;
            } else {
                for($suffix = 2; !$this->checkUniqueSlug($new_slug = $slug . '-' . $suffix); $suffix++) {
                }
                return $new_slug;
            }
        }
        
        private function slugify($slug)
        {
            if($this->translit) {
                return yii\helpers\Inflector::slug(TransliteratorHelper::process($slug), '-', true);
            } else {
                return $this->slug($slug, '-', true);
            }
        }
        
        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;
        }
        
        private function checkUniqueSlug($slug)
        {
            /**
             * @var ActiveRecord $owner
             */
            $owner = $this->owner;
            $query = $owner->find()->where([
                $this->out_attribute => $slug,
            ]);
            if(!$owner->isNewRecord) {
                $pks = $owner->primaryKey();
                if(!empty($pks)) {
                    $pk_rules = ['and'];
                    foreach($pks as $pk) {
                        $pk_rules[] = [$pk => $owner->$pk];
                    }
                    $query->andWhere(['not', $pk_rules]);
                }
            }
            return !$query->exists();
        }
        
    }