A
A
Alexander Stepanov2019-09-23 12:04:50
Yii
Alexander Stepanov, 2019-09-23 12:04:50

How to configure CNC for different actions of the same controller in YII2?

There is a store with a "Catalog" controller that has actions: categories, products...
Categories are on nested sets, and products are like products...
There is a rule for categories and CNC works fine for them, as long as products have id instead of slug. As soon as I try to attach the CNC to the products, nonsense starts - either the products open as 404, or both categories and products open as 400.
So I understand that a separate action needs to write a separate rule, but I didn’t find how to add a condition with a slug to <_a: product> :[\w\-]+
How to defeat him? If you can explain in more detail, otherwise I read something, only - yt.
Just the rules in urlManager:

'catalog' => 'shop/catalog/index',
// 'catalog/<url:[\w\-]+>' => 'shop/catalog/product',
[class' => 'frontend\urls\CategoryUrlRule'],

and in the rules for categories:
public function parseRequest($manager, $request)
    {
        if (preg_match('#^' . $this->prefix . '/(.*[a-z])$#is', $request->pathInfo, $matches)) {
            $path = $matches['1'];

            $result = $this->cache->getOrSet(['category_route', 'path' => $path], function () use ($path) {
                if (!$category = $this->repository->findBySlug($this->getPathSlug($path))) {
                    return ['id' => null, 'path' => null];
                }
                return ['id' => $category->id, 'path' => $this->getCategoryPath($category)];
            }, null, new TagDependency(['tags' => ['categories']]));

            if (empty($result['id'])) {
                return false;
            }

            if ($path != $result['path']) {
                throw new UrlNormalizerRedirectException(['shop/catalog/category', 'id' => $result['id']], 301);
            }

            return ['shop/catalog/category', ['id' => $result['id']]];
        }
        return false;
    }

    public function createUrl($manager, $route, $params)
    {
        if ($route == 'shop/catalog/category') {
            if (empty($params['id'])) {
                throw new InvalidParamException('Empty id.');
            }
            $id = $params['id'];

            $url = $this->cache->getOrSet(['category_route', 'id' => $id], function () use ($id) {
                if (!$category = $this->repository->find($id)) {
                    return null;
                }
                return $this->getCategoryPath($category);
            }, null, new TagDependency(['tags' => ['categories']]));

            if (!$url) {
                throw new InvalidParamException('Undefined id.');
            }

            $url = $this->prefix . '/' . $url;
            unset($params['id']);
            if (!empty($params) && ($query = http_build_query($params)) !== '') {
                $url .= '?' . $query;
            }

            return $url;
        }
        return false;
    }

    private function getPathSlug($path): string
    {
        $chunks = explode('/', $path);
        return end($chunks);
    }

    private function getCategoryPath(Category $category): string
    {
        $chunks = ArrayHelper::getColumn($category->getParents()->andWhere(['>', 'depth', 0])->all(), 'slug');
        $chunks[] = $category->slug;
        return implode('/', $chunks);
    }

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander Stepanov, 2019-09-28
@Exebeche

In fact, everything turned out to be nowhere funnier.
Initially, I correctly set the routing rule for goods - 'catalog/<url:[\w\-]+>' => 'shop/catalog/product', just in the model, the find method had to be set by slug instead of id as it was originally.
And everything began to work wonderfully))
Thank you all for your help.
It remains to master how to do 301 now from old addresses

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question