Язык создания запросов(dbSimple++).

ksnk

прохожий
Как-то, вот, сочинилось. Язык, в принципе, похож на Котеровский из dbSimple. Прелесть его в том, что сама реализация - 50 строк...
Основной смысл - комбинации с ? в начале, служат плейсхолдерами для переменных, передаваемых в функцию. Можно указывать тип передаваемой переменной. ?d - число? привести к числу, вставлять без кавычек, ?s - строка, вставлять с двойными кавычками, ?k - строка, которую требуется обрамить обратными `` кавычками, ?x - просто тупо вставить без коррекции и так далее. Просто вопросик вызывает анализ параметра. Число вставляется без кавычек, строка - с кавычками. Понятно, в нужных местах, делается escape.
Каждый вопросик сдвигает указатель на следующую переменную. Если сразу после ? стоит число - считается, что нужно использовать переменную с таким номером и не двигать текущий указатель переменной. Пока все предсказуемо и не ново. А вот и ноухау: ;)
?(...) - применяется к параметру - массиву. Все значения массива пробегаются и комбинация символов из строчки в скобках, применяется к паре - ключ (первый параметр),значение (второй параметр). Все полученные значения соединяются через запятую. Нехитрый, казалось бы, трюк позволяет мастерить практически всё многообразие запросов.

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

$db - драйвер базы данных, _ - внутренний метод, который получает массив параметров, переданных из внешних функций драйвера. Первый элемент ассива - sql-форма, последующие - параметры.
PHP:
 $db->_(array('insert into ?k (?(?k)) values (?2(?2))','x_table'
               ,array('one'=>1,'two'=>2,'three'=>'облом')))
insert into `x_table` (`one`,`two`,`three`) values (1,2,"облом")
PHP:
$db->_(array("SELECT * from table  AS e
WHERE e.`ID` in  (?1(?d)) 
ORDER BY FIELD(e.`ID`, ?1(?d))",
array(25,24,2345));
SELECT * from table AS e
WHERE e.`ID` in (25,24,2345)
ORDER BY FIELD(e.`ID`, 25,24,2345)
Единственно "некрасивая" фенечка - генерация простыни из insert values
PHP:
// генерация простыни
        $x=array(
              array('x'=>1,'y'=>2,'z'=>3),
              array('x'=>1,'y'=>2,'z'=>3),
             array('x'=>1,'y'=>2,'z'=>3),
         );
         $part=array();
         foreach($x as $xx) $part[]= $db->_(array(array('(?(?2))',$xx)));
         $db->_(array('insert into ?k (?(?k)) values ?3(?2x);','table',$x[0],$part)))
Ну и реализация:
PHP:
    /**
     * helper-заполнятель sql конструкций.
     * список подстановок
     *  ?_ - подставить префикс таблицы, указатель парамемтров не перемещается
     *  ?12x - подставить 12 по счету параметр. Указатель параметров не перемещается
     *      без номера - указатель перемещается на следующий параметр
     *  ?x - подставить параметр без обработки
     *  ?d, ?i - параметр - чиcло. Явно приводится к числовому значению, каычек нет.
     *  ?k - параметр - имя поля, обрамляется `` кавычками
     *  ?s - параметр - строка - выводится в двойных кавычках,
     *      делается mysql_real_escape_string
     *  ? - анализируется значение, для чисел не вставляются кавычки,
     *      для строк делается ескейп
     *  ?(...) - параметр - массив, для каждой кары ключ-значение массива
     *      применяется формат из скобок. Разделяются запятыи
     *
     * @param array $args  - нулевой параметр - формат
     * @return string
     */
    function _($args)
    {
        static $pref;
        //$args=func_get_args();
        $format = $args[0];
        $cnt = 1;
        $start = 0;
        while (preg_match('/(?<!\\\\)\?(\d*)(i|d|x|k|_|s|\(([^\)]+)\)|)/i'
            , $format, $m, PREG_OFFSET_CAPTURE, $start)
        ) {
            $x = '';
            $cur = $m[1][0];
            if (empty($cur)) $cur = $cnt++;
            if (empty($m[2][0])) {
                if (is_int($args[$cur]) || ctype_digit($args[$cur]))
                    $x = (0 + $args[$cur]);
                else
                    $x = '"' . mysql_real_escape_string($args[$cur]) . '"';
            } else switch ($m[2][0]) {
                case '_':
                    if (!isset($pref))
                        $pref = ENGINE::option('database.prefix', 'xxx_');
                    $x = $pref;
                    break;
                case 'i':
                case 'd':
                    $x = (0 + $args[$cur]);
                    break;
                case 'x':
                    $x = $args[$cur];
                    break;
                case 'k':
                    $x = '`' . mysql_real_escape_string($args[$cur]) . '`';
                    break;
                case 's':
                    $x = '"' . mysql_real_escape_string($args[$cur]) . '"';
                    break;
                default: //()
                    if (is_array($args[$cur])) {
                        $s = array();
                        foreach ($args[$cur] as $k => $v)
                            $s[] = $this->_(array($m[3][0], $k, $v));
                        $x = implode(',', $s);
                    }
            }
            $format = substr($format, 0, $m[0][1]) . $x . substr($format, $m[2][1] + strlen($m[2][0]));
            $start = $m[0][1] + strlen($x);
        }
        return $format;
    }
Какого либо контроля на число передаваемых переменных и соответствие их sql-формату нет. imho, cам php в варнингах исправно сообщит о кривости шаблона, при первом же его применении.
 

fixxxer

К.О.
Партнер клуба
PHP:
$x = '`' . mysql_real_escape_string($args[$cur]) . '`';
ну вот это откровенная хрень =)
 
  • Like
Реакции: ksnk

hell0w0rd

Продвинутый новичок
хватит писать велосипеды, берите проверенные решения:D
https://github.com/hell0w0rd/MySQLClass/tree/master/src/hell0w0rd
Я в данном случае юзал такую хорошую штуку - как func_get_args, так что массивы не нужно городить, так приятнее.
А вообще - мне кажется надо брать что-то типо doctrine DBAL, или другие аналогичные компоненты. Они помимо всего прочего умеют сглаживать особенности синтаксиса БД)
 

Фанат

oncle terrible
Команда форума

hell0w0rd

Продвинутый новичок
o, ja-ja!


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

hell0w0rd

Продвинутый новичок
Фанат
А нет, пардон, да, содрал)))
http://habrahabr.ru/post/148701/ - вот эта статья понравилась, по ее мотивам и писал) Спасибо, во многом разобрался)
unset($host, $user, $password, $database); // for paranoid
:)
Из того что в вашем классе не нравится - нет единой формы возвращаемого результата, нет возможности теоретически расширить, изменить драйвер. Хотя она у меня тоже теоретическая) fetch должен быть в драйвере, а не менеджере)
 

Фанат

oncle terrible
Команда форума
PHP:
 $db->_(array('insert into ?k (?(?k)) values (?2(?2))','x_table'
               ,array('one'=>1,'two'=>2,'three'=>'облом')))
PHP:
$db->_(array("SELECT * from table  AS e
WHERE e.`ID` in  (?1(?d)) 
ORDER BY FIELD(e.`ID`, ?1(?d))",
array(25,24,2345));
смотри, ради сокращения кода библиотеки ты сделал нечитаемым код приложения. Хотя в библиотеку никто не лазит, а приложение всегда перед глазами.
PHP:
$db->query('insert into ?n SET ?u','x_table', array('one'=>1,'two'=>2,'three'=>'облом'));
$a = array(25,24,2345)
$db->query("SELECT * FROM table AS e WHERE e.`ID` in (?a) ORDER BY FIELD(e.`ID`, ?a)", $a, $a);
ну лучше же читается - не?
 

Фанат

oncle terrible
Команда форума
Фанат
Из того что в вашем классе не нравится - нет единой формы возвращаемого результата, нет возможности теоретически расширить, изменить драйвер. Хотя она у меня тоже теоретическая) fetch должен быть в драйвере, а не менеджере)
Имя, сестра, имя!
Какие ваши доказательства из реальной практики?
- нет единой формы возвращаемого результата - пример, когда это нужно?
- нет возможности теоретически расширить, изменить драйвер - теоретическая всегда есть. Вот как раз драйвер-то, лежащий внутри, меняй каку годно.
- fetch должен быть в драйвере - ну разумеется. Будет драйвер - будет в драйвере. наследуясь от драйвера в основном классе.
 

hell0w0rd

Продвинутый новичок
Имя, сестра, имя!
Какие ваши доказательства из реальной практики?
- нет единой формы возвращаемого результата - пример, когда это нужно?
- нет возможности теоретически расширить, изменить драйвер - теоретическая всегда есть. Вот как раз драйвер-то, лежащий внутри, меняй каку годно.
- fetch должен быть в драйвере - ну разумеется. Будет драйвер - будет в драйвере. наследуясь от драйвера в основном классе.
Мне не нравится проверять результат запроса на прямую. Приятнее проверять ошибки.
 

ksnk

прохожий
смотри, ради сокращения кода библиотеки ты сделал нечитаемым код приложения. Хотя в библиотеку никто не лазит, а приложение всегда перед глазами.
С одной стороны - отчего бы не завести еще тройку-четверку ключиков,раз уж их и так 8. С другой стророны, вся работа с параметрами-массивами уместилась в один скобочный конструкт. Надо думать... :)

Кстати, есть ли надобность в реальной sql жизни объединять sql-кусочки не через запятую? Мне как-то не встречалась пока такая надобность, но может я чего не понимаю?

$x = '`' . mysql_real_escape_string($args[$cur]) . '`';
ну вот это откровенная хрень =)
В общем-то согласен, но какую то защиту от корявых данных на момент отладки хочется иметь. Если на вход случайно запулить массив с ключикаим из странных символов, можно получить неадекватные ошибки от mysql и потерять время на отладке
 

ksnk

прохожий
Я в данном случае юзал такую хорошую штуку - как func_get_args,
Вообще-то этот метод - "внутреннний". Внешние функции драйвера выглядят вполне адекватно и именно таким методом собирают свои параметры для построителя реального sql. Отсюда и проистекает внешний вид функции _
 

Фанат

oncle terrible
Команда форума
Изменил код, добавил приятностей)
Я вот не понимаю, что ты вертишься, как уж на сковородке?
Я тебя открытым текстом спрашиваю: "приведи пример, как сделать приятнее"
Ты: "я там у себя почесал где-то, стало приятнее".

Код привести можешь?

ИМХО, цель любого класса-хелпера - сделать более удобной работу в SQL в приложении.
Отсюда становится ясно, что должно быть в тех примерах, которые я от тебя безуспешно пытаюсь получить - код приложения, решающий какую-то задачу, который получается твоим классом удобнее, чем моим. Или моим вообще не решается.
или хорошо, без сравнения.
просто - пример того, как надо писать код в приложении, соответственно твоим представлениям об этом.

Без примеров кода можешь даже не трудиться отвечать.
 

Фанат

oncle terrible
Команда форума
С другой стророны, вся работа с параметрами-массивами уместилась в один скобочный конструкт. Надо думать... :)
Чё тут думать?
Надо с целью определяться.
Если ты пишешь на obfuscated PHP contest - попытка годная.
Если цель какая-то другая - надо её четко сформулировать, и тогда уже смотреть, соответствует ли ей полученное решение.
 

hell0w0rd

Продвинутый новичок
Я вот не понимаю, что ты вертишься, как уж на сковородке?
Я тебя открытым текстом спрашиваю: "приведи пример, как сделать приятнее"
Ты: "я там у себя почесал где-то, стало приятнее".

Код привести можешь?

Цель любого класса-хелпера - сделать более удобной работу в SQL в приложении.
Отсюда становится ясно, что должно быть в тех примерах, которые я от тебя безуспешно пытаюсь получить - код приложения, решающий какую-то задачу, который получается твоим классом удобнее, чем моим. Или моим вообще не решается.
или хорошо, без сравнения.
просто - пример того, как надо писать код в приложении, соответственно твоим представлениям об этом.

Без примеров кода можешь даже не трудиться отвечать.
посмотри файл index.php
 

Фанат

oncle terrible
Команда форума
PHP:
$driver = new MysqliDriver('127.0.0.1', 'root', 'root', 'test');
$db = new hell0w0rd\SqlManager($driver);
$users = $db->query('SELECT * FROM1 `users` WHERE `id`=100');
if($users->isSuccessful()){
    var_dump($users);
    var_dump($users->getRow());
    var_dump($users->getByKey('city', 'Казань'));
}else{
    echo 'Ошибка же!';
    var_dump($users->getError());
}
Понятно. Дичь, каменный век. Каждый запрос заворачиваем в проверку. Ошибки шарашим прямо на экран. Исключения и централизованная обработка ошибок? Нет, не слышал.
Всё-таки неистребимо желание среднего пехаписта навалить кучу кода на пустом месте.

getByKey - это вообще какая-то фигня, попытка подменить SQL. "Давайте выберем тыщу записей, а потом ручками отфильтруем нужные"

В общем, все ясно с тобой. Я-то надеялся, действительно что-то умное увижу, чему-то поучусь.
 

ksnk

прохожий
Чё тут думать?
Надо с целью определяться.
Цель, к которой я стремлюсь - записать запрос с параметром-массивом ( немассивы не рассматриваем, ибо тривиально ;) ) с одним sql-шаблоном и одним упоминанием массива в параметрах для максимально возможного разнообразия запросов.

Разнообразие запросов, которое я могу записать. После примера - дополнительные ключики плейсходлеры для массивов, которые "повышают читабельность"
insert into `x_table` (`one`,`two`,`three`) values (1,2,"облом")
Предлагается завести ключики ?a для перечисления ключей через запятую и ?v для перечисления значений через запятую?
update table set one=1,two=2,three="облом"
insert into table (one,two,three) values (1,2,"облом")
on duplicate key update one=values.one,two=values.two,three=values.three
Предлагается завести ключик ?y(не помню как оно у Котерова :( ) для перечисления через запятую кусочков set'а и еще один ключик для перечисления нижеследующих update'ов?

В общем - не вижу явной выгоды. Чего-то пропустил?

Возможно, в моем случае для повышения читабельности можно круглые скобки "массивного" плейсхолдера заменить на квадратные.
 
Сверху