根据会话值选择实体


Select entity based on session value

我得到了两个实体。一个是WebshopItem实体,另一个是WebshopPrice实体。每次创建一个网店商品时,您还需要填写3个网店价格。网店价格为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;
}

更新

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

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

doctrine.orm.default_entity_listener_resolver:
        class: Your'GreatBundle'Listener'EntityListenerResolver
        arguments: [@service_container]

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);
    }
}

您可能会在注入用户会话的服务中收听Doctrine的postLoad事件:

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

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);
        }
    }
}

src/Your/GreatBundle/Entity/WebshopItem.php

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;
   }
}

您可以查询加入WebshopItemPrice WHERE WebshopItemsPrice.current=$variableFromSesion的WebshopItem。例如:

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

其中,$variableFromSesion是存储在会话中的当前用户货币。执行该查询后(通过getResult()),您可以通过调用$webshopItem->getPrices()来获取价格-这应该只返回一个结果

诀窍不在于如何检索数据,而在于用什么来检索数据。因为这取决于Request对象,所以应该使用类似服务的东西。如果你确信你永远不会在其他地方使用这个,那么就使用树枝扩展。如果你的后端代码也会使用它,那么就使用一个服务,比如MyPricePickerService(并在树枝扩展中获取)。请注意,关于trick扩展,我找不到任何可以保证为每个作用域创建新实例的东西,所以在每次调用此操作时,您应该使用注入的Container(所以不是缓存的Request或MyPricePickerService的以前实例)!