从外部Entity Repository构建实体属性

时间:2014-08-19 07:54:03

标签: symfony doctrine-orm repository entity

我有一个用户实体,可以向他的客户收费。因此,用户可以创建发票实体。我想要做的是通过汇总发票总额,能够轻松检索用户已收取的费用。我可以通过将$ user变量传递给汇总这些发票的方法,轻松地在我的发票存储库中执行此操作。但是我想将这个值存储在User实体中,所以在我的twig模板中,我可以用这样的方式调用它:{{app.user.chargedAmount}}

但据我所知,我无法在我的用户实体中创建一个getChargedAmount(),它将使用发票存储库并设置受保护的$ chargedAmount属性。

我应该如何在我的用户实体中存储此自定义值?

2 个答案:

答案 0 :(得分:1)

有几种方法可以做到这一点,这些方法都不会涉及实体中的存储库。 (说实话,可能还有很多方法可以做到这一点。)

  1. 假设您的用户模型和发票模型使用oneToMany关联,您可以在您的用户模型中使用一种方法,该方法可以循环关联的发票并即时获取总和。这意味着当前的总数不会持久存储到数据库中。

    $totalCharged = null;
    
    public function getTotalCharged()
    {
        if (null !== $totalCharged) {
            return $totalCharged;
        }
    
        $totalCharged = 0;
    
        foreach ($this->getInvoices() as $invoice) {
            $totalCharged += $invoice->getTotal();
        }
    
        return $totalCharged;
    }
    
  2. 您可以设置一个事件监听器,每次更改(创建,更新,删除)发票时都会监听,然后使用最终结果更新您的用户模型。 (假设您使用的是Doctrine ORM)。如果您尚未使用这些事件,则可能需要您更新控制器操作以包含事件。

    use Doctrine\ORM\EntityRepository;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\EventDispatcher\GenericEvent;
    
    class UserInvoiceTotalChargedSubscriber implements EventSubscriberInterface
    {
        protected $invoiceRepository;
    
        public function __construct(EntityRepository $invoiceRepository)
        {
            $this->invoiceRepository = $invoiceRepository;
        }
    
        public static function getSubscribedEvents()
        {
            return array(
                'acme.invoice.create' => 'updateTotalCharged',
                'acme.invoice.update' => 'updateTotalCharged',
                'acme.invoice.remove' => 'updateTotalCharged',
            );
        }
    
        public function updateTotalCharged(GenericEvent $event)
        {
            $invoice = $event->getSubject();
    
            if (!$invoice instanceof InvoiceInterface) {
            // Or Invoice if you are not using interfaces
                throw new \Exception(
                    sprintf('Invoice expected, %s provided', get_class($invoice)
                );
            }
    
            $user = $invoice->getUser();
    
            $totalCharged = $this->invoiceRepository
                ->getTotalChargedForUser($user);
    
            $user->setTotalCharged($totalCharged);
            // This could be moved to a separate class that performed the
            // calculation instead where you could call it like
            // $this->totalChargedCalculator->calculate($invoice->getUser());
            // Obviously this would need to be injected instead of the repository
        }
    }
    
  3. 如果您只想在树枝模板中访问此属性,则可以创建自定义树枝扩展并在其中调用它。您可以在{{ acme_invoice_total_charged(user) }}模板中使用哪个,但这并不提供相同类型的可移植性。这(与选项1一样)意味着当前总数不会持久存储到数据库中。

    class AcmeExtension extends \Twig_Extension
    {
        protected $invoiceRepository;
    
        public function __construct(EntityRepository $invoiceRepository)
        {
            $this->invoiceRepository = $invoiceRepository;
        }
    
        public function getFunctions()
        {
            return array(
                new \Twig_SimpleFunction(
                    'acme_invoice_total_charged', 
                    array($this, 'getTotalChargedForUser')
                ),
            );
        }
    
        public function getTotalChargedForUser(UserInterface $user)
        {
            return $this->invoiceRepository->getTotalChargedForUser($user);
        }
    
        public function getName()
        {
            return 'acme_invoice_extension';
        }
    }
    

答案 1 :(得分:0)

在您的UserRepository中,您可以创建一个自定义查询(例如findChargedAmount)来检索收费金额。

public function findChargedAmount($user)
{
    $em = $this->getEntityManager();
    $query = $em->createQuery('SELECT SUM(i.total) AS amount FROM MyBundle:Invoice i WHERE i.user = :user');
    $query->setParameter('user', $user);
    $sum = $query->getResult();

    return $sum[0]['amount'];
}

假设发票实体作为用户的外键。您还可以使用query builder

构建此查询

希望能帮助你。