[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Класс работы с БД
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
Aeq
Очередной велосипед. Собственно зачем? Да вот нужен всегда под рукой простой и удобный класс работы с БД.

Чем обычные mysql_* pg_* функции не нравятся? Букоф много писать лень, можно ведь проще и удобнее сделать, и по пути избавить себя от опечаток в куче простых запросов. Сложные запросы все равно тестируются отдельно, а вот простые часто пишутся "неглядя".

Почему тогда не взять готовое решение типа ActiveRecord? В реализации на PHP там куча массивов с параметрами, эти параметры помнить надо, и от опечаток не избавляет, никакого автокомплита в IDE, а хотелось бы чтоб простые вещи с автокомплитом были. Если кто-то знает удачные готовые решения, пожалуйста поделитесь :)

За основу взят PDO. Почему? Потому что работать приходится и с MySQL и c PostgreSQL, а городить еще и велосипед абстракции СУБД совершенно не зачем, раз есть PDO. Собственно класс довольно небольшой, добаввляет несколько часто требуемых возможностей к PDO.
  • Соединение устанавливается перед первым запросом (т.н. lazy connection). Ну есть ведь странички на сайтах, на которых соединение с базой не нужно, и совершенно не хочется заморачиваться когда оно нужно или нет. Бывает не нужно впринципе, бывает от того что все в кэше...
  • Пишет лог запросов в произвольный класс. Просто подставьте любой класс с методом debug($msg).
  • Кеширует запросы произвольным классом-кэшером с тремя функциями get($name), set($name, $value) и clear(). Сюда сразу прилагаются два класса кэшера: 1) кэш в массиве, кэширует только в рамках одного запуска скрипта и 2) кэш в Memcached. В кэш могут попадать не только результаты запросов целиком, но и построчно (этакие зачатки ORM, но все же это просто построчный кэш, и городить ORM-велосипедо-монстра смысла точно нет).
  • Набор небольших методов для построения запросов. Описание ниже в примерах. Они не только упрощают построение запроса, но и помогают кэшеру кэшировать не только результат запроса целиком, но и построчно.
  • Связывание данных по внешним ключам. Выбрать-то их не сложно и обычным запросом, а вот связать все ссылочками заморочисто может быть, для того предусмотрена пара методов.
Теперь примеры. Как-то так, в самом простом варианте используется PDO. Как создать объект PDO писать не буду, конструкторы у PDO и моего класса одинаковые.
$sth = $pdo->prepare('SELECT * FROM fruit LIMIT 10');
$sth->execute();
$fruits = $sth->fetchAll();

С моим классом APDO, это будет выглядеть так:
$fruits = $apdo
->statement('SELECT * FROM fruit LIMIT 10')
->
all();

Особой разницы пока не видно, да? Это просто демонстрация того как можно создать запрос на SQL. То же самое, но уже более просто и ООПэшно:
$fruits = $apdo
->from('fruit')
->
limit(10)
->
all();

Уже лучше. Но чем же все-таки простой сырой SQL не угодил? Да вот например тем, что если у меня есть моделька, то она уже знает из какой таблички данные тянуть, и в коде уже будет как-то так:
$fruits = $model_fruit->db()
->
limit(10)
->
all();

Да и кэш не сможет построчно закэшировать, если не будет выделено имя таблицы.

Сколько записей было в предыдущем запросе, если б не было лимита?
$last_count = $apdo
->last()
->
count();

Если знаем какой конкретно хотим фрукт (по id):
$i_want_this_one = $apdo
->from('fruit')
->
key(123)
->
one();

Если нужен только цвет этого фрукта:
list($color) = $apdo
->from('fruit')
->
fields('color')
->
key(123)
->
oneL();

Если нужен массив [id => имя] красных фруктов:
$red_fruits_id_name = $apdo
->from('fruit')
->
fields('id, name') # или ->fields(['id', 'name'])
->key('red', 'color')
->
allK();

Удаляем вишню:
$apdo
->from('fruit')
->
key('cherry', 'name')
->
delete();

Красим яблоки в зеленый цвет:
$apdo
->in('fruit')
->
key('apple', 'name')
->
update(['color' => 'green']);

Теперь чуть сложнее: связывание данных. Есть два дерева, которые вероятнее всего получчены из предыдущего запроса, но для наглядности просто создадим массив. Какие фрукты растут на этих деревьях?
$trees = [
[
'id' => 1, 'name' => 'apple tree'],
[
'id' => 2, 'name' => 'orange tree'],
];


$fruits = $apdo
->from('fruit')
->
references($tree, 'fruits', 'tree', 'tree_id')
->
all();

# $fruits == [
# ['id' => 1, 'name' => 'apple1', 'tree_id' => 1,
# 'tree' => &['id' => 1, 'name' => 'apple tree', 'fruits' => &recursion],
# ],
# ['id' => 2, 'name' => 'apple2', 'tree_id' => 1,
# 'tree' => &['id' => 1, 'name' => 'apple tree', 'fruits' => &recursion],
# ],
# ['id' => 3, 'name' => 'orange', 'tree_id' => 2,
# 'tree' => &['id' => 2, 'name' => 'orange tree', 'fruits' => &recursion],
# ],
# ];

Обратная операция. Узнаем на каких деревьях растут фрукты.
$fruits = [
[
'id' => 1, 'name' => 'apple1', 'tree' => 1],
[
'id' => 2, 'name' => 'apple2', 'tree' => 1],
[
'id' => 3, 'name' => 'orange', 'tree' => 2],
];


$trees = $apdo
->from('tree')
->
referrers($fruits, 'fruits', 'tree')
->
all();

# $trees == [
# ['id' => 1, 'name' => 'apple tree', 'fruits' => [
# &['id' => 1, 'name' => 'apple1', 'tree_id' => 1, 'tree' => &reqursion],
# &['id' => 2, 'name' => 'apple2', 'tree_id' => 1, 'tree' => &reqursion],
# ]]
# ['id' => 2, 'name' => 'orange tree', 'fruits' => [
# &['id' => 3, 'name' => 'orange', 'tree_id' => 2, 'tree' => &reqursion],
# ]],
# ];

Это был не полный список методов. Полный список привожу ниже, названия впринципе говорят сами за себя, но если не понятно, гляньте в комменты к методам, там все написано.
Методы основного класса-соединения APDO:
pdo connected statementCount executedCount cachedCount last setPkey setLog setCache statement from in

Методы класса-запроса APDOStatement:
log cache rowCount lastQuery nothing table pkey join leftJoin where orWhere key orKey groupBy having orderBy addOrderBy limit offset fields handler
all allK one oneL page pageK keys count execute insert update delete cacheClear referrers references

Надеюсь кому-то мой класс пригодится в работе или его части/идеи в реализации своих коннектов к базе.

Я лично использовал его как прослойку между модельками и БД, то есть либо использовал внутри методов модели, либо из модели вызывал метод, например ->db(), который возвращает APDOStatement с предустановленным именем таблички, первичным ключом и возможно какими-то доп. условиями (типа "new_published=1").

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

Если найдете баги, буду рад. Юнит-тест прилагается, он конечно не особо оптимально написан, но все функции вроде тестирует.

Кто возьмет класс на вооружение, и что-то внесет свое - будет интересно посмотреть.

Собственно код лежит на GitHub.

З.Ы. Первый пост на этом форуме, извиняйте если чего не так.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2025 Invision Power Services, Inc.