Критика работы с БД в SimplePHPframework от AmdY

WMix

герр M:)ller
Партнер клуба
такая горячая дискусия,....

на самом деле, это уже далеко не код студента, и конечно же это не код группы людей с инженерами.. конечно все сильно ужато, ужато на столько, что AmdY может еще все держать в голове и проектировать дальше, натыкаясь на грабли,.. в принципе достаточно абстрактно написано, не будте столь критичными...

но гдето прав и Фанат, мне было бы такого набора инструментов тоже мало... но я всеже надеюсь что это не конец а только начало...
и возможно еслиб он был не так резок, никогоб не задело (я тоже медленно привыкаю к марксу, коту и вопросительному знаку с крадким именем)

меня как человека ленивого останавливает отсутствие документации,... бегло пробежавшись глазами по коду, в голове осталось менее 5% ... те заметил пару удобных вещей, ну да все это уже я видел, и всего этого есть хорошо описанное...

но не останавливайся, AmdY, и не затормаживайся на документации,.. делай дальше.. послушай что написал фанат, и выбери только то что считаешь правильным..
это твой FrameWork и только ты знаешь о его будущем... ;)
 

Фанат

oncle terrible
Команда форума
Вот же ж блин о чем угодно почему-то каждый желает поговорить, только не о деле.
Окей желаешь внезапно поговорить о пдо - давай поговорим о пдо.

пдо - это недодал с раздутым самомнением.
с точки зрения апи у меня к нему претензий нет.
с точки зрения дал у него не сделано и половины необходимого функционала. хотя корежит из себя суперабстракцию. с этой точки зрения она во-первых, занимается не своим делом, а во-вторых - делает это херово.

Я не требую от пдо функционала ДАЛ. Она сама лезет на эти галеры. Раз полезла - я могу её критиковать за убогую реализацию.

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

Претензии у меня к расширителям, которые
а) не глядя тупо копируют функционал пдо, считая его идеальным
б) не сделав толком работу с скл, бегут к пленительным высотам ормов.
в) как следствие пункта бэ, начинают решать проблемы конструирования SQL средствами орм.
 

fixxxer

К.О.
Партнер клуба
fixxxer
вообще любые? а как перпареды эмулируешь?
Руками, и вообще я глубоко унутрях юзаю прекрасный годами проверенный mysql extension и идите в топку со своими deprecated (есличе - на mysqli переделывается за 5 минут). Толку от нетипизированного плейсхолдера мало. Нативные, да, теряю но и хрен с ними, это проще, чем думать каждый раз, что сводится к нативным, а что нифига.
Абстрагирование от конкретной БД даже как постановку задачи считаю бредом сивой кобылы.

Фанат
Про пдо согласен. Ну то есть основная претензия к коду Amdy сводится к layering violation ага? ;)
 

Ragazzo

TDD interested
fixxxer
Aha! Значит сам агитировал раньше за PDO, а признался в таких грехах как mysql_*, иноверец!сжечь его! :D
 

Фанат

oncle terrible
Команда форума
fixxxer
я бы не хотел употреблять такие страшные слова.
потому что к ним цепляются потом, и начинают спорить с тем, что я кого-то хочу загнать в какие-то рамки. Хотя я никого никуда загонять не хочу и возражать на эти левые обвинения мне уже поперек горла (в этом смысле я боюсь даже слова "основные", поскольку некоторые воспримут не как "суть критики", а как "принципиальные недостатки". Некоторые уже ринулись утешать Amdy, хотя ни он сам, ни его фреймворк в это мне нуждаются, а мои замечания не дают повода для этого.

Но в сущности - да, я считаю, что не доделав нижний уровень, мы полезли выше, и проблемы нижнего решаем за счет верхнего. И наоборот - внизу имеем то, что должно быть вверху. Собственно, началось всё с функции insert().

Как и многие далостроители, Amdy отрезал ноги у запроса, сделал вместо них протезы, и в таком виде отправил гулять в приложение.
К примеру, хелпер для апдейтов.
Вот прям така сложна операция, така сложна - обязательно её надо облегчить.

ладно, получаем (псевдо)код
PHP:
$db->query("UPDATE table ?placeholder WHERE field=?placeholder",$data,$var);
который превратился в
PHP:
$db->update("table",$data,$db->getExpr("field=?placeholder",$var));
никакого упрощения не получили
сэкономив два слова в запросе, наворотили монстроподобный синтаксис, расчленив запрос на куски и раскидав на два этажа.
всё стало куда сложнее, приводя, в экстремальных случаях, к ужасам типа $db->addOr(...).

Ладно - говорит он - это не хелпер, это абстракция.
Вот здесь, я считаю, мы имеем принципиальный косяк.
Во-первых, мы не слишком-то абстрагировались. Кишки конкретного диалекта SQL все равно торчат там и сям.
Во-вторых, абстрагировались мы не там, где надо.
если delete() - как мне пытался впарить Ragazzo - это метод-прототип для базового класса, то почему этот базовый класс - dal? и почему базируется на вполне конкретном диалекте SQL?

Я считаю, что надо сделать отдельно удобный инструментарий для работы SQL.
Это будет 1 уровень.
Дальше, если ты действительно хочешь всё упрятать - сделай второй, и в нём уже прячь. Только это всё равно не сработает, но если уж очень хочется.

Вообще, это во мне, наверное, говорит бритва оккама.
И опыт, который говорит о том, что когда не могут сделать просто - делают сложно.
И ещё другой опыт, который говорит, что в рекламе у каждого фреймворкостроителя всё в шоколаде и ОРМе.
А на практике, куда ни ткни - везде голый SQL фигачат (потому что жизнь чуточку сложнее рекламы). А инструментов для нормальной работы с SQL-то и неееету! :)
 

WMix

герр M:)ller
Партнер клуба
PHP:
 $db->update("table",$data,$db->getExpr("field=?placeholder",$var));
я наоборот нахожу подобный синтаксис "тип доктрина" удобным, когда нужно создать сложный по сути sql, который может полностью измениться в зависимости от входящих переменных.

пример на zend
PHP:
$sql = $this->getAdapter()->select()-> ...
if(xyz) $sql->joinLeft(...)
switch(abc)
case mama: $sql->where(...)
 

Фанат

oncle terrible
Команда форума
да при чем здесь это.
менять SQL от входящих переменных можно при любом подходе.
вот только работая с SQL, ты можешь сделать всё, а с квери-билдером - только то, что в него заложено.
 

Фанат

oncle terrible
Команда форума
так внутри квери билдера всё равно будет та же склейка :)

Вот, кстати, о склейке.
пока у нас честный SQL, мы стесняемся его писать в контроллере. И отправляем туда, где ему место - в модель.
а когда мы его замаскировали, сделав красивую объектную структуру, то, вроде, не зазорно и в контроллере написать. и подменить его кэшем (чем должна заниматься модель, а не dal) уже не можем.
 

WMix

герр M:)ller
Партнер клуба
то, вроде, не зазорно и в контроллере написать
бывает и такое, и порою ничего страшного нет в таком подходе,
Бизнес-логика в конроллере или модели?
Как и в любом религиозном споре, тут нет одного правильного ответа. Существует два подхода к этому вопросу: толстые контроллеры и тонкие модели, и наоборот. В первом случае, как нетрудно догадаться, бизнес-логика располагается в контроллерах, во втором — в моделях.
Споры о том, какой из подходов более правильный, ведутся давно и стороны могут нагородить кучу аргументов как за, так и против любой из сторон.
На мой взгляд — оба подхода имеют право на жизнь, но главное не мешать их в одном приложении: выбрать для него какой-то один стандарт и ему соответствовать.
соглашусь с этим высказыванием... тут понять задачу нужно сперва!
 

флоппик

promotor fidei
Команда форума
Партнер клуба
так внутри квери билдера всё равно будет та же склейка :)
Она не будет сделана руками в каждом месте, и что сведет к минимуму ручной труд — и ошибки от этого труда. А еще иногда над проектом работает больше одного человека. А еще иногда в модель нужно внести изменения. Поэтому если клеить строки в магическую строку, не связанную с объектом для тебя является нормальной работой программиста... ну извини, аргументов на такой уровень спора у меня и правда нет.
 
  • Like
Реакции: scb

WMix

герр M:)ller
Партнер клуба
так внутри квери билдера всё равно будет та же склейка :)
ну да будет, а мне какое дело как работает бензопила, интересно что этим можно пилить дрова!.. конечноже как дитя планеты нужно думать о загрезнении окружающей среды, но обычной пилой пилить - увольте!
 

Фанат

oncle terrible
Команда форума
что сведет к минимуму ручной труд.
Отличный повод перейти от теоретических рассуждений к практике.
Вот тебе пример классического случая ручной склейки.
PHP:
$where = $db->parse("month(`date`)=?i and year(`date`)=?i", $data['month'], $data['year']);

if ( $point_id ) {
	$where .= $db->parse(" AND point_id=?i",$point_id);
}
if ( $source ) {
	$where .= $db->parse(" AND source=?s",$source);
}
$sql = "SELECT *, day(date) day, price*num as sum FROM history WHERE $where ORDER BY date DESC";
$res = $db->query($sql);
приведи, пожалуйста, примеры возможных ошибок и реализацию того же самого с помощью билдера.
И посмотрим, сколько тут где ручного труда и возможных ошибок :)

no pseudocode, please.
 

Фанат

oncle terrible
Команда форума
клеить строки в магическую строку, не связанную с объектом для тебя является нормальной работой программиста...
вот это, кстати, очень важная фраза.

Секрет заключается в том, что эта работа является нормальной для всех. Вообще для всех. В реальной жизни.
В воображаемом идеальном мире, в котором живёт большинство программистов - да, это ненормально, и никогда не бывает.
В грязном грешном реальном коде - это везде. В качестве досадных исключений, TODOs, временных хаков и заплаток - но везде. И меньше этих "временных" исключений не становится :)

поэтому лично я - за реализм.
Как было написано в одном объявлении - "Не льсти себе - встань поближе" ;-)
 

WMix

герр M:)ller
Партнер клуба
Вот тебе пример ручной склейки.
не спорю, наглядно! добавь туда возможный join мы ищем продукты category_name LIKE 'вибра%' а гдето возможно group by потомучто произошла мультипликация, гдето having
еще можно иногда этим же запросом строки считать, а порою этого ненужно, итд.
и наглядность начинает проподать...

а можно на query builder написать еще один буилдер и расскидать склейку этого же sql в разные методы, ...

ну да нет смысла спорить, и голым SQL я тоже пишу, и в этом не нахожу ничего страшного!
 

WMix

герр M:)ller
Партнер клуба
на zend
PHP:
$sql = $this->getAdapter()->select()->from( 'history',  
	array( '*', 
		'day' => new Zend_Db_Expr( 'day(date)' ), 
		new Zend_Db_Expr( 'price*num') 
	)
 )
->where("month(date)=?", (int)$data['month'] )
->where("year(date)=?", (int)$data['year'])
->order('date DESC');

if ( $point_id ) {
	$sql->where("point_id=?",(int)$point_id);
}
if ( $source ) {
	$sql->where("source=?",(string)$source);
}

// на всякий для дебагинга 
// echo $sql->assemble(); 


$res = $this->getAdapter()->fetch[Row/All/..]($sql);
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я считаю, это прекрасный пример! Потому что он упадет с ошибкой, ведь date, по которому ты сортируешь — зарезервированное слово.

Теперь тебе надо следить, что бы не забыть пробел перед каждым AND. И если ты его забудешь, ты будешь его искать довольно долго, особенно если это необязательное условие, как раз. Или не дай бог, зависит от нескольких условий.
Теперь если ты захочешь добавить условие раньше твоей начала странной склейки тебе надо будет следить, что бы добавить AND и пробел после нового условия. Это при условии, что оно тоже не зависит от других критериев.
Или не дай бог у тебя есть во WHERE открывающая или закрывающая скобка... в более-менее комплексных запросах ты будешь долго блуждать, проверяя все комбинации условий.
Если ты хочешь задать какие-то значения раньше остальных — ну, например, ты знаешь, что тебе нужно просто добавить сортировку и ограничение на число записей на страницу — сорри, ты не можешь это унифицировать. Ты не сможешь передать свой запрос в какой-то обьект, который посчитает число записей на страницу относительно какого-то пользовательского значения, и тебе это надо будет делать руками. В каждом вызове контроллера, где у тебя пагинация.
Если ты не дай бог переименовал поле...
А если тебе передали несуществующий год? или месяц?
а если у тебя поле называется TEXT ? И ты забыл его где-то закавычить?
Я не думаю об этом всем, я пишу логику.

Проблема в том, что ты пишешь код в стиле «я хочу получить массив строк»... MVC так не работает. Модель — это объект.
В моем случае, это будет что-то вроде:

PHP:
$history = ORM::factory('history')->where('month', '=', $month)->where('year', '=', $year);
// хочу я из десять штук!
$history->limit(10);
// и отсортировать по дате
$history->order('date');
if ($point_id) {
$history->where('point_id', '=', $point_id);
}
if ($source) {
$history->where('source', '=', $point_id);
}
$history->find_all();
 
Сверху