Как выполнять запросы в сущности?
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));
Но, очевидно, это не сработает.
Вообще-то, вы не должны этого делать.
Сущности, как правило, не должны знать об объектном менеджере (напрямую или через некоторый промежуточный объект).
Причиной этого является в основном тестируемость, но, по моему опыту, это помогает держать вещи организованными другими способами.
Я бы подошел к нему, создав класс обслуживания, который обрабатывает запросы для вас. Ваш контроллер (или что-то еще) будет управлять им следующим образом:
<?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), чтобы избежать частых поисков, вы бы сделали это где-то рядом или в этом классе обслуживания. Это упрощает и упрощает ваши сущности и легко проверяется. Поскольку вы вводите свой сущ. Человек в службу во время строительства, вы можете издеваться над этим по мере необходимости.
getFavoriteCommentaries () может использовать различные реализации. Тривиальным было бы проксировать его Member :: getFavoriteCommentaries (), который фактически загрузил бы все, а затем отфильтровал бы «любимые». Вероятно, это будет не очень хорошо масштабироваться, поэтому вы можете улучшить его, используя EM для получения только необходимых данных.
Ваш 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; } );
как$idsToFilter = array(1,2,3,4); $member->getComments()->filter( function($entry) use ($idsToFilter) { if (in_array($entry->getId(), $idsToFilter)) { return true; } return false; } );
(не испытано)
Обратите внимание, что такой метод будет перебирать и загружать все ваши комментарии, поэтому в случае, если у Пользователя есть много, это может быть большим узким местом;
В большинстве случаев вы хотите использовать пользовательские репозитории, где вы можете разместить такую логику.
Как предложил timdev, вы можете создать MemberService, который будет переносить такой вызов, зная EntityManager.
Разделение сущностей с уровня сопротивления – большое улучшение по сравнению с Доктриной 1, и вы не должны нарушать это правило.
Использовать пользовательский репозиторий для запросов
Вы не должны писать запросы в своих сущностях, но для этого вы должны использовать репозиторий. Это также объясняется в документации по доктрине 7.8.8 Пользовательские репозитории . Он позволит вам создавать ваши пользовательские запросы на центральном месте и сохраняет чистоту сущностей.
Используйте критерии для фильтрации коллекций:
Но если вы хотите фильтровать внутри своей коллекции в методе get
вы можете использовать Criteria
. Вы можете прочитать, как использовать Criteria
в документации Doctrine. 8.8. Фильтрация коллекций . Фильтровать, как вы хотите сделать, будет выглядеть примерно так:
Объявите в верхней части класса объекта класс Criteria
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; }
Ваш вопрос был очень трудно понять, пожалуйста, попытайтесь работать над тем, как вы структурируете свои вопросы в будущем. Например, вы говорите «возврат назад того же результата», но «фильтр», что может означать что угодно. Вы хотите использовать тот же набор результатов (почему бы вам никогда не захотелось это сделать), и просто используйте 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 ();
Я согласен с «timdev». Вы не должны определять запрос в классе объектов. Мой способ определить класс сервиса поддерживает сущности – это классы репозитория. Например: User (entity – YourBundle / Entity / User.php) будет иметь UserRepository (класс обслуживания – YourBundle / Repository / UserRepository.php). Ваш метод «фильтр» должен быть здесь. Вам просто нужно сопоставить этот класс обслуживания в классе сущности. В вашем контроллере вы всегда можете получить доступ к «фильтру» через свой репозиторий. Это документально подтверждено в книге Symfony2