И всё-таки, как «правильно» выполнять из PHP сложные sql-запросы?

Года три назад попросили меня написать простенькую софтинку на PHP для печати счетов. Так уж получилось, что логика СУБД (MSSQL), на которую опиралась эта софтина, была весьма монструозна — около восьмиста таблиц, перепутанных взаимными связями. Поэтому большинство запросов включали в себя условные вызовы аггрегирующих функций (самое простое — sum(when eq then a else 0 end)), PIVOT\UNPIVOT и тому подобное.

C учетом моего не слишком уж большого опыта на тот момент я решил не ввязываться в data mapping\active record и просто закинул запросы в текстовые файлы, сделал в них текстовые плейсхолдеры типа {PARAM1} и написал функцию, заменяющую текст плейсхолдера на значения переменных из ассоциативного массива.

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

И, что удивительно, всё это безобразие работает и по сей день. Правда, количество костылей и подпорок уже начинает слегка раздражать.
А именно — ручной escaping, type-checking, в конце концов — не работает ctrl+пробел. Я уж промолчу про то, что отладка запросов нормально не работает из-за «неродных» плейсхолдеров, и syntax check в PhpStorm из-за этого сходит с ума. А вместе с ним и я, потихоньку.

Doctrine на такой сложности запросов превращает двухстрочный вызов в нечто невероятное, а про размер схемы я просто тактично умолчу. Родные плейсхолдеры (:PARAM) не умеют содержать в себе куски запроса. А у нас автогенерация во все поля, кастомные фильтры, отключаемые джойны из внешних СУБД, находящихся за 4-5 тыс км от нашей серверной комнаты. Паника, боль, унижение.

В общем, родился план. Делаем класс Query с тайп-чекингом, возвратом результатов в XML (да, есть и такое) либо в массиве. Дальше делаем кучу наследников для каждого отдельного SQL-запроса, у которых в public -секции висит класс с перечисленными входными параметрами. А дальше всё так же — текстовый файл и плейсхолдеры.

Обратно — либо массивом, либо XML, либо неким классом наподобие ResultSet->First (next,last).

Всё это до боли напоминает изобретение велосипеда. Подозреваю, что всё это уже написано до нас. Но беглый гуглеж не помог. Может, кто сталкивался с такими вещами?
  • Вопрос задан
  • 5404 просмотра
Пригласить эксперта
Ответы на вопрос 2
@rPman
Не нужно перебарщивать, решите только одну главную проблему передачи параметров — escaping и quoting параметров, никаких монструозных велосипедов, только поправьте метод выполняющий ваши запросы, :param пусть идут в sql-запрос без изменений (а сам запрос сделать параметризованным, список параметров получается просто поиском всех вхождений /\:(\w+)/), а {param} заменяются по старинке, пусть там останутся куски самого запроса с выражениями.
Ответ написан
Комментировать
@yar229
Я, наверное, чего-то не понял, но вроде же говорится о функционале хранимых процедур

create procedure BigBadQueryWithParams(@p1 int, @p2 nvarchar(1024))
as
begin
select * from MyTable where Field1 = @p1;
end;


mssql_init, mssql_bind параметры и mssql_execute...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
18 апр. 2024, в 21:56
2000 руб./за проект
18 апр. 2024, в 21:00
150 руб./за проект