Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Подобие LINQ на PHP для EAV модели хранения данных

Anna | 31.05.2014 | нет комментариев

Увидев пост о LINQ на PHP, я решил немедленно поделиться своими наработками в этой области.
Моей реализации вдалеке до полновесного LINQ, но в ней присутсвует особенно невидимая черта спецтехнологии — отсутвие инородной строки запроса.

Для чего?

Моя действие, как рабочая так и не дюже, связана с БД, которая имеет EAV модель хранения данных. Это значит, что при увеличении числа сущностей, число таблиц не возрастает. Каждая информация хранится каждого в 2-х таблицах.
image
Таблицы с данными в EAV модели
Безусловно, что для того Дабы получить «запись» из такой конструкции, нужно написать запрос абсолютно непохожий на подобный запрос при обыкновенной структуре БД.
Скажем:

SELECT field_1, field_2, field_3 FROM object

и в EAV

SELECT f1.value_bigint, f2.value_bigint, f3.value_bigint 
FROM objects ob, attributes_values f1, attributes_values f2, attributes_values f3 
WHERE ob.ID_type="object" 
AND f1.ID_object = ob.ID_object AND f1.ID_attribute = 1
AND f2.ID_object = ob.ID_object AND f2.ID_attribute = 2 
AND f3.ID_object = ob.ID_object AND f3.ID_attribute = 3

Как говорится — почувствуйте задницу разницу.
Обстановка осложняется тем, что многие объекты связаны между собой отношениями, которые подобно раздувают запрос.

Генератор запросов

В один очаровательный момент мне наскучило писать плохочитаемую лапшу, которая содержит 50% — 70% вспомогательного кода. Тогда и возникла идея генерировать запрос механически. Так на свет появилася IQB — Irro Query Builder. Его доктрина была навеяна тем, как устроено взаимодействие с БД в Drupal.
Вышеописанный запрос в IQB будет выглядеть дальнейшим образом:

$q = new IQB();
$query = $q->from(array(new IQBObject('ob','object'), 
                         new IQBAttr('f1',1,INT), 
                         new IQBAttr('f2',2,INT), 
                         new IQBAttr('f3',3,INT)
                ))
        ->where('f1','with','ob')->where('f2','with','ob')->where('f3','with','ob')
        ->select('f1')->select('f2')->select('f3')
        ->build();

число кода не уменьшилось, но читаемость, как мне кажется, повысилась.
В этом запросе использованы все основные способы для генерации запроса.
Способ from() принимает класс либо массив классов представляющих собой таблицы БД. Таблиц каждого две, так что и классов такое же число. Конструктор класса таблицы принимает псевдоним таблицы, её воображаемый тип и тип данных, если это таблица признака.
Псевдоним таблицы применяется во всех остальных способах генератора запросов. Воображаемый тип, для таблицы объектов, является наименованием сущности, среди которых ведётся поиск, а для таблицы признаков, воображаемый тип нужен легко Дабы различать признаки одного объекта. Тип данных, говорит из какого поля таблицы брать данные. Это нужно т.к. признак объекта является конструкцией с 4 полями под данные, из которых применяется только одно, и в каком именно поле хранятся данные нужно указывать очевидно.
Способ where() накладывает данные на выборку. Принимает неизменно 3 довода: псевдоним таблицы, условие, значение. В зависимости от данные, в качестве значения может быть передан псевдоним иной таблицы, значение либо массив значенией с которым сравнивается поле таблицы.
Скажем:

$q->where('attr','with','object');

задаст условие

attr.ID_object = object.ID_object

из такого выражения

$q->where('attr','=','object');

получится схожее, но вовсе другое выражение

attr.value_bigint = object.ID_object

а если таблица object не была объявлена во from(), то получится вот это (если ещё тип данных признака изменить на string)

attr.value_ntext = "object"

В качестве условий дозволено применять строки ‘=’, ‘!=’, ‘>=’, ‘<=’, ‘>’, ‘<’, ‘like’ и ‘with’ — принадлежность признака определенному объекту.
Способ select() указывает генератору, значения каких таблиц обязаны попасть в выборку. Помимо того дозволено «обернуть» это значение в функцию, передав в способ третьим доводом строку как бы «SUM($)», и взамен бакса в функцию подставится поле таблицы. Вторым доводом дозволено передать псевдоним поля в выборке.
Совместно с способами groupBy() и orderBy() этого хватает для построения среднестатистическиз запросов на чтение.

Впрочем не всё так легко.
Объекты, как и сущности в обыкновенных БД, могут быть связаны отношениями.
Связь, как это ни необычно — тоже объект. С признаками. И Дабы получить объект Б, тот, что является дочерним у объекта А, нужно проделать следующие манипуляции:

$q->from(array( 
        new IQBObject('b','B'),
        new IQBAttr('parent',23,INT),
        new IQBAttr('child',24,INT)
    ))
    ->where('parent','=',123456) // ID_object объекта А
    ->where('child','with','parent')
    ->where('child','=','b')

Многовато для простого «взять Б дочерний у А». Дабы автоматизировать связывание объектов, в IQB сущетвует способ linked().
Способ принимает ID_object либо псевдоним знаменитого объекта, псевдоним дочернего/родительского и «флаг разворота» т.е. указание — искать дочерние объекты либо родительские. Таким образом вышеизложенный код дозволено зписать так:

$q->from(new IQBObject('b','B'))->linked(123456,'b');// по умолчанию ищется дочерний объект.

Дозволено было бы на этом и завершить, но периодично попадаются задачи, для которых генератор запросов оказывается несколько ограниченным. Скажем, с некоторых пор начали попадаться объекты, у которых какой-то признак может отсутсвовать. Для решения этой задачи был добавлен способ joinTo() тот, что делает LEFT JOIN таблицы признака к таблице объекта.
А для вовсе уж экзотических запросов есть rawWhere() и rawSelect() которые разрешают вводить произвольные куски запроса.

Завершение

Я не усердствовал делать библиотеку для общего пользования, следственно новые вероятности вводил только когда в этом возникала надобность. В связи с этим ошибки проектиования, допущенные на ранних этапах разработки, обросли парой слоёв костылей, нужных для совместимости со ветхим кодом и для поддеражания новых функций.
Несморя на вероятность реализовыть с поддержкой IQB достаточно трудные запросы, эластичным его дозволено назвать только с натяжкой. Следственно теперь формируется доктрина больше эластичного генератора, тот, что дозволит ещё огромнее сократить число символов при задании данные запроса, но это теснее вовсе иная история.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB