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