Если вы работаете над большим проектом на symfony + Doctrine и у вас много моделей и сложных запросов, вам обязательно потребуется способ, как хранить и использовать эти запросы, не теряя преимуществ ООП и более прямым способом, нежели традиционные способы addNamedQuery() и createNamedQuery(). Ниже приводится такой способ.
Идея состоит в следующем: мы создаем query-классы для текущей модели. Таким образом, мы можем создавать необходимые методы для реализации бизнес-логики. В теории звучит очень просто. Даввайте попробуем разобрать конкретный пример. Рассмотрим для начала YAML-модель:
BlogAuthor:
columns:
id:
type: integer(4)
primary: true
autoincrement: true
name:
type: string(255)
relations:
Post:
type: one
class: BlogPost
local: id
foreign: author_id
BlogPost:
columns:
id:
type: integer(4)
primary: true
autoincrement: true
author_id:
type: integer(4)
notnull: true
title:
type: string(255)
content:
type: string(65535)
relations:
Author:
type: one
class: BlogAuthor
local: author_id
foreign: id
Comments:
type: many
class: BlogComment
local: id
foreign: post_id
BlogComment:
columns:
id:
type: integer(4)
primary: true
autoincrement: true
post_id:
type: integer(4)
notnull: true
author:
type: string(255)
content:
type: string(5000)
relations:
Post:
type: one
class: BlogPost
local: post_id
foreign: id
Теперь давайте представим Query-класс, отвечающий таблице BlogPost:
<?php
class BlogPostQuery extends Doctrine_Query
{
static public function create($conn = null, $class = null)
{
return parent::create($conn, 'BlogPostQuery')
->from('BlogPost p');
}
public function addPosts($fields = 'p.*')
{
return $this->addSelect('p.*');
}
public function addComments($fields = 'c.*')
{
return $this
->addSelect($fields)
->leftJoin('p.Comments c')
->addGroupBy('c.id');
}
public function addAuthors($fields = 'a.*')
{
return $this
->addSelect($fields)
->leftJoin('p.Author a')
->addGroupBy('a.id');
}
public function addCommentsCount($alias = 'nb_comments')
{
return $this
->addSelect(sprintf('COUNT(c.id) as %s', $alias))
->addGroupBy('c.id');
}
public function filterByAuthorName($authorName)
{
return $this
->andWhere('a.name = ?', $authorName);
}
}
И как же мы можем использовать этот Query-объект? Вот несколько use-cases:
// Получаем все посты
$posts = BlogPostQuery::create()
->addPosts()
->fetchArray();
// Получаем все посты с комментариями
$posts = BlogPostQuery::create()
->addPosts()
->addComments()
->fetchArray();
// Получаем все посты с комментариями и числом комментариев для каждого поста
$posts = BlogPostQuery::create()
->addPosts()
->addComments()
->addCommentsCount('yataa')
->fetchArray();
// Получаем все посты автора chuck и их комментарии
$posts = BlogPostQuery::create()
->addAuthors()
->addPosts()
->addComments()
->filterByAuthorName('chuck')
->fetchArray();
// и т.д...
Конечно же наш пример слишком прост, чтобы понять все возможные преимущества такого подхода, но при работе с десятками i18n объектов этот подход поможет расчистить ваши классы модели, контроллеры и оптимизировать вашу работу.
Некоторые уточнения
Некоторые пользователи давали негативный фидбэк на описанную выше технику, поясняя свою позицию тем, что она будет поощрять использование пользовательских query-объектов напрямую в контроллерах. Это совсем не так, поскольку запросы должны быть использованы только в рамках модели, например, в классе BlogPostTable:
<?php
class BlogPostTable extends Doctrine_Table
{
static public function getPostsWithCommentsByAuthor($authorName)
{
return BlogPostQuery::create()
->addPosts()
->addComments()
->filterByAuthorName($authorName)
->fetchArray()
;
}
}
И в контроллере:
class blogActions extends sfActions
{
public function executeListByAuthor(sfWebRequest $request)
{
$this->posts = BlogPostTable::getPostsWithCommentsByAuthor(
$request->getParameter('author')
);
}
}
По мотивам http://prendreuncafe.com/blog/post/Optimize-your-Doctrine-Workflow-with-Specialized-Queries. Have fun ))
2 Comments
«По мотивам»… скромненько ;)
)) не нравится формулировка? я указал источник, вроде бы все должны быть довольны