Twig扩展:数据库查询

Twig extension: database query

我需要做一个自定义过滤器,将价格转换为用户的货币偏好。 所以我 table 每天都会更新最新的汇率。

我打算这样调用过滤器 {{ '200'|price }} 或 {{ '200'|price('USD') }}

过滤器首先会从 cookie 中获取用户偏好。

然后会根据货币代码查询最新汇率,换算成实际价格

我的问题是,在 twig 扩展中进行数据库查询是否可以(在此处过滤)。

我可能不得不在一个页面中调用此过滤器 10 次。这是否意味着还有 10 个查询?

您有什么更好的建议?

是的,如果你没有为Doctrine定义缓存配置,那意味着你每次都会向数据库发送请求来获取数据。

您可以选择查询汇率、自己将它们存储在缓存中或使用 Doctrine 的缓存功能来执行此操作。

Symfony 2 cache Doctrine query results

这两种方式都比每次都直接从数据库中查询数据要好。

使用教义事件系统,在这种情况下postLoad事件将是合适的。您可以将价格添加到实体中未映射的 属性,然后在树枝中调用,例如:{{ entity.prices.usd }}

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

听众class:

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')] }}

您可以创建 class CurrencyConverter,它将仅查询一次数据库并使用其结果,假设在用户请求期间速率未更改。一些简单的服务(你可以用 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 很可能会将整个货币汇率 table 加载到内存中,并且会非常快。

Doctrine 缓存可能会加速更多,但任何缓存都会导致其他问题和问题:

  • 查询结果应该在缓存中多长时间?
  • 我需要在速率更新时手动清除缓存吗?
  • 我是从缓存还是数据库中得到结果?

等等。