in Профессиональное

О «symfony best practices»

Кросспост моего хабратопика.

Nicolas Perriault представлял на SymfonyDay’09 презентацию “30 Symfony Best Practices”. Кое-что из его практик очевидно (было мне известно), кое-что не было. Но есть две практики, которые мне совершенно не видятся как “best”. О них я и хочу поговорить.

Итак:

#4
Никаких экземпляров Criteria (Propel) или Doctrine_Query, SQL запросов и любой ORM/RDBMS специфики не должно быть ни в шаблонах ни в экшенах (actions);
Чем сильнее вы привяжете модель к контроллерам и видам, тем более инертным к изменениям будет ваш бэкэнд.

Далее следует несколько примеров:

// ПЛОХО
public function executeRecentProducts( sfWebRequest $request )
{
    $this->products = Doctrine::getTable( 'Product' )
        ->createQuery( 'p' )
        ->where( 'p.is_published = 1' )
        ->orderBy( 'published_at DESC' )
        ->limit(10)
        ->execute();
    // Плохо, получаем Doctrine_Collection
}

// ЧУТЬ ЛУЧШЕ
public function executeRecentProducts( sfWebRequest $request )
{
    $this->products = Doctrine::getTable( 'Product' )
        ->createQuery( 'p' )
        ->where( 'p.is_published = 1' )
        ->orderBy( 'published_at DESC' )
        ->limit(10)
        ->fetchArray();
    // Уже лучше, Array
}

// ХОРОШО
public function executeRecentProducts( sfWebRequest $request )
{
    $this->products = ProductTable::getRecent( $max = 10, $published = true );
    // Array, идеально ))
}

Итак, что же предлагает Николас? С тем что нужно избегать Doctrine_Query и т.п. в видах и действиях – с этим я согласен. Но он также предлагает передавать во view только массивы (см. примеры выше). На словах выглядит неплохо, но зачастую может возникнуть проблема с подтягиванием связанных записей (1:n или n:n). Опять же, подтягивать в виде заранее не выбранные при джойне записи – это можно сказать “плохой тон” разработки. Но с другой стороны это происходит совершенно прозрачно для разработчика (и при необходимости отлавливается через webDebug).

Другой неприятный момент в передаче массивов в вид в том, что какое-то из передаваемых значений может потребовать предварительной обработки перед выводом, что придется выполнять явно в действии или в *Table классе. Если же у нас есть объект, то мы можем вызвать например метод getMyField() вместо getField().

#25
Избегайте помещения под версионный контроль любые из генерированных классов вида Base*, в особенности, если вы хотите писать плагины для многократного использования или же хотите перераспределять вашу работу. Почему? Возможно что-то захочет расширить ваши классы модели или же добавить к ним behavior другой.

Что меня беспокоит здесь? То, что в репозитории не хранится целостное приложение. Т.е. модель конечно есть, схема есть. Но отсутствуют классы, от которых наследуется ваша модель. Таким образом, осуществляя вынос вашего приложения на production сервер, вы всегда должны помнить, что помимо update’а кода, выполнения миграции (которая еще не факт что выполнится при отсутствии Base* классов), выполнения дополнительных процедур, присущих конкретному релизу, вы должны будете еще пересобрать и модель. Согласитесь, еще один элемент сакральных знаний, который со временем (особенно на больших проектах) переходит в область чего-то почти магического.

В Doctrine 2.0 обещают уйти от наследования Base* классов, так что, возможно, скоро эта практика утратит актуальность. Но пока мы имеем Doctrine 1.2 ))

Ну что, коллеги, а вы что думаете об этих двух практиках? Как поступаете изо дня в день?

Write a Comment

Comment

*

  1. Привет.

    №4: Да, всё так. Но он потом исправился — Optimize your Doctrine Workflow with Specialized Queries

    №25:

    Согласитесь, еще один элемент сакральных знаний

    Не соглашусь. Во-первых, ничего сакрального — ну нужны базовые классы, ничего не поделаешь.
    Есть ещё риск забыть их сгенерить. Но это если деплоить руками. А зачем деплоить руками, если можно деплоить скриптом и/или rsync?

    • А вот и нет. У него везде fetchArray() ))

      А по поводу моделей – вообще надо попробовать. Но что-то я не в восторге.