Pull to refresh

Comments 21

UFO just landed and posted this here
UFO just landed and posted this here
Вы может какую другую доктрину использовали, ибо никаких проблем ни с тем же экранированием, ни с кешированием, ни с невалидными SQL запросами я не встречал. Точно так же как не видел ненужного дублирования кода, отсутствия целостности API и громоздкого кода при использовании…

На поддержке остался только один проект на Yii к счастью, и мне больно использовать родной AR уже, не удобно… особенно миграции (привык я к migration:diff доктрины).
а чем именно Вас не устраивает Doctrine 2?

и как я писал в заключении
Был бы очень признателен, если бы в комментариях Вы поделились своими вариантами решения по внедрению паттерна DataMapper, каких-то других ORM в Yii, о своих способах решения разрастания бизнес логики в моделях ActiveRecord в Yii, о предметно-ориентированном программировании с использовании Yii


как бы Вы решили такую проблему?
Когда-то давно я тоже столкнулся с подобной проблемой, и даже задавал этот вопрос на QA. toster.ru/q/46088#from_trackerИзначально в приложении
было огромное количество плейнтекстовых sql-запросов, данные фетчились в ассоциативные массивы.
Извиняюсь, промахнулся мимо кнопки.

Когда-то давно я тоже столкнулся с подобной проблемой, и даже задавал этот вопрос на QA. toster.ru/q/46088#from_tracker
Изначально в приложении было огромное количество плейнтекстовых sql-запросов, данные фетчились в ассоциативные массивы.

В итоге запилил свой собственный велосипед. Получилось весьма легковесно и быстро, работает автодополнение в IDE, кеширование, автовалидация, построчная загрузка из датасета и прочие полезняшки.

Идея не нова — для начала описываем объекты-входные параметры, объекты-выходные параметры. Резалтсет должен наследоваться от специального абстрактного класса.

class CCotoCustQueryParameters{
    function __construct()
    {
        $this->CUSTNO = new DBQuery\Parameters\CIntegerParameter();
    }
}


class CCotoCustQueryRecordSet extends DBQuery\ResultSet\ObjectResultSet {
    function __construct()
    {
        $this->CUST_CUSTNO = new DBQuery\Parameters\CIntegerParameter();
        $this->CUST_NAME = new DBQuery\Parameters\CStringParameter();
        $this->CUST_ADDR = new DBQuery\Parameters\CStringParameter();
        $this->CUST_WTEL = new DBQuery\Parameters\CStringParameter();
    }
}


… а затем используем эти объекты по прямому назначению

//Объявляем источник параметров
$coto_params = new SqlSchema\Service\CCotoCustQueryParameters();

//У нас параметр всего один - заполняем его из переданных в форму параметров
$coto_params->CUSTNO->setValue($reportParams->woCOTOCustNo->getValue());

//Источник SQL - плейтнекстовый файл, унаследован от CAbstractSource
$coto_sqlsource = new DBQuery\SqlSource\CTextFileSource('service/coto_cust');

//подгружаем в текстовый файл ранее забитые переменные
$coto_sqlsource->loadObject($coto_params);

//создаем экземпляр резалтсета
$coto_resultset = new SqlSchema\Service\CCotoCustQueryRecordSet();

//Связываем источник sql и массив выходных резалтсетов (их может быть больше одного, если столько отдаёт запрос)
$coto_query = new CDBQuery($coto_sqlsource,array($coto_resultset));

//Ну и выполняем
$coto_query->ExecuteSQL();



Теперь объект $coto_resultset можно просто передать в view. Конкретно этой вьюхи у меня сейчас нету, но есть другая. Там уже можно поиграться с форматированием, например. При наличии правильных тегов phpdoc автодополнение IDE работает и во вьюхах.

<td><?=$rs_workorders->GRECNO->getValue()?></td>
<td><?=$rs_workorders->CREATED->format(CDateTimeParameter::PhpOutputFormatDateOnly)?></td>
<td><?=$rs_workorders->BILLD->format(CDateTimeParameter::PhpOutputFormatDateOnly)?></td> 
<td style='text-align: right'><?=$rs_workorders->SUM_WORK->formatMoney()?></td>
<td style='text-align: right'><?=$rs_workorders->SUM_ITEM->formatMoney()?></td> 


Если кому интересно — могу рассказать об этом велосипеде подробнее, а то и в паблик выложить.
не вижу особо преимуществ даже перед родным AR, не то что перед доктриной.
Doctrine такое барахло. Что-то посложнее бложика и 90% запросов один фиг QueryBuilder. Элементарный запрос, где в where стоит что-либо отличное от «равно» — добро пожаловать QueryBuilder. Ладно бы еще Doctrine позволяла plain SQL прогонять, так нет же сиди настраивай ResultSetMapping. Кэширование — черный ящик какой-то, вроде все по туториалу ставишь, а хрен пойми то ли кэширует, то ли не кэширует. Да и вообще не должна Модель заниматься кэшированием. Translatable — это вообще отдельный пи… ец, о котором даже говорить неохота. DQL — бредятина, вот не лень было придумывать еще абстракции над SQL.

Да и вообще в ORM реальная польза есть только от всяких связей one-to-many, many-to-one. Все остальное хлам. Работать с данными в виде объектов тот еще гемор: чуть-чуть нестандартный вывод в шаблоне — добро пожаловать велосипедить всякие функции для объектов, когда для массивов есть целая орда встроенных в язык функций.
давайте по порядку:
Используйте DQL для выборок, это удобно. Используют же люди LINQ с SQL подобным синтаксисом. Выражения поддерживаются, можно объединять сложные выражения в свою функцию (например GEODISTANCE), в итоге у нас получаются красивая выборка из объектов для нашей бизнес логики, которой глубоко плевать откуда пришла эта выбора. В YII с этим дело обстоит если не так же то хуже. И ни в одной другой ORM.

По поводу plain SQL — так позволяет же. причем на выходе вы можете указать гидрацию не в объекты а в массив и разбирать все руками. Все эти ResultMapping они для более сложных кейсов.

По поводу кеширования — у вас модель ничего и не знает о нем. Этим занимается сервисный слой который сохраняет данные. Модель вообще ничего не знает где она хранится.

Translatable — не использовал в продакшене так что не могу ничего сказать. Но ничего страшного в нем не увидел. То что нужно для DDD и т.д.

ORM и созданы для работы со связями, так что ничего удивительного. Object-relation mapping как говорится из названия, это отображение данных в реляционных СУБД на ваши доменные-модели.

Главный плюс доктрины в том, что она вынесена целиком и полностью в сервисный слой. Это значит что вы можете без особых проблем в будущем заменить ORM скажем на ODM, не меняя при этом сами модели (или просто сменить ORM, или часть данных хранить где-то еще).

У вас есть только репозиторий ваших моделей, который по хорошему так же должен абстрагироваться от доктрины (имеется в виду что для каждой энтити свой репозиторий реализующий свой интерфейс). Тогда достигается максимальный профит при дальнейшем расширении и поддержке.

Или вы хотите сказать что в Yii со всем что вы перечислили плохо? Или вы предлагаете полностью отказаться от ORM? С точки зрения бизнес логики у нас все равно останутся репозитории/провайдеры, а что они используют глубоко плевать.
ДА я Yii-то и не защищаю, так как особо не работал с ним. А вот с доктриной опыт работы был, впечатления только отрицательные. Столько кода я даже на банальном QueryBuilder от какой-нибудь Kohana не писал. Вот меня все время возмущает, ну почему бы не сделать поддержку в методах find(), findAll() других знаков кроме "=". Вот надо сделать, скажем, условие с неравенством, сиди пиши queryBuilder.

Кстати, бесячий баг (или это фича?) поправили, когда для использования связи надо было спецом джойнить нужную модель в QueryBuilder. К примеру, есть модели Article и User, у Article есть связь на User (getUser). Если я напишу какой-нибудь запрос с QueryBuilder для Article и не заджойню явно User, то метод $article->getUser() вернет NULL.

По поводу кеширования — у вас модель ничего и не знает о нем. Этим занимается сервисный слой который сохраняет данные. Модель вообще ничего не знает где она хранится.


А по-хорошему кэширование вообще надо вынести из доктрины, кэшированием контроллер должен заниматься, а не доктрина.

Translatable — не использовал в продакшене так что не могу ничего сказать. Но ничего страшного в нем не увидел. То что нужно для DDD и т.д.


Открываете профайлер, смотрите на 100500 запросов, в ужасе закрываете.

Главный плюс доктрины в том, что она вынесена целиком и полностью в сервисный слой. Это значит что вы можете без особых проблем в будущем заменить ORM скажем на ODM, не меняя при этом сами модели (или просто сменить ORM, или часть данных хранить где-то еще).


Конечно БД мы каждый день меняем. Тяни ради этого громоздкую и тормозную библиотеку
Я вообще стараюсь не использовать методы findAll или find или findBy. Как я уже говорил, репозитории у меня реализуют просто интерфейс, и зарегистрированы как сервисы (провайдера дынных по сути). Пока правда есть проблемы с менеджерами записей, контроллер все равно должен делать flush, с этим я пока не разобрался полностью.

Джойнить в любом случае нужно (вы же хотите сделать джойн, иначе какой в этом смысл). Но если вы в select не указали, то getUsers за счет ленивой подгрузки должен вернуть все. Хотя нужно проверить, но я не помню что бы у меня были какие-то проблемы с этим.

Кеширование в доктрине нужно для внутренних целей. Так что все в порядке. Именно кеширование запросов да — оно там не нужно, но я и не использую.

По поводу 100500 запросов — помню было дело, мне стандартный пагинатор (от KnpBundles) дико бесит, потому и отказался от него. Но в случае с Translatable вроде бы ничего особо страшного не приметил, увы не много с ним возился ибо потом было решено отказаться от хранения этого всего в MySQL в пользу монги (нужны были гео-индексы и индексация массивов по ключу).

По поводу смены базы данных — нет не каждый день. Но у меня были случаи когда часть данных уходило из локальной базы в базу клиента с доступом по API. В этом случае мне пришлось только переписать репозитории для нескольких сущностей и все.

Вообще на вкус и цвет. Мне нравится тот контроль который дает доктрина, мне нравится подход с мэппингом таблиц (объекты проецируются на базу а не наоборот). Если вам не нравится — не используйте. Но говорить о том что доктрина не нужна или сильно ущербна, это уж как-то слишком громко.

p.s. Так а что вы используете в конечном счете? Просто PDO/plain sql?
Сейчас работаю с Rails, поэтому ActiveRecord. До этого кроме Symfony2 и Doctrine2 работал со встроенной в Кохану ОРМ, а также с обычным queryBuilder. Это на работе, для себя есть желание написать свой велосипед: взять обычный queryBuilder и немного расширить его функционал, всякие scope, relationship
> о своих способах решения разрастания бизнес логики в моделях ActiveRecord в Yii

А зачем её там вообще хранить?

потому что это определение active record? Ну то есть если мы убираем всю бизнес логику из AR моделек, и оставляем там только тупое хранение данных и доступ к рядам таблиц через объектную прослойку — это будет уже не AR. У этого подхода есть свое имя — row data gateway, и это вполне себе норм практика.


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

Как бы да, но я склонялся в ответе к тому, что MVC это всё же Presentation layer, а не Domain или Data source. Для простоты наверное в этом фрейме AR поселили в M…
Only those users with full accounts are able to leave comments. Log in, please.

Articles