Класс SQL

Класс для работы с базой данных

Класс состоит из двух частей: 1) простая обёртка для DbSimple плюс пара заплаток и исправлений для Berry; 2) ORM. Поэтому данная документация состоит как бы из двух частей тоже: статичных методов (в названиях метода есть ::) и методов вызываемые от обьекта (в названиях метода есть ->). Некоторые методы могут работать и как статичные, и как динамические - разница в знаках (на кукурузных полях).

Полную информацию касательно самой DbSimple вы сможете найти на официальном сайте.

Почему нет поддержки различных БД?

Сейчас есть поддержка только MySQL. Использовать немускул можно, конечно, но исключительно за счёт наследования и создания функций-билдеров запросов. Вот, кстати, из-за них и нет поддержки разных БД. Я остановился на DbSimple из-за её простых и приятных плюшек. Чтобы иметь возможность работать с различными базами нужна обёртка иного рода, обёртка полностью подменяющая прямые запросы. Подобное написать можно, но учесть все мелочи или все "крупности" различных БД точно не смогу. И думается, что в итоге написание такой обёртки превратится в борьбу с эмуляцией одной БД под другую.

Переменные

Переменные класа при наследовании служат настройками поэтому должны быть видимые. то есть либо var, либо public.

sql->table

Устанавливает реальное название табицы. Можно указать таблицу из другой БД.

Пример

class Table extends SQL {
    var $table = 'example_table';
}

// или

class Table extends SQL {
    var $table = 'some_db.prefix_table';
}

sql->primary_key

Установка первичного ключа, идентификатора. По умолчанию это id. Можно выбрать и нечисловой идентификатор.

Пример

// по id
$table = new Table(2);

// по какому-то иному полю с ключом unique
$table = new Table('Сосиски');

sql->parent_key

Поле-родитель. Советуется называть его pid. Построение деревьев с ключом-родителем не лучшая в мире вещь, но.

sql->has_one

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

Обратите внимание: связи строятся не на отношении класса к таблице, а на отношениях класса к классу.

Пример

class Post extends SQL {
    // это оно
    var $has_one = array('user');
}

class User extends SQL {
    var $table = 'profiles';
    var $has_many = array('posts');
}

Если модель имеет нестандартные ключи, то об этом надо явно указать в связях. В идеале у таблице post поле связующие с моделью user должно называться user_id, но в примере ниже оно имеет название poster_id.

class Post extends SQL {
    // модель => array(ключ в данной таблице, ключ в связанной таблице)
    var $has_one = array('user' => array('poster_id', 'id'));

    // или так
    /* var $has_one = array('user' => array(
        'local' => 'poster_id',
        'foreign' => 'id'
    )); */
}

class User extends SQL {
    var $table = 'profiles';
    var $has_many = array('posts' => array('id', 'poster_id'));
}

sql->belongs_to

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

Пример

class Post extends SQL {
    var $has_one = array('user');
}

class User extends SQL {
    var $table = 'profiles';

    // это оно
    var $belongs_to = array('post'); // тут один post
}

sql->has_many

Сзязь Много-к-одному, когда один пользователь может быть автором многих постов в блоге. Так же это обратная связь от один-к-одному.

Пример

class Post extends SQL {
    var $has_one = array('user');
}

class User extends SQL {
    var $table = 'profiles';

    // это оно
    var $has_many = array('posts');  // много данных из post поэтому posts
}

sql->has_and_belongs_to_many

Описывает тип связи много-ко-много. Например, один пост в блоге входит в много категорий, а в одной категории много записей из блога.

Пример

class Post extends SQL {
    // это оно
    var $has_and_belongs_to_many = array('categories');
}

class Category extends SQL {
    // обратная сторона много-ко-многим точно такая же
    var $has_and_belongs_to_many = array('posts');
}

Методы

sql::connect()

Создаёт соеденение с БД.

Пример

sql::connect(array(
    'username' => 'пользователь',
    'password' => 'пароль',
    'database' => 'сервер/база данных',
    'prefix' => 'префиккс'
));

Названия ключей не имеют значения. Главным соеденением будет то, что стоит раньше. В примере это first.

sql::query()

Выполняет запрос и возвращает результат.

Пример

print_r(sql::query('select * from [table]'));

/* Array (
    [0] => Array (
        [id] => 1
        [name] => Some
    )

    [1] => Array (
        [id] => 2
        [name] => Test
    )
) */

Обратите внимание: в запросе использована несвойственная конструкция для DbSimple, а именно квадратные скобки вокруг имени таблицы. После обработки к имени таблицы будет подставлен префикс, если он был указан в настройках соеденения.

sql::get(), sql->get()

Статичный метод - синоним sql::query().

Пример

$table = new Table;
print_r($table->get());

// или

print_r(sql::table('table')->get());

/* Array (
    [0] => Array (
        [id] => 1
        [name] => Some
    )

    [1] => Array (
        [id] => 2
        [name] => Test
    )
) */

sql::cell(), sql->cell()

Выполняет запрос и возвращает результат в виде одной ячейки.

Пример

// 5
print_r(sql::cell('select id from [table]'));

sql::col(), sql->col()

Выполняет запрос и возвращает результат в виде одной колонки. Хорошо использовать с array_key.

Пример

print_r(sql::col('select name, id as array_key from [table]'));

/* Array (
    [1] => Some
    [2] => Test
) */

sql::row(), sql->row()

Выполняет запрос и возвращает результат в виде одного ряда.

Пример

print_r(sql::col('select * as array_key from [table] where id = ?', 2));

/* Array (
    [id] => 2
    [name] => Test
) */

sql->count()

Возвращает число найденых строк.

Пример

$table = new Table;
$table->where('id > ?', 1);

// 1
print_r($table->count());

// или

// 1
print_r(count($table));

print_r($table->get());

/* Array (
    [0] => Array (
        [id] => 2
        [name] => Test
    )
) */

sql->as_array()

Возвращает данные в виде массива. Казалось бы, причём тут Лужков sql->get() тоже возвращает массив. Но sql->get() отдаёт плоский массив, так как не учитывает связи между таблицами.

Пример

Предположим, есть таблици post, categories и user. Одна запись в post может иметь связь с несколькими записями из таблицы categories и одной из таблицы user.

// ищем в таблице post идентификатор с номером 1
$post = new Post(1);

// явно указываем что нам нужно
$post->select('post.*', 'user.name', 'categories.name');

// получаем массив
print_r($post->as_array());

/* Array (
    [id] => 2
    [name] => Test
    [user] => Array (
        [name] => Великий Корнхолио
    )

    [categories] => Array (
        [0] => Array (
            [name] => PHP
        )

        [1] => Array (
            [name] => Python
        )

        [2] => Array (
            [name] => Lua
        )
    )
) */

Можно проигнорировать метод sql->select() и получать данные по ходу, но тогда количество запросов будет не 1, а по одному на каждую таблицу.

$post = new Post(1);

// 1
print_r($post->id);

// Test
print_r($post->name);

// Великий Корнхолио
print_r($post->user->name);

print_r($post->categories->as_array());

/* Array (
    [0] => Array (
        [name] => PHP
    )

    [1] => Array (
        [name] => Python
    )

    [2] => Array (
        [name] => Lua
    )
) */

То же самое, что и выше, но с альтернативным синтаксисом доступа к обьектам.

$post = new Post(1);

// 1
print_r($post['id']);

// Test
print_r($post['name']);

// Великий Корнхолио
print_r($post['user']['name']);

print_r($post['categories']->as_array());

/* Array (
    [0] => Array (
        [name] => PHP
    )

    [1] => Array (
        [name] => Python
    )

    [2] => Array (
        [name] => Lua
    )
) */

sql->as_object()

То же самое что и sql->as_array(), но в виде обьектов, а не массива.

sql->select()

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

Пример

$post = new Post(1);
$post->select('post.*', 'user.name', 'concat("My", "S", "QL") as string');
print_r($post->as_array());

/* Array (
    [id] => 2
    [name] => Test
    [user] => Array (
        [name] => Великий Корнхолио
    )

    [string] => MySQL
) */

Если указать .* для таблицы отличной от инициализированной, то получится +1 запрос, который получит все поля таблицы и отсеит поля с типами text (и вариации) и blob (и вариации).

sql::from(), sql->from()

Статичный метод - синоним sql::table() без второго параиметра в виде идентификатора. Динамический метод добавляет таблицу из которой будет произведена выборка. sql->from() напрямую лучше не использовать, описывайте связи в моделях.

Пример

// как синоним sql::tsble()
print_r(sql::from('table'));

// или, но не надо

$table = new Table;
$table->from('another_table1', 'another_table2');
$table->from('another_table3');
$table->from('another_table4');

// Работает, но лучше описать связи в моделях
$table->where('another_table1.id = another_table4.table_id');

sql->join()

Данный метод подключает таблицы, если они описаны. Так как скрипт сам пытается анализировать чего от него хотят, то sql->join() напрямую лучше не использовать.

Пример

$table = new Table;
$table->join('sometable');

// Но это не нужно скрипту, так как при запросе вроде
$table->select('*', 'sometable.id');

// или вроде такого
$table->where('sometable.id = ?', 12);

// скрипт сам поймёт, что нужно подключить sometable

sql->where()

Добавляет критерии поиска. Первым параметром должна идти строка или массив (для or) поиска, все последующие параметры - плейсхолдеры.

Пример

$table = new Table;

// where (id = 2) and (name = 'Test')
$table-where('id = ?', 2);
$table-where('name = ?', 'Test');

// или

// where (id = 2 or name = 'Test')
$table-where(array('id = ?', 'name = ?'), 2, 'Test');

// или, но такой подход может иметь косяки

// where (id = 2 or name = 'Test')
$table-where('id = ? or name = ?', 2, 'Test');

sql->order_by()

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

Пример

$table = new Table;

// order by id, name desc
$table->order_by('id', '-name');

// или

// order by id, name desc
$table->order_by('id');
$table->order_by('-name');

sql->limit()

Добавляет ограничение на количество выбранного.

sql->page()

Метод учитывая sql->limit() позволяет сортировать данные по страницам, а не по количеству.

Пример

$table->limit(10);

// синоним sql->offset(40)
$table->page(5);

sql->offset()

select [...] limit 10, 20, где 20 и есть этот самый offset. Как сказать-то?

Пример

// limit 10, 40
$table->limit(10);
$table->offset(40);

sql->group_by()

Добавляет группировку по полю(ям). Синтаксис такой же как у sql::order_by().

sql->having()

Добавляет фильтр по полю(ям). Синтаксис такой же как у sql::order_by().

sql::union()

Объединяет результаты нескольких запросов.

Пример

$song1 = new Song(1);
$song1->select('id', 'title', 'artist.name');

$song5 = new Song(5);
$song5->select('id', 'title', 'artist.name');

$union = sql::union($song1, $song5);

// Так же поддерживаются: sql->limit(), sql->offset() и sql->page()
$union->order_by('title');

// Так же поддерживаются: sql->as_array() и sql->as_object()
print_r($union->get());

/* Array
(
    [0] => Array
        (
            [id] => 5
            [title] => Love TKO
            [artist.name] => Teddy Pendergrass
        )

    [1] => Array
        (
            [id] => 1
            [title] => Santa Monica
            [artist.name] => Theory of a Dead Man
        )

) */

sql->save()

Сохраняет данные.

Пример

// вставляем данные
$table = new Table;
$table->name = 'And another test';

// 3
var_dump($table->save());

// или так
$table = new Table;
$table[]['name'] = 'And another test 2';
$table[]['name'] = 'And another test 3';

// Array([0] => 4 [1] => 5)
var_dump($table->save());

// редактируем данные
$table = new Table(2);
$table->name = 'Test [edited]';

// 1
var_dump($table->save());

Метод $table->save() может возвращать четыре типа: 1) число, если происходит установка данных и она удачна, возвращается один последний вставленный ID (при му); 2) 1 вернтёся после успешного редактирования данных; 3) если данные редактировать нет смысла, то есть они неизменены, то вернётся 0; 4) и лишь при неудачи в случае ошибки возвращается null.

"Сосисочным" метод имеет место быть, да.

$post = new Post(2);
$post->name .= ' [edited]';
$post->user->name = 'Some name';

// Array ([0] => 1 [1] => 1)
var_dump($post->save());

Получать и сохравнять данные можно иначе.

$post = new Post;

// And another test
print_r($post[3]->name);

$post[2]->name .= ' [edited]';
$post[2]->user->name = 'Some name';

// Array ([0] => 1 [1] => 1)
var_dump($post->save());

Таблицам с нечисловым первичным ключом подобное недоступно.

sql->into()

См. описание sql->values().

sql->values()

Одним запросом вставляет множество записей.

Пример

$table = new Table;
$values = array(
    'field1' => 'value1',
    'field2' => 'value2',
    'field3' => 'value3'
);
$table->values($values);

// или

$table = new Table;
$fields = array('field1', 'field2', 'field3');
$values = array('value1', 'value2', 'value3');

$table->into($fields);
$table->values($values);

Оба варианта работают совершенно одинакого. Какой вариант использовать зависит исключительно от ситуации.

sql->delete()

Удаляет данные.

sql->create()

Создаёт новую таблицу. Синтаксис как у sql->alter().

sql->alter()

Изменяет рабочую информацию о полях в таблице.

Пример

$table = new Table;

$table->id = array(
    'type' => 'int(11) unsigned'
);

// или

$table['id'] = array(
    'type' => 'int(11) unsigned'
);

// вернёт true в случае удачи
var_dump($table->alter());

Чтобы посмотреть все настройки воспользуйтесь sql::schema().

Обратите внимание: данный метод не умеет работать с ключами поставленными на несколько полей.

sql::using()

Переключает между соеденениями. Метод возвращает название предыдущего соеденения. Если параметр не задан, то возвращает название текущего соеденения.

Пример

// first
print_r(sql::using());

// first
print_r(sql::using('third'));

// third
print_r(sql::using('first'));

sql::table()

Инициализирует модель описывающую таблицу либо обьект класса SQL. Метод был создан, чтобы избежать проблем с отсутствующей моделью.

Пример

// модель не описана и это вызовет ошибку
$table = new Table;

// всё оки и при этом имеем обьект
$table = sql::table('table');

Вторым параметром можно указать идентификатор записи.

// модель не описана и это вызовет ошибку
$table = new Table(2);

// всё оки и при этом имеем обьект
$table = sql::table('table', 2);

Ну, и ещё инициализируя модель через sql::table() можно сразу писать "сосиской", "паровозом" и прочими гомо-подобными синонимами.

$table = sql::table('table')->where('name = ?', 'Test')->as_array();

sql::is_valid()

Проверяет является ли соеденение удачным.

sql::link()

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

sql::last_id(), sql->last_id()

Возвращает последний вставленный ID.

Пример

print_r(sql::last_id());

// или

print_r(sql::last_id('table'));

// или

$table = new Table;
print_r($table->last_id());

sql::last_error()

Возвращает массив с данными о последней ошибки. Указав первый параметр можно получить конкретный ключ массива.

sql::last_query()

Возвращает массив с данными о последнем запросе. Указав первый параметр можно получить конкретный ключ массива.

sql::statistics()

Возвращает массив с данными по статистике. Указав первый параметр можно получить конкретный ключ массива.

sql::logger()

Устанавливает функцию, которая послужит логером для запросов и ошибок.

sql::relations()

Строит карту связей между таблицами.

sql::schema(), sql->schema()

Возвращает рабочую информацию по таблице.

Пример

print_r(sql::schema('table'));

// или

$table = new Table;
print_r($table->schema());

/* Array
(
    [id] => Array
        (
            [name] => id
            [type] => int(11) unsigned
            [null] =>
            [key] => p
            [auto] => 1
            [default] =>
        )

    [name] => Array
        (
            [name] => name
            [type] => varchar(255)
            [null] =>
            [key] =>
            [auto] =>
            [default] =>
        )

) */

sql::raw()

Метод используется как плейсхолдер для "чистого" запроса.

Пример

print_r(sql::get('select * from [table] where id = ?', sql::raw('1 + 1')));

/* Array (
    [0] => Array (
        [id] => 2
        [name] => Test
    )
) */

sql::childrens(), sql->childrens()

Возвращает идентификаторы "детей".

Пример

// второй параметр - идентификатор, для которого следует получить "детей"
print_r(sql::childrens('table', 2));

// или

$table = new Table(2);
print_r($table->childrens());

Обратите внимание: на данный момент SQL работает только с одним типом деревьев: через ключ-родитель.