2016-05-14 4 views
1

Мне нужно сделать собственный фильтр, который будет конвертировать цену в предпочтение валюты пользователя. Итак, у меня есть таблица, обновленная каждый день с последними обменными курсами.Расширение Twig: запрос базы данных

Я планирую вызвать фильтр таким образом {{ '200' | цена}} или {{ '200' | цена ('USD')}}

Фильтр будет первым взять предпочтение пользователем из печенье.

Затем будет запрашивать последний обменный курс на основе кода валюты и конвертировать фактическую цену.

Мой вопрос в том, можно ли делать запрос базы данных в расширении ветви (здесь фильтр).

Возможно, мне придется называть этот фильтр 10 раз на странице. Означает ли это еще 10 запросов?

Какие лучшие способы вы бы посоветовали?

ответ

3

Да, если вы не определяете конфигурацию кеша для Doctrine, это означает, что вы будете отправлять запрос в базу данных для сбора данных каждый раз.

Вы можете выбирать между запросами на обменные курсы, самостоятельно хранить их в кеше или использовать функцию кеширования Doctrine для этого.

Symfony 2 cache Doctrine query results

Оба способа лучше, чем запрашивать данные из базы данных непосредственно каждый раз.

+0

Спасибо, это то, что мне нужно было услышать. – Brieuc

+0

Достаточно сделать статическое свойство в расширении, которое поддерживает обменные курсы для всего запроса. – malcolm

+0

Привет @malcolm, я полностью согласен с тем, что статическое свойство является хорошим решением. Однако, как вы также отметили, это пожизненное время - это единственный запрос, поэтому я думаю, что если обменный курс не является значительным в вашем приложении и нуждается в обновлении в реальном времени (в этом случае вам может понадобиться даже лучшее решение, чем продление его на каждый запрос) , Я все еще думаю, что положить их в кеш - хорошее решение. –

2

Использовать систему событий доктрины, в данном случае postLoad мероприятие будет подходящим. Вы можете добавить цены не отображается недвижимость в вашей организации, и называют потом в веточке, как: {{ entity.prices.usd }}

services: 
    app.postload.listener: 
     class: AppBundle\EventListener\PostLoadListener 
     tags: 
      - { name: doctrine.event_listener, event: postLoad } 

Слушатель класса:

namespace AppBundle\EventListener; 

use Doctrine\ORM\Event\LifecycleEventArgs; 
use AppBundle\Entity\Product; 



class PostLoadListener 
{ 

protected static $currencies = []; 

public function postLoad(LifecycleEventArgs $args) 
{ 
    $entity = $args->getEntity(); 


    $entityManager = $args->getEntityManager(); 


    if ($entity instanceof Product) { 
     $price = $entity->getPrice(); 
     if (empty($this->currencies) { 
      // get currencies from db and calculate prices 
      $this->currencies = $entityManager->getConnection()->prepare('SELECT.....')->execute()->fetchAll(); 
     } 

     // Calculate prices and make them as array: $prices = ['usd' => 34, 'eur` => 30 .....] 

    $entity->setPrices($prices); 
} 

}

Позвоните им в Twig:

{{ entity.prices[app.request.cookies.get('currency')] }} 
+0

Это хорошая идея. Возможно, я не смогу получить доступ к свойству entity.prices.usd, так как я получаю такую ​​валюту {{app.request.cookies.get ('currency')}}. Но в любом случае упоминание системы событий доктрины - хорошая идея. Спасибо! – Brieuc

+1

Вы можете: '{{entity.prices [app.request.cookies.get ('currency')]}}' – malcolm

+0

О да, действительно, спасибо! – Brieuc

1

Вы можете создать класс CurrencyConverter, который будет запрашивать базу данных только по ce и использовать его результат, предполагая, что скорость не изменяется во время запроса пользователя. Некоторые простые службы (вы можете вводить его с DI для вашего расширения Twig) как

class CurrencyConverter 
{ 
    /** @var EntityManager */ 
    private $em; 

    private $rates = []; 

    public function __construct(EntityManager $em) 
    { 
     $this->em = $em; 
    } 

    public function convert($amount, $currency) 
    { 
     return $amount * $this->getRate($currency); 
    } 

    private function getRate($currency) 
    { 
     if (!isset($this->rates[$currency])) { 
      $repository = $this->em->getRepository('AppBundle:Rate'); 
      $this->rates[$currency] = $repository->getLatestRate($currency); 
     } 

     return $this->rates[$currency]; 
    } 
} 

Таким образом, вы будете иметь 1 запрос к базе данных для каждого запроса на валюту. Если у вас мало пользователей, которых может быть достаточно. MySQL, скорее всего, загрузит всю таблицу курсов валют в память и будет быстро разгоняться.

Доктрина кэш может ускорить больше, но любой кэш приводит к дополнительным проблемам и вопросам:

  • Как долго должен запрашивать результат быть в кэше?
  • Нужно ли очищать кеш вручную при обновлении ставки?
  • Я только что получил результат из кеша или базы данных?

и так далее.

Смежные вопросы