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 缓存可能会加速更多,但任何缓存都会导致其他问题和问题:
- 查询结果应该在缓存中多长时间?
- 我需要在速率更新时手动清除缓存吗?
- 我是从缓存还是数据库中得到结果?
等等。
我需要做一个自定义过滤器,将价格转换为用户的货币偏好。 所以我 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 缓存可能会加速更多,但任何缓存都会导致其他问题和问题:
- 查询结果应该在缓存中多长时间?
- 我需要在速率更新时手动清除缓存吗?
- 我是从缓存还是数据库中得到结果?
等等。