从Doctrine的馆藏中获取特定物品的正确方法

时间:2017-12-04 21:21:28

标签: php symfony doctrine-orm doctrine

我在自己的项目中第一次使用学说。我正面临一个问题,即从一个多对多关系的学说中返回的集合中找到正确的对象。

假设我有一个实体Page,它有很多Section个子实体。

/**
 * @ORM\Entity
 * @ORM\Table(name="Pages")
 */
class Page 
{
    // bunch of properties

    /**
     * @ORM\OneToMany(targetEntity="Section", mappedBy="page")
     * @var Collection 
     */ 
    protected $sections;

    public function __construct() 
    {
        $this->sections = new ArrayCollection();
    }

    /**
     * @return Collection
     */
    public function getSections(): Collection
    {
        return $this->sections;
    }

}

现在我想要实现的是能够通过它的名称获取Section(我应该提到nameSection实体的属性)。< / p>

所以最后我希望能够实现类似的东西:

class SomeController 
{

    public function HomePageAction() 
    {
        $page = $this->getEntityManager()
                     ->getRepository('App:Entity:Page')
                     ->findOneBy(array('name' => 'homepage'));

        $section = $page->findSectionByName('header');

        // rendering etc.
    }

}

当然,我可以循环遍历所有部分并返回一个与我正在寻找的名称匹配的部分(如果没有则抛出异常)或者我想知道是否有更简单的方法可以做到这一点?另外,这是我应该在某种自定义存储库类中执行的操作,还是可以将方法findSectionByName保留在Entity类中?先感谢您。

所以,到目前为止我尝试了......

// class App\Entity\Page
public function getSectionByName(string $name)
{
    foreach ($this->getSections() as $section) {
        if ($section->getName() === $name) 
            return $section;
    }
    return null;
}

2 个答案:

答案 0 :(得分:1)

最佳做法是在您的收藏中使用匹配(条件$条件)功能。

所以:

use Doctrine\Common\Collections\Criteria;

public function getSectionByName(string $name)
{
    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('name', $name))
        ->setFirstResult(0)
        ->setMaxResults(1);

    return $this->getSections()->matching($criteria)->first();
}

如果您想抛出未找到的异常,最佳做法是在您的操作中执行此操作:

public function HomePageAction() 
{
    $page = $this->getEntityManager()
                 ->getRepository('App:Entity:Page')
                 ->findOneBy(array('name' => 'homepage'));

    $section = $page->findSectionByName('header');

    if($section === false) {
        //here throw your exception.
    }
    // rendering etc.
}

有关过滤教条集合的更多信息,请参阅Doctrine - Working with Associations

答案 1 :(得分:1)

您还可以在Page实体

中生成自定义存储库
 /**
 * @ORM\Entity(repositoryClass="App\Repository\PageRepository")
 */
class Page
{
    ....
}

之后,在App\Repository\PageRepository定义函数中,将逐页和部分名称

获取
    // App\Repository\PageRepository
    public function getSectionByPageAndName($pageName, $sectionName)
    {
        return $this->getEntityManager()
            ->createQueryBuilder()
            ->select('s')
            ->from(Page::class, 'p')
            ->join(Section::class, 's')
            ->where('p.name = :pageName')
            ->andWhere('s.name = :sectionName')
            ->setParameter('pageName', $pageName)
            ->setParameter('sectionName', $sectionName)
            ->getQuery()
            ->getResult();
    }

之后,您可以轻松完成此功能 一遍又一遍,只需在你的控制器中调用存储库上的函数

class SomeController
{

    public function HomePageAction()
    {
        $sections = $this->getEntityManager()
            ->getRepository('App:Entity:Page')
            ->getSectionByPageAndName($pageName, $sectionName);

        //etc
    }

}

因为您的关系是@OneToMany,如果sectionName不唯一$sections将是空数组或Section个对象的数组,如果您想限制只有一个结果或其他内容请查看docs