UrlManager.php 4.69 KB
<?php

namespace frontend\components;

use artbox\core\models\Alias;
use artbox\core\models\Language;
use artbox\core\services\Languages;
use yii\helpers\Json;
use yii\web\NotFoundHttpException;
use yii\web\Request;


/**
 * Url manager extended to work with aliases and languages
 *
 * @package artbox\core\seo
 */
class UrlManager extends \yii\web\UrlManager
{
	/**
	 * @var bool
	 */
	public $hideDefaultLanguagePrefix = false;

	/**
	 * @see \yii\web\UrlManager
	 * @var bool
	 */
	public $enablePrettyUrl = true;

	/**
	 * @see \yii\web\UrlManager
	 * @var bool
	 */
	public $showScriptName = false;

	/**
	 * @var \artbox\core\services\Languages
	 */
	protected $languages;

	/**
	 * UrlManager constructor.
	 *
	 * @param \artbox\core\services\Languages $languages
	 * @param array $config
	 */

	public $params = [
		'id' => 'id',
		'page' => 'page',
		'per-page' => 'per_page',
		'book_id' => 'book_id',
		'q' => 'q',
		'tag' => 'tag',
	];

	public function __construct(Languages $languages, array $config = [])
	{
		$this->languages = $languages;

		parent::__construct($config);
	}

	/**
	 * @param \yii\web\Request $request
	 *
	 * @return array|bool
	 * @throws \artbox\core\exceptions\AliasOverwriteException
	 * @throws \yii\base\ExitException
	 * @throws \yii\base\InvalidConfigException
	 */
	public function parseRequest($request)
	{
		$redirect = $this->checkRedirect($request->url);

		if ($redirect !== null) {

			\Yii::$app->response->redirect("/" . $redirect->value, 301);
		}
		$request = $this->parseLanguage($request);
		$path = $request->pathInfo;

		if (strlen($path) && $path[strlen($path) - 1] == '/'
			#    && $path[strlen($path)-2]=='/'
		) {
			throw new NotFoundHttpException();
		}


		/**
		 * @var Alias $alias
		 */
		$alias = Alias::find()
			->where(
				[
					'value' => trim($request->pathInfo, '/'),
				]
			)
			->andWhere(
				[
					'language_id' => $this->languages->getCurrent()->id,
				]
			)
			->one();
		$this->invalidParams(\Yii::$app->request->queryParams);
		if ($alias !== null) {
			$params = Json::decode($alias->route);

			$route = array_shift($params);

			/**
			 * @todo REFACTOR AS SOO AS POSIBLE!
			 *       remove service locator, and implement Dependency Injection
			 * @var \artbox\core\components\SeoComponent $seo
			 */
			$seo = \Yii::$app->get('seo');
			$seo->setAlias($alias);
			return [
				$route,
				$params,
			];
		}

		return parent::parseRequest($request);
	}

	/**
	 * @param array|string $params
	 *
	 * @return string
	 */
	public function createUrl($params)
	{
		if ($this->hideDefaultLanguagePrefix && ($this->languages->getCurrent()->url == $this->languages->getDefault()->url)) {
			$prefix = '';
		} else {
			$prefix = '/' . $this->languages->getCurrent()->url;
		}

		if (isset($params['alias'])) {
			if ($params['alias'] instanceof Alias) {
				return $prefix . '/' . $params['alias']->value;
			} elseif (is_array($params['alias'])) {
				return $prefix . '/' . $params['alias']['value'];
			}
		}

		return $prefix . parent::createUrl($params);
	}

	/**
	 * @param $request
	 *
	 * @return mixed
	 * @throws \yii\base\ExitException
	 * @throws \yii\base\InvalidConfigException
	 */
	protected function parseLanguage(Request $request)
	{
		$split = explode('/', $request->pathInfo);
		if (in_array($split[0], array_keys($this->languages->getActive()))) {
			if ($this->hideDefaultLanguagePrefix && ($split[0] == $this->languages->getDefault()->url)) {
				unset($split[0]);

				\Yii::$app->response->redirect('/' . implode('/', $split), 301)
					->send();
				\Yii::$app->end();
			} else {
				$this->languages->setCurrent($split[0]);

				unset($split[0]);

				$request->setPathInfo(implode('/', $split));
			}
		} else {
			if ($this->hideDefaultLanguagePrefix) {
				$this->languages->setCurrentDefault();
			} else {
				\Yii::$app->response->redirect(
					'/' . $this->languages->getDefault()->url . '/' . implode('/', $split),
					301
				)
					->send();
				\Yii::$app->end();
			}
		}

		return $request;
	}

	/**
	 * Looks for rule in table(column)
	 * `redirect.from` if findes -
	 * redirects to `redirect.to`
	 *
	 * @param string $url
	 */
	protected function checkRedirect(string $url)
	{
		$url1 = parse_url($url);


		$string = '{"0":"' . ltrim($url1['path'], "/") . '"';
		if (isset($url1['query'])) {
			parse_str($url1['query'], $url1['query']);
			$string .= (isset($url1['query']['id']))
				? ',"id":' . $url1['query']['id']
				: '';
		}

		$string .= '}';

		$alias = Alias::find()
			->where(['like', 'route', $string])
			->limit(1)
			->one();
		return $alias;


	}

	protected function invalidParams($requestParams)
	{
		foreach ($requestParams as $key => $param) {

			if (!array_key_exists($key, $this->params)) {
				throw new NotFoundHttpException();
			}
		}
	}
}