CatalogUrlManager.php 6.42 KB
<?php

namespace common\modules\product;


use common\modules\product\models\CategorySearch;
use common\modules\product\models\ProductSearch;

use Yii;
use yii\helpers\Url;
use yii\web\HttpException;
use yii\web\UrlRuleInterface;

class CatalogUrlManager implements UrlRuleInterface {
    public $route_map = [];
    /**
     * Parses the given request and returns the corresponding route and parameters.
     * @param \yii\web\UrlManager $manager the URL manager
     * @param \yii\web\Request $request the request component
     * @return array|boolean the parsing result. The route and the parameters are returned as an array.
     * If false, it means this rule cannot be used to parse this path info.
     */
    public function parseRequest($manager, $request)
    {
        $pathInfo = $request->getPathInfo();
        $paths = explode('/', $pathInfo);

        if(isset($paths[1])) {
            if(strripos($request->url,'catalog/'.$paths[1].'?') && (!strripos($request->url,'?page')) && (!strripos($request->url,'?sort'))){
                throw new HttpException(404 ,'Page not found');
            }

        }


        if (!array_key_exists($paths[0], $this->route_map)) {
            return false;
        }

        $params = [];
        if ($paths[0] == 'catalog') {
            $route = 'catalog/category';

            // Category
            if (!empty($paths[1])) {
                $category = CategorySearch::findByAlias($paths[1]);
                if (empty($category)) {
                    http_redirect(Url::to(['/']));
                }
                $params['category'] = $category;
            }
            if (!empty($paths[2])) {
                // Filter

                if (strpos($paths[2], 'filters:') === 0) {
                    $this->parseFilter($paths[2], $params);

                }
                else {
                    throw new HttpException(404 ,'Page not found');
                }
            }
        } elseif ($paths[0] == 'product') {
            if (!empty($paths[2])) {
                throw new HttpException(404 ,'Page not found');
            }
            $product = ProductSearch::findByAlias($paths[1]);
            if (empty($product->product_id)) {
                throw new HttpException(404 ,'Page not found');
            }
            $route = 'catalog/product';
            $params = [
                'product' => $product,
            ];
        }

        return [$route, $params];
    }
    /**
     * Creates a URL according to the given route and parameters.
     * @param \yii\web\UrlManager $manager the URL manager
     * @param string $route the route. It should not have slashes at the beginning or the end.
     * @param array $params the parameters
     * @return string|boolean the created URL, or false if this rule cannot be used for creating this URL.
     */
    public function createUrl($manager, $route, $params)
    {

        if (!in_array($route, $this->route_map)) {
            return false;
        }

        switch($route) {
            case 'catalog/category':
                if (!empty($params['category'])) {
                    $category_alias = is_object($params['category']) ? $params['category']->alias : strtolower($params['category']);
                    $url = 'catalog/'. $category_alias .'/';
                    unset($params['category']);
                } else {
                    $url = 'catalog/';
                }

                $this->setFilterUrl($params, $url);

                foreach ($params as $key => $param) {
                    if (empty($params[$key])) {
                        unset($params[$key]);
                    }
                }

                if (!empty($params) && ($query = http_build_query($params)) !== '') {
                    $url .= '?' . $query;
                }

                return $url;
                break;

            case 'catalog/product':
                if (!empty($params['product'])) {
                    $product_alias = is_object($params['product']) ? $params['product']->alias : strtolower($params['product']);
                    unset($params['product']);
                }
                $url = 'product/'. $product_alias;

                if (!empty($params) && ($query = http_build_query($params)) !== '') {
                    $url .= '?' . $query;
                }



                return $url;
                break;

        }
    }

    private function option_value_encode($value) {
        return str_replace(array(',', '/'), array('~', '&s;'), $value);
    }

    private function setFilterUrl(&$params, &$url) {
        $filter = [];
        if (!empty($params['filters'])) {
            foreach ($params['filters'] as $key => $values) {
                switch($key) {
                    case 'prices':
                        $filter[] = $key .'='. implode(':', $values);
                        break;

                    default:
                        foreach($values as &$value) {
                            $value = $this->option_value_encode($value);
                            if (empty($value)) {
                                unset($value);
                            }
                        }
                        $filter[] = $key .'='. implode(',', $values);
                        break;
                }
            }
            if (!empty($filter)) {
                $url .= 'filters:'. implode(';', $filter);
            }
            unset($params['filters']);
        }
    }

    private function parseFilter($paths, &$params) {
        $params['filters'] = [];
        $filter_str = substr($paths, 8);
        $filter_options = explode(';', $filter_str);
        foreach ($filter_options as $filter_option) {
            if (empty($filter_option)) {
                continue;
            }
            list($filter_key, $filter_option) = explode('=', $filter_option);
            if($filter_key == 'prices') { // price-interval section
                $prices = explode(':', $filter_option);
                $params['filters'][$filter_key] = [
                    'min' => floatval($prices[0]),
                    'max' => floatval($prices[1]),
                ];
            }
            else { // brands and other sections
                $params['filters'][$filter_key] = explode(',', $filter_option);
            }
        }
    }

}