NodeUrlRule.php 4.35 KB
<?php

class NodeUrlRule extends CBaseUrlRule
{
    public $rules = array();
    public $langExpression = '(en|ru)';
    public $langVar = 'lang';
    public $nodeVar = 'node_id';

    /**
     * Creates a URL based on this rule.
     * @param CUrlManager $manager the manager
     * @param string $route the route
     * @param array $params list of parameters (name=>value) associated with the route
     * @param string $ampersand the token separating name-value pairs in the URL.
     * @return mixed the constructed URL. False if this rule does not apply.
     */
    public function createUrl($manager, $route, $params, $ampersand)
    {
        if (!isset($params[$this->nodeVar])) return false;
        /** @var $node Node */
        $node = Node::model()->findByPk($params[$this->nodeVar]);
        if (empty($node)) return false;
        if (!isset($this->rules[$node->data_type])) return false;
        foreach ($this->rules[$node->data_type] as $k => $v) {
            if (is_string($k) && is_string($v)) {
                $rule = new CUrlRule($v, $k);
                $this->rules[$node->data_type][$k] = $rule;
            } else {
                $rule = $v;
            }
            $newParams = $params;
            unset($newParams[$this->langVar]);
            unset($newParams[$this->nodeVar]);
            $url = $rule->createUrl($manager, $route, $newParams, $ampersand);
            if ($url !== false) {
                $path = "/{$node->link}";
                for ($t = $node; $t->node_id != null; $t = $t->node) {
                    $path = "/{$t->node->link}{$path}";
                }
                return "{$params[$this->langVar]}{$path}/{$url}";
            }
        }
        return false;
    }

    /**
     * Parses a URL based on this rule.
     * @param CUrlManager $manager the URL manager
     * @param CHttpRequest $request the request object
     * @param string $pathInfo path info part of the URL (URL suffix is already removed based on {@link CUrlManager::urlSuffix})
     * @param string $rawPathInfo path info that contains the potential URL suffix
     * @return mixed the route that consists of the controller ID and action ID. False if this rule does not apply.
     */
    public function parseUrl($manager, $request, $pathInfo, $rawPathInfo)
    {
        //$rawPathInfo = $request->getPathInfo();
        //$pathInfo = $rawPathInfo;
        preg_match("#^{$this->langExpression}#", $pathInfo, $langMatches);
        if (0 == count($langMatches)) return false;
        $lang = $langMatches[0];
        //subtract lang prefix
        $pathInfo = substr($pathInfo, strlen($lang) + 1);


        //subtract at least one node link
        $nodes = array();
        /** @var $node Node|null */
        while (true) {
            preg_match('#^([^\/]+)#', $pathInfo, $matches);
            if (0 == count($matches)) break;
            $link = $matches[0];
            $nodeCriteria = new CDbCriteria();
            $nodeCriteria->compare('link', $link);
            if (!empty($node)) {
                $nodeCriteria->compare('node_id', $node->id);
            } else {
                $nodeCriteria->addCondition('node_id is null');
            }
            $node = Node::model()->find($nodeCriteria);
            if (empty($node)) break;
            $nodes[] = $node;
            if (strlen($link) == strlen($pathInfo)) {
                $pathInfo = '';
                break;
            }
            if ($pathInfo[strlen($link)] == '/') {
                $pathInfo = substr($pathInfo, strlen($link) + 1);
            } else {
                $pathInfo = substr($pathInfo, strlen($link));
            }
        }
        if (0 == count($nodes)) return false; // no matching nodes
        $node = end($nodes);
        if (!isset($this->rules[$node->data_type])) return false; //no rules for type
        //parse rest
        foreach ($this->rules[$node->data_type] as $k => $v) {
            if (is_string($k) && is_string($v)) {
                $rule = new CUrlRule($v, $k);
                $this->rules[$node->data_type][$k] = $rule;
            } else {
                $rule = $v;
            }
            $route = $rule->parseUrl($manager, $request, $pathInfo, $pathInfo);
            if ($route !== false) {
                $_GET[$this->langVar] = $lang;
                $_GET[$this->nodeVar] = $node->id;
                return $route;
            }
        }
        return false;
    }
}