Доктрина 2, запрос внутри сущностей - PullRequest
6 голосов
/ 15 августа 2011

Как выполнять запросы в сущности?

namespace Entities\Members;

/**
 * @Entity(repositoryClass="\Entities\Member\MembersRepository")
 * @Table(name="Members")
 * @HasLifecycleCallbacks
 */
class Members extends \Entities\AbstractEntity
{
    /**
     * @Id @Column(name="id", type="bigint",length=15)
     * @GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /** 
     * @Column(name="userid", type="bigint", length=26, nullable=true) 
     */
    protected $userid;

    /** 
     * @Column(name="fname", type="string", length=255,nullable=true) 
     */
    protected $fname;

    /**
     *  @OneToMany(targetEntity="\Entities\Users\Wall", mappedBy="entry", cascade={"persist"}) 
     */
    protected $commententries;

    public function __construct()
    {
        $this->commententries = new \Doctrine\Common\Collections\ArrayCollection();
    }
}

Пример. Я бы хотел, чтобы внутри этой сущности была функция: filter() и я хочу иметь возможность фильтровать коллекцию commententries. Он должен вернуть коллекцию с определенным условием, таким как id=1. По сути, это должна быть фильтрация данных, полученных из запроса на соединение.

Так что-то вроде этого:

$this->commententries->findBy(array('id' => 1));

Но, очевидно, это не работает.

Ответы [ 5 ]

21 голосов
/ 16 августа 2011

Ваша ArrayCollection уже реализует метод filter (), вам нужно передать Closure, чтобы заставить его работать с вашими сущностями (здесь, commentEntries).

$idsToFilter = array(1,2,3,4);

$member->getComments()->filter(
    function($entry) use ($idsToFilter) {
       if (in_array($entry->getId(), $idsToFilter)) {
           return true;
       }

       return false;
    }
); 

(не проверено)

Обратите внимание, что такой метод будет повторяться и нетерпеливо загружать по всем вашим комментариям, поэтому в случае, когда у пользователя много, это может быть большим узким местом;

В большинстве случаев вам нужноиспользовать собственные репозитории, где вы можете разместить такую ​​логику.

Как предложил Тимдев, вы можете создать MemberService, который будет оборачивать такой вызов, зная EntityManager.

Отделение сущностей отУровень сопротивления является большим улучшением по сравнению с Доктриной 1, и вы не должны нарушать это правило.

12 голосов
/ 16 августа 2011

Вообще говоря, вы не должны этого делать.

Сущности, как правило, не должны знать о менеджере сущностей (напрямую или через некоторый промежуточный объект).

Причиной этого является в основном тестируемость, но, по моему опыту, она помогает организовать вещи другими способами.

Я бы подошел к этому, разработав класс обслуживания, который будет выполнять поиск для вас.Ваш контроллер (или что-то еще) будет управлять им так:

<?php
// create a new service, injecting the entitymanager.  if you later wanted 
// to start caching some things, you might inject a cache driver as well.
$member = $em->find('Member',$member_id); //get a member, some how.
$svc = new MemberService($em);

$favoriteCommentaries = $svc->getFavoriteCommentaries($member);

Как я намекаю в комментарии, если позже вы решите, что хотите добавить кэширование (например, через memcached), чтобы избежать частых поисков,Вы бы сделали это где-нибудь рядом или в этом классе обслуживания.Это делает ваши сущности красивыми, простыми и легко проверяемыми.Поскольку вы внедряете свой EntityManager в сервис во время создания, вы можете смоделировать это при необходимости.

getFavoriteCommentaries () может использовать различные реализации.Тривиальным было бы передать его в Member :: getFavoriteCommentaries (), который фактически загрузит все, а затем отфильтровать «любимые».Вероятно, это не будет особенно хорошо масштабироваться, поэтому вы можете улучшить его, используя EM для извлечения только тех данных, которые вам нужны.

5 голосов
/ 11 октября 2013

Использовать пользовательский репозиторий для запросов

Вы не должны писать запросы в своих сущностях, но вы должны использовать репозиторий для этого.Это также объясняется в документации доктрины 7.8.8 Пользовательские репозитории .Это позволит вам создавать свои пользовательские запросы в центральном месте и поддерживать четкие определения сущностей.

Использовать критерии для фильтрации коллекций:

Но если вы хотите отфильтроватьвнутри вашей коллекции в методе get вы можете использовать Criteria.Вы можете прочитать о том, как использовать Criteria в документации Доктрины 8.8 Фильтрация коллекций .Чтобы фильтровать, как вы хотите, выглядело бы что-то вроде этого:

Объявите в верхней части вашего класса сущности Criteria class

use Doctrine\Common\Collections\Criteria

В вашем методе getCommentEntries используйте классотфильтровать:

public function getCommentEntries()
{
    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('id', 1));

    $filteredCommentEntries = $this->commententries->matching($criteria);

    return $filteredCommentEntries;
}
1 голос
/ 06 мая 2012

Я согласен с "тимдев". Вы не должны определять запрос в вашем классе сущностей. Мой способ определения класса обслуживания поддержки сущностей - это классы репозитория. Например: Пользователь (entity - YourBundle / Entity / User.php) будет иметь UserRepository (класс обслуживания - YourBundle / Repository / UserRepository.php). Ваш метод "фильтра" должен быть здесь. Вам просто нужно отобразить этот класс обслуживания в вашем классе сущности. В вашем контроллере вы всегда можете получить доступ к «фильтру» через его репозиторий. Это подробно описано в книге Symfony2

1 голос
/ 15 августа 2011

Ваш вопрос было действительно трудно понять, пожалуйста, попробуйте и поработайте над тем, как вы будете структурировать свои вопросы в будущем.Например, вы говорите «вернуть тот же результат», но «фильтр», что может означать что угодно.Хотите ли вы использовать один и тот же набор результатов (с какой стати вы когда-либо решили это сделать) и просто использовать array_filter или array_walk для фильтрации результатов или вы действительно хотите использовать условное соединение?Это невероятно неоднозначно.

В любом случае .. ответ (после прочтения вашего вопроса 4 раза).

$q = $qb->select ( "m","w" )
            ->from ( "Members", "m" )
            ->leftJoin( "m.commententries","w",'WITH', 'w.id = :id')
            ->setParameter ( "id", $id )
            ->getQuery ();
...