protected/modules/yupe/components/urlManager/LangUrlManager.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * LangUrlManager - альтернативный менеджер урлов с поддержкой языков
 * при инициализации добавляет к существующим правилам маршрутизации правила для выбора языков в начале пути.
 * То есть, если рассматривать на примере - /<controller>/<index>,
 * то в случае обработки мы получим дополнительное правило:
 * /<language>/<controller>/<action>.
 * Добавленный параметр используется в LanguageBehavior
 *
 * @category YupeComponent
 * @package  yupe.modules.yupe.components.urlManager
 * @author   YupeTeam <support@yupe.ru>
 * @license  BSD http://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F_BSD
 * @link     https://yupe.ru
 */
namespace yupe\components\urlManager;

use CUrlManager;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use Yii;
use YupeModule;

/**
 * Class LangUrlManager
 * @package yupe\components\urlManager
 */
class LangUrlManager extends CUrlManager
{
    /**
     * @var string
     */
    public $langParam = 'language';
    /**
     * @var string
     */
    protected $_defaultLang;
    /**
     * @var string
     */
    protected $_currentLang;
    /**
     * @var string
     */
    protected $_langFromUrl;
    /**
     * @var string
     */
    protected $_langFromCookie;
    /**
     * @var array
     */
    protected $_languages;
    /**
     * @var YupeModule
     */
    protected $yupe;

    /**
     * @inheritdoc
     */
    public function init()
    {
        $this->yupe = Yii::app()->getModule('yupe');
        $languages = $this->getAvailableLanguages();

        if ('path' === $this->urlFormat && count($languages) > 1) {

            $languages = implode('|', $languages);
            $rules = [];
            $langPattern = '/<'.$this->langParam.':('.$languages.')>/';
            foreach ($this->rules as $pattern => $route) {
                if (is_array($route)) {
                    if (isset($route['pattern'])) {
                        $route['pattern'] = $langPattern.ltrim($route['pattern'], '/');
                        $rules[] = $route;
                    }
                } else {
                    $pattern = $langPattern.ltrim($pattern, '/');
                    $rules[$pattern] = $route;
                }
            }

            $this->rules = array_merge($rules, $this->rules);
        }

        parent::init();
    }

    /**
     * @return array
     */
    public function getAvailableLanguages()
    {
        if (null === $this->_languages) {
            $this->_languages = explode(',', $this->yupe->availableLanguages);
        }

        return $this->_languages;
    }

    /**
     * @return string
     */
    public function getDefaultLang()
    {
        if (null === $this->_defaultLang) {
            $this->_defaultLang = $this->isBackend()
                ? $this->yupe->defaultBackendLanguage
                : $this->yupe->defaultLanguage;
        }

        return $this->_defaultLang;
    }

    /**
     * @return null|string
     */
    public function getCurrentLang()
    {
        if (null === $this->_currentLang) {
            $language = $this->getLangFromUrl();

            if (null === $language) {
                $language = $this->getLangFromCookie() ?: $this->getDefaultLang();
            }

            $this->_currentLang = in_array($language, $this->_languages, true) ? $language : null;
        }

        return $this->_currentLang;
    }

    /**
     * @return null|string
     */
    public function getLangFromUrl()
    {
        if ($this->_langFromUrl && !Yii::app()->getComponent('request', false) )
            return $this->_langFromUrl;

        /* @var $request \CHttpRequest */
        $request = Yii::app()->getRequest();

        $path = explode('/', $request->getPathInfo());
        $language = !empty($path[0]) ? $path[0] : null;

        if ($language === null) {
            $language = $request->getQuery($this->langParam);
        }

        $language = in_array($language, $this->_languages, true) ? $language : null;

        $this->_langFromUrl = $language;


        return $this->_langFromUrl;
    }

    /**
     * @return null|string
     */
    public function getLangFromCookie()
    {
        if ($this->_langFromCookie && !Yii::app()->getComponent('request', false) )
            return $this->_langFromCookie;

        /* @var $request \CHttpRequest */
        $request = Yii::app()->getRequest();

        if (isset($request->cookies[$this->getCookieKey()])) {
            $language = $request->cookies[$this->getCookieKey()]->value;

            $this->_langFromCookie = in_array($language, $this->_languages, true) ? $language : null;
        }


        return $this->_langFromCookie;
    }

    /**
     * @return string
     */
    public function getCookieKey()
    {
        return $this->langParam.'_'.($this->isBackend() ? 'backend' : 'frontend');
    }


    /**
     * @param string $route
     * @param array $params
     * @param string $ampersand
     * @return mixed|string
     */
    public function createUrl($route, $params = [], $ampersand = '&')
    {
        if (count($this->_languages) > 1) {

            if (!isset($params[$this->langParam])) {
                $params[$this->langParam] = $this->getCurrentLang();
            }

            if ($this->getDefaultLang() === $params[$this->langParam]) {
                unset($params[$this->langParam]);
            } elseif (trim($route, '/') === '') {
                return Yii::app()->getHomeUrl().$params[$this->langParam];
            }
        }

        return str_replace('%2F', '/', parent::createUrl($route, $params, $ampersand));
    }

    /**
     * @param $url
     * @param null
     * @return string
     */
    public function replaceLangInUrl($url, $lang = null)
    {
        $parsed = parse_url($url);

        $result = '';

        if (isset($parsed['scheme'])) {
            $result .= $parsed['scheme'].'://';
        }

        if (isset($parsed['user'])) {
            $result .= $parsed['user'];
            if (isset($parsed['pass'])) {
                $result .= ':'.$parsed['pass'];
            }
            $result .= '@';
        }

        if (isset($parsed['host'])) {
            $result .= $parsed['host'].'/';
        }

        if ('path' === $this->urlFormat && isset($parsed['path'])) {
            $path = trim($parsed['path'], '/');

            $replaced = preg_replace_callback(
                '#^(' . implode('|', $this->_languages) . '){1}(\/.*)?$#',
                function($matches) use ($lang) {
                    return $lang . (isset($matches[2]) ? $matches[2] : '');
                },
                $path
            );

            $replaced = trim($replaced, '/');

            if ($path === $replaced && null !== $lang) {
                $replaced = $lang;
                if ($path !== '') {
                    $replaced .= '/'.$path;
                }
            }

            $result .= $replaced;

            if ($result !== '') {
                if (strpos($url, '/') === 0) {
                    $result = '/'.$result;
                }

                if (substr($url, -1) === '/') {
                    $result .= '/';
                }
            }
        }

        if ('get' === $this->urlFormat) {
            $queryParams = [];

            if (isset($parsed['query'])) {
                parse_str($parsed['query'], $queryParams);
            }

            if (null === $lang && isset($queryParams[$this->langParam])) {
                unset($queryParams[$this->langParam]);
            } else {
                $queryParams[$this->langParam] = $lang;
            }

            $query = urldecode(http_build_query($queryParams));

            if ($query !== '') {
                $result .= '?'.$query;
            }
        }

        if ($result === '') {
            $result .= '/';
        }

        return $result;
    }

    /**
     * @param $url
     * @return string
     */
    public function removeLangFromUrl($url)
    {
        return $this->replaceLangInUrl($url);
    }

    /**
     * @return bool
     */
    public function isBackend()
    {
        $url = trim($this->removeLangFromUrl(Yii::app()->getRequest()->getUrl()), '/');

        return strpos($url, 'backend') === 0;
    }
}