Я знаю, что это очень старая публикация, но я все равно отвечу на нее, потому что я нахожусь в процессе разработки своих собственных классов для удовлетворения потребностей, аналогичных тем, которые задает вопрос.
После изучения я обнаружил, что проблема с Zend-Db и другими подобными движками заключается в том, что они пытаются быть всем для всех. Чтобы обратиться к самой большой аудитории, им нужно предложить наиболее общую функциональность, которая, насколько я вижу, сама по себе уничтожает их (и, как мастерски объяснил Билл Карвин).
Одна из наиболее очевидных чрезмерных сложностей, с которыми сталкиваются многие движки, - это путать генерацию кода SQL с его выполнением (что облегчает написание грязного SQL). Во многих приложениях хорошей идеей является их явное разделение, побуждая разработчика задуматься о внедрении атак и т. Д.
При создании движка SQL первое, что нужно сделать, это ограничить область действия SQL, которую может создать ваш движок. Вы не должны позволять ему производить select * from table
например; движок должен требовать от разработчика явного определения каждого столбца select
, where
и having
. В качестве другого примера, часто бывает полезно, чтобы у каждого столбца был псевдоним (обычно это не требуется для базы данных).
Обратите внимание, что ограничение SQL этими способами не ограничивает то, что вы действительно можете получить из базы данных. Да, это делает предварительное кодирование более многословным в некоторых случаях, но также делает его более структурированным и позволяет вывести сотни строк библиотечного кода, которые когда-либо существовали в первую очередь, для работы со сложными исключениями и предоставления ( кхм) "гибкость".
Библиотеки, которые я написал до сих пор, содержат около 600 строк кода (~ 170 строк из которых обрабатывают ошибки). Он имеет дело с соединениями ISO, вложенными операторами (в предложениях SELECT
, FROM
и WHERE
), любыми предложениями двустороннего сравнения, IN
, EXISTS
и BETWEEN
(с вложенными операторами в предложение WHERE). Он также неявно создает привязки, вместо непосредственного введения значений в SQL.
Ограничения (кроме уже упомянутых): SQL написан специально для Oracle. Не проверено на любой другой платформе базы данных.
Я готов поделиться кодом, при условии, что все улучшения отправлены обратно.
В качестве примера того, что позволяют мне создавать библиотеки, я надеюсь, что следующее достаточно просто, чтобы быть интуитивно понятным, и в то же время достаточно сложным, чтобы продемонстрировать потенциал расширяемости:
<?php
$substmt = new OraSqlStatement;
$substmt->AddVarcharCol ('value','VALUE')
->AddVarcharCol ('identity','UID',false)
->AddVarcharCol ('type','info_type',false)
->AddFrom ('schemaa.user_propertues','up')
->AddWhere ('AND')
->AddComparison ('UID', '=', 'e.identity', 'column')
->AddComparison ('info_type', '=', 'MAIL_ADDRESS');
$stmt = new OraSqlStatement;
$stmt->AddVarcharCol ('company_id', 'Company')
->AddVarcharCol ('emp_no', 'Emp Id')
->AddVarcharCol ('person_id', 'Pers Id')
->AddVarcharCol ('name', 'Pers Name')
->AddDateCol ('employed_date', 'Entry Date')
->AddDateCol ('leave_date', 'Leave Date')
->AddVarcharCol ('identity', 'User Id')
->AddVarcharCol ('active', 'Active')
->AddVarcharCol ($substmt, 'mail_addy')
->AddFrom ('schemab.employee_tab', 'e')
->AddFrom ('schemaa.users_vw','u','INNER JOIN','u.emp_no=e.emp_number')
->AddWhere ('AND')
->AddComparison ('User Id', '=', 'my_user_id')
->AddSubCondition ('OR')
->AddComparisonNull ('Leave Date', false)
->AddComparisonBetween ('Entry Date', '2011/01/01', '2011/01/31');
echo $stmt->WriteSql();
var_dump($stmt->GetBindArray());
?>
Который производит:
SELECT
company_id "Company", emp_no "Emp Id", person_id "Pers Id", name "Pers Name",
employed_date "Entry Date", leave_date "Leave Date", identity "User Id", active "Active",
( SELECT value "VALUE" FROM schemaa.user_propertues up
WHERE upper(identity) = upper(e.identity)
AND upper(TYPE) = upper (:var0)
) "mail_addy"
FROM
schemab.employee_tab e
INNER JOIN schemaa.users_vw u ON u.emp_no = e.emp_number
WHERE
upper (identity) = upper (:var1)
AND ( leave_date IS NOT NULL OR
employed_date BETWEEN to_date (:var2,'YYYY/MM/DD') AND to_date (:var3,'YYYY/MM/DD')
)
Вместе с массивом связывания:
array
0 => string 'MAIL_ADDRESS' (length=12)
1 => string 'my_user_id' (length=10)
2 => string '2011/01/01' (length=10)
3 => string '2011/01/31' (length=10)