@beta-it

Как избавиться от лишних запросов к БД при создании своих правил URL в Yii2?

Создал свое правило для формирования URL в Yii2, проблема в том что при выводе ссылки вида:
<a href="<?= Url::to(['site/test', 'country' => 'de'])?>">Test Route</a>
<a href="<?= Url::to(['site/test', 'country' => 'de'])?>">Test Route</a>
<a href="<?= Url::to(['site/test', 'country' => 'fr'])?>">Test Route</a>
<a href="<?= Url::to(['site/test', 'country' => 'ru'])?>">Test Route</a>

При этом создаются дублирующие запросы к БД вида:
SELECT * FROM `countries` WHERE `id`='DE' LIMIT 1
Одних только запросов с id=DE создалось: 6 судя по Yii Debug как то можно от этого избавиться, сократить?

<?php

namespace components;

use common\models\City;
use common\models\Country;
use yii\base\Object;
use yii\web\UrlRuleInterface;

class CountryCityUrlRule extends Object implements UrlRuleInterface
{

    public function createUrl($manager, $route, $params)
    {
        if ($route === 'site/test'){

            if ( isset($params['country']) ){

                $country = Country::find()->select('name')->asArray()->where(['id' => $params['country']])->limit(1)->scalar();

                if ( isset($params['city']) ){
                    $city = City::find()->select('name_en')->asArray()->where(['id' => $params['city'], 'country_id' => $country])->limit(1)->scalar();

                    if ($country !== false && $city !== false){
                        return $country . '/' .  $city;
                    }
                }

                if ($country !== false) {
                    return $country;
                }

            }

        }
        return false;
    }

    public function parseRequest($manager, $request)
    {
        $pathInfo = $request->getPathInfo();

        if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {

            if (isset($matches[1])){
                $country_id = Country::find()->select('id')->asArray()->where(['name' => $matches[1]])->limit(1)->scalar();

                if (isset($matches[3])){

                    $city_id = City::find()->select('id')->asArray()->where(['name_en' => $matches[3], 'country_id'=>$country_id])->limit(1)->scalar();

                    if ($country_id !== false && $city_id !== false){
                        return ['site/test', ['country' => $country_id, 'city'=>$city_id]];
                    }
                }

                if ($country_id !== false) {
                    return ['site/test', ['country' => $country_id]];
                }
            }



        }
        return false;
    }

}
  • Вопрос задан
  • 358 просмотров
Решения вопроса 2
NeLexa
@NeLexa
Прикрутите кэширование результата SQL запроса.
www.yiiframework.com/doc-2.0/guide-caching-data.html

Пример:
$cacheDuration = 60; // 1 min
$country_id = Country::getDb()->cache(function ($db) {
    return Country::find()->select('id')->asArray()->where(['name' => $matches[1]])->limit(1)->scalar();
}, $cacheDuration);
Ответ написан
rpsv
@rpsv
делай либо хорошо, либо никак
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@beta-it Автор вопроса
Решил следующим способом, сначала сократил всю выборку до одного запроса, далее работал по массиву, + еще воспользовался Вашими советами спасибо...
private function getCountry($countryId = null){

        if (isset($countryId)){

            $result = Country::getDb()->cache(function ($db) {

                return Country::find()->select('id, name')->asArray()->indexBy('id')->all();

            });

            return $result[$countryId]['name'];
        }
        return null;

    }
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы