Php 根据会话值选择实体

Php 根据会话值选择实体,php,symfony,Php,Symfony,我有两个实体。一个是WebshopItem实体,另一个是WebshopPrice实体。 每次创建一个WebshopItem时,您也要填写3个WebshopPrices。网店价格为3种货币(欧元、美元和英镑) 根据您选择的货币(并保存在会话中),我希望显示您选择的货币。所以,如果你选择欧元,我当然想显示欧元的价格 在symfony做这件事的一般方式是什么?我应该根据会话中的内容使用从WebshopItem对象返回价格的细枝扩展吗?我应该已经从数据库中过滤WebshopPrices吗 期待您的最佳解

我有两个实体。一个是WebshopItem实体,另一个是WebshopPrice实体。 每次创建一个WebshopItem时,您也要填写3个WebshopPrices。网店价格为3种货币(欧元、美元和英镑)

根据您选择的货币(并保存在会话中),我希望显示您选择的货币。所以,如果你选择欧元,我当然想显示欧元的价格

在symfony做这件事的一般方式是什么?我应该根据会话中的内容使用从WebshopItem对象返回价格的细枝扩展吗?我应该已经从数据库中过滤WebshopPrices吗

期待您的最佳解决方案。谢谢

实体/WebshopItem.php

class WebshopItem
{
   /**
   * @var \Doctrine\Common\Collections\Collection
   */
   private $prices;

   etc....
}
实体/WebshopItemPrice.php

class WebshopItemPrice
{

   /**
   * @var integer
   */
   private $id;

   /**
   * @var string
   */
   private $currency;

   /**
   * @var string
   */
   private $price;

   private $webshopItem;
}

您可以查询与WebshopItemPrice
连接的WebshopItem,其中
WebshopItemPrice.currency=$variableFromSesion。例如:

$queryBuilder
    ->select('WebshopItem, WebshopItemPrice')
    ->leftJoin('WebshopItemPrice.prices', 'WebshopItemPrice')
    ->where('WebshopItemPrice.currency = :currency')
    ->setParameter('currency', $variableFromSesion)

其中,
$variableFromSesion
是存储在会话中的当前用户货币。执行该查询(通过
getResult()
)后,您可以通过调用$webshopItem->getPrices()获取价格-这应该只返回一个结果技巧不是如何检索数据,而是如何使用它。因为这取决于请求对象,所以您应该使用一些服务。如果你确定你永远不会在其他地方使用它,那么就使用细枝扩展。如果您的后端代码也会使用它,那么就使用一个服务,比如MyPricePickerService(并在twig扩展中获得它)。请注意,在twig extension上,我找不到任何东西可以保证为每个作用域创建一个新实例,因此每次调用此操作时,都应该使用注入的容器(因此不是缓存的请求或MyPricePickerService的以前的实例)

更新

您也可以使用,但在这种情况下,您需要覆盖默认的解析器以在侦听器中获取会话:

src/Your/GreatBundle/Resources/config/services.yml

doctrine.orm.default_entity_listener_resolver:
        class: Your\GreatBundle\Listener\EntityListenerResolver
        arguments: [@service_container]
services:
    price.listener:
        class: Your\GreatBundle\Listener\PriceListener
        arguments: [@session]
        tags:
            - { name: doctrine.event_listener, event: postLoad }
src/Your/GreatBundle/Listener/EntityListenerResolver

namespace Your\GreatBundle\Listener;

use Doctrine\ORM\Mapping\EntityListenerResolver as EntityListenerResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class EntityListenerResolver implements EntityListenerResolverInterface
{
    private $instances = [];
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function clear($className = null)
    {
        if ($className === null) {

            $this->instances = [];

            return;
        }

        if (isset($this->instances[$className = trim($className, '\\')])) {

            unset($this->instances[$className]);
        }
    }

    public function register($object)
    {
        if ( ! is_object($object)) {

            throw new \InvalidArgumentException(sprintf('An object was expected, but got "%s".', gettype($object)));
        }

        $this->instances[get_class($object)] = $object;
    }

    public function resolve($className)
    {
        if (isset($this->instances[$className = trim($className, '\\')])) {

            return $this->instances[$className];
        }

        // Here we are injecting the entire container to the listeners
        return $this->instances[$className] = new $className($this->container);
    }
}

您可以在与用户会话一起注入的服务中收听:

src/Your/GreatBundle/Resources/config/services.yml

doctrine.orm.default_entity_listener_resolver:
        class: Your\GreatBundle\Listener\EntityListenerResolver
        arguments: [@service_container]
services:
    price.listener:
        class: Your\GreatBundle\Listener\PriceListener
        arguments: [@session]
        tags:
            - { name: doctrine.event_listener, event: postLoad }
src/Your/GreatBundle/Listener/PriceListener.php

namespace Your\GreatBundle\Listener\PriceListener;

use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Your\GreatBundle\Entity\WebshopItem;

class PriceListener
{
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

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

        if ($entity instanceof WebshopItem) {

            $currency = $this->session->get('currency', 'EUR');
            $entity->setCurrency(currency);
        }
    }
}
namespace Your\GreatBundle\Entity;

class WebshopItem
{
   ...

   // You don't need to persist this...
   private $currency = 'EUR';

   public function setCurrency($currency)
   {
        $this->currency = $currency;
   }

   public function getPrice()
   {
        foreach ($this->prices as $price) {

            if ($price->getCurrency() === $this->currency) {

                return ($price->getPrice();
            }
        }

        return null;
   }
}
src/Your/GreatBundle/Entity/WebshopItem.php

namespace Your\GreatBundle\Listener\PriceListener;

use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Your\GreatBundle\Entity\WebshopItem;

class PriceListener
{
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

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

        if ($entity instanceof WebshopItem) {

            $currency = $this->session->get('currency', 'EUR');
            $entity->setCurrency(currency);
        }
    }
}
namespace Your\GreatBundle\Entity;

class WebshopItem
{
   ...

   // You don't need to persist this...
   private $currency = 'EUR';

   public function setCurrency($currency)
   {
        $this->currency = $currency;
   }

   public function getPrice()
   {
        foreach ($this->prices as $price) {

            if ($price->getCurrency() === $this->currency) {

                return ($price->getPrice();
            }
        }

        return null;
   }
}

听起来很有趣。这项服务基本上是什么样子的?我的意思是,我有一个包含10个项目的概览页面。服务是处理每个WebshopItem的WebshopItem,还是一次处理全部10个WebshopItem?逐项处理。它所做的仅仅是为一个项目返回合适的价格,比如公共函数getItemDefaultPrice(WebshopItem$item)。如果您对价格加载感到困扰:预加载应该通过急切地加载该关系或显式地预加载控制器中的实体来完成。当我假设每次从Doctrine检索数据时都调用PriceListener时,我是否正确?对我来说,这似乎是一些开销。还是更糟?不是更糟吗。。。条令事件就是为此而设计的,以条令扩展为例()。条令事件是一种很好的解耦方式。如果您想避免使用postLoad事件,那么您应该开发一个WebshopItem管理器(或存储库),并在每次需要检索其中一个时使用它。我已经更新了我的答案,请查看它。