Symfony2-访问实体中的存储库功能

Symfony2-访问实体中的存储库功能,symfony,entity,Symfony,Entity,假设我的数据库中有两个表:兔子和胡萝卜。 兔子可以有0个或多个胡萝卜,一个胡萝卜属于一只兔子。这是两个表之间的1,n关系 我有两个实体,兔子和胡萝卜 我在模板中传递了一个兔子数组,我想从每只兔子那里获得特定的胡萝卜并显示它们:假设我想从数组中的每只$rabbit中获得10个更昂贵的胡萝卜(胡萝卜价格将存储在胡萝卜表中) 比如: {% for rabbit in rabbits %} {% for carrot in rabbit.getMoreExpensiveCarrots %}

假设我的数据库中有两个表:兔子和胡萝卜。 兔子可以有0个或多个胡萝卜,一个胡萝卜属于一只兔子。这是两个表之间的1,n关系

我有两个实体,兔子和胡萝卜

我在模板中传递了一个兔子数组,我想从每只兔子那里获得特定的胡萝卜并显示它们:假设我想从数组中的每只$rabbit中获得10个更昂贵的胡萝卜(胡萝卜价格将存储在胡萝卜表中)

比如:

{% for rabbit in rabbits %}
    {% for carrot in rabbit.getMoreExpensiveCarrots %}

        {{ carrot.price }}

    {% endfor %}
{% endfor %}
我使用的是repository类,但如果我在rabbit repository类中创建函数getMoreExpensiveCarrots($rabbit),我将无法从这样的实体类访问该函数,这正是我想要的:

$rabbit->getMoreExpensiveCarrots()

我认为这样做的一种方法是在rabbit实体中创建一个getMoreExpensiveCarrots():

// Entity rabbit
class Rabbit
{
    public function getMoreExpensiveCarrots()
    {
        // Access repository functions like getMoreExpensiveCarrots( $rabbit )
        // But how can I do such thing ? Isn't that bad practise ?
        return $carrots;
    }         
}
我想我也能做到:

    // Entity rabbit
    class Rabbit
    {
        public function getMoreExpensiveCarrots()
        {
            $this->getCarrots();

            // Then try here to sort the carrots by their price, using php            

            return $carrots;
        }         
    }
这是我的控制器:

    public function indexAction()
    {
        $em = $this->getDoctrine()->getEntityManager();

        $rabbits = $em->getRepository('AppNameBundle:Rabbit')->getSomeRabbits();

        return $this->render('AppNameBundle:Home:index.html.twig', 
                array(
                    "rabbits"=>$rabbits
        ));
    }
从模板中的每个兔子调用getMoreExpensiveCarrots函数的最佳实践是什么


谢谢

您的实体类应该只关心它们所表示的对象,而完全不了解实体管理器或存储库

这里一个可能的解决方案是使用包含
getMoreExpensiveCarrots
方法的服务对象(
RabbitService
)。允许服务了解实体管理器和存储库,因此您可以在这里执行任何复杂的操作

通过使用服务对象,您可以保持关注点的分离,并确保您的实体类完成了它们想要完成的任务,仅此而已


您还可以使用第二个选项,假设胡萝卜存储在ArrayCollection中。您只需在方法中执行所需的任何排序逻辑。这很好,因为您将对实体可用的数据进行操作。

让我来解释一下。原则2 ORM确实需要重新思考。你现在的心态是,兔子应该能够在需要胡萝卜的时候查询胡萝卜。你需要改变这种心态

对于教义2,想法是在你创造兔子的时候就给兔子胡萝卜。换句话说,它是在查询时完成的。假设无论查询数据库中兔子的过程是什么,都知道您还需要一组特定的胡萝卜

在这种情况下,您需要10个最昂贵的胡萝卜,因此您的流程需要知道这一点。现在回到@Arms answer,使用名为loadRabbitsWithExpensiveCarrots的方法创建一个RabbitManager服务。返回值将是一个兔子数组,其中已经填充了胡萝卜

更新此内容以处理评论

  • 条令2存储库与Symfony 2服务
  • 存储库倾向于关注一种类型的实体,即兔子存储库最好只用于处理兔子。当您开始遇到需要多种类型实体的更为复杂的需求时,就很难确定给定功能应该位于哪个存储库中。您的应用程序(控制器)必须知道要引入哪个存储库,并且可能需要知道更多关于内部的信息

    Symfony 2服务隐藏了关于如何组织兔子和胡萝卜的所有细节。它是一个更一般的概念,可以处理涉及多个实体的更复杂的查询。它是S2的基本构建块,您确实需要熟悉它

    对于您当前的需求,两种方法都可以

  • 胡萝卜参数问题
  • 还是不确定你到底是什么意思。也许您可以发布一个示例查询?请记住,您当然可以向rabbit对象添加getExpensiveCarrots()方法。该方法将开始调用getCarrots()。返回的胡萝卜应该已经由初始查询加载。您的方法将进行筛选和排序

    请记住,我们正在努力处理一只兔子身上可能有成百上千个胡萝卜的情况。因此,出于性能考虑,我们试图避免加载所有胡萝卜。在初始查询中根本不加载胡萝卜可能更容易开始。相反,第一次调用兔子->getCarrots()时,原则2将自动发出查询并加载该兔子的所有胡萝卜。然后,您的getExpensiveCarrots方法将再次根据需要进行过滤和排序


    希望这有帮助。可能只是让你更加困惑。

    回到基本面。忘掉存储库和服务,只关注兔子和胡萝卜

    class Rabbit
    {
    /** @ORM\OneToMany(targetEntity="Carrot", mappedBy="rabbit" */
    protected $carrots;
    
    public function getCarrots() { return $this->carrots; }
    
    public function getMoreExpensiveCarrots()
    {
        // Get all carrots
        $carrots = $this->getCarrots()->toArray();
    
        // Sort by price
        // http://php.net/manual/en/function.usort.php
        usort(&$carrots,array($this,'compareTwoCarrotsByPrice'));
    
        // Now slice off the top 10 carrots (slice - carrots, hah, kindo of funny
        $carrots = array_slice($carrots, 0, 10);
    
        // And return the sorted carrots
        return $carrots;
    }
    public function compareTwoCarrotsByPrice($carrot1,$carrot2)
    {
        if ($carrot1->getPrice() > $carrot2->getPrice()) return -1;
        if ($carrot1->getPrice() < $carrot2->getPrice()) return  1;
        return 0;
    }
    }
    

    这里唯一的缺点是,对于每只兔子,条令会自动生成一个针对所有胡萝卜的单独查询。在某一点上,性能将受到阻碍。当您达到这一点时,您可以返回到原始查询,并查看如何更有效地引入胡萝卜。但是首先让上面的类工作,因为我认为这可能是您的阻塞点。

    然后我将从我的实体兔子调用该服务?您将单独调用该服务,就像从控制器调用一样。对不起,我是一个初学者,在这种情况下,我不太理解存储库和服务之间的区别,因为我必须从控制器调用它:(我不想从我的控制器调用getMoreExpensiveCarrots,而是从我模板中的每个$rabbit。实际上,在我的控制器中,我就是这样做的:Rabbts=$em->getRepository('AppNameBundle:Rabbit')->getSomeRabbits();现在我应该如何调用该服务的getMoreExpensiveCarrots?不是。有人能告诉我应该如何使用该服务吗?我如何从$rabbits调用我的getMoreExpensiveCarrots?好的,谢谢你的帮助,我现在更了解它是如何工作的了。
    {% for rabbit in rabbits %}
        {% for carrot in rabbit.getMoreExpensiveCarrots %}
    
            {{ carrot.price }}
    
        {% endfor %}
    {% endfor %}