Symfony2 и Doctrine2 Repository

Я тут подумал, что лучше писать меньше, но чаще :). Хочется конечно написать большой материал, но времени постоянно не хватает.

Symfony2 и Doctrine2 Repository.

На форуме Игорь Негруца сделал мне замечание по поводу построения DQL запросов прямо в коде контроллеров. Есть такое дело и давно хотелось его поправить.

Для начала нужно в сущности явно указать привязку к репозиторию. В аннотациях это делается так:

/**
 * \Application\PortfolioBundle\Entity\Project
 *
 * @orm:Table(name="portfolio_projects")
 * @orm:Entity(repositoryClass="Application\PortfolioBundle\Repository\ProjectRepository")
 */
class Project

Дальше генерируем наши кастомные репозитории:

/var/www/test/symfony2 $ ./app/console doctrine:generate:repositories PortfolioBundle
Generating entity repositories for "PortfolioBundle"
  > OK generating Application\PortfolioBundle\Repository\ProjectRepository
  > SKIP no custom repository for Application\PortfolioBundle\Entity\Category

Теперь попробую порефакторить существующий экшн. Например вот этот:

    /**
     * Display links to prev/next projects
     *
     * @param Category $category
     * @param Project $project
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function nearbyProjectsAction($category, $project)
    {
        $em = $this->get('doctrine.orm.entity_manager');
 
        // get all projects from this category
        $query = $em->createQuery('SELECT p FROM PortfolioBundle:Project p JOIN p.categories c WHERE c.id = ?1 ORDER BY p.date DESC');
        $query->setParameter(1, $category->getId());
        $projects = $query->getResult();
 
        // get next and previous projects from this category
        $i = 0; $previousProject = null; $nextProject = null;
        foreach ($projects as $p) {
            if ($project->getId() == $p->getId()) {
                $previousProject = isset($projects[$i-1]) ? $projects[$i-1] : null;
                $nextProject     = isset($projects[$i+1]) ? $projects[$i+1] : null;
                break;
            }
            $i++;
        }
 
        return $this->render('PortfolioBundle:Project:nearby-projects.html.php',
                array(
                    'category' => $category,
                    'previousProject' => $previousProject,
                    'nextProject' => $nextProject,
                ));
    }

Он выводит блок ссылок на предыдущий/следующий проект по отношению к текущему проекту.

Для выборки всех проектов из определенной категории создаю в репозитории метод getProjectsByCategory(). Получается следующее:

<?php
 
namespace Application\PortfolioBundle\Repository;
 
use Doctrine\ORM\EntityRepository;
 
/**
 * ProjectRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class ProjectRepository extends EntityRepository
{
    /**
     * Get all projects from this category
     * 
     * @param \Application\PortfolioBundle\Entity\Category $category
     * @return array
     */
    public function getProjectsByCategory(\Application\PortfolioBundle\Entity\Category $category)
    {
        $query = $this->getEntityManager()
                ->createQuery('SELECT p FROM PortfolioBundle:Project p
                    JOIN p.categories c WHERE c.id = ?1 ORDER BY p.date DESC');
        $query->setParameter(1, $category->getId());
 
        return $query->getResult();
    }
}

А в контроллере просто пишу:

        // get all projects from this category
        $projects = $em->getRepository("PortfolioBundle:Project")
                ->getProjectsByCategory($category);

Красота 🙂

Я воспринимал репозитории как дата мапперы, но Саша Стешеко подсказал, что это отдельный паттерн.

И офф. документация доктрины “Custom Repositories”.

12 thoughts on “Symfony2 и Doctrine2 Repository

  1. Степа, объясни, зачем ты аттачишь картинки с какими-то нерелевантными телками к своим блогозаписям?

    • напрягают картинки или именно телки :)?
      по мне так живей блог смотрится. если вообще без картинок, то скучно и серо.

    • убрал немного, а то перебор.
      Кейт Хадсон оставил. она довольно релевантная )

  2. Девушки в целом ни в коем случае не напрягают, просто они совершенно не в тему в данном контексте. Статья о программинге же.

    Так обычно поступают на Хабре: размещают картинку что б человек интереса ради проследовал под кат.

    Спасибо за понимание.

  3. Для большей гибкости, я думаю, что между репозитариями и контроллером, должен быть еще один слой (службы, команды).
    И контроллер ничего не должен знать о $em. Зачем контроллеру знать о ORM?
    Просто логика модели “расплываеться” по контроллерам, и нет возможности подменить реализацию.

    • В целом правильно думаешь, но меня пока такой уровень абстракции вполне устраивает.

  4. Спасибо за материал. Но я вот гуглю один вопрос и никак не могу найти ответ – возможно, поможете.
    Задача достаточно простая: есть Category и Post (1:N)
    Как на модели Category определить методы getOldPosts(), getSpamPosts() и т.д.?

  5. Степан, в репозиториях только возможны методы которые извлекают данные или также delete, insert, update?

Leave a Reply

Your email address will not be published. Required fields are marked *