SQL

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

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

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

Переменные

sql→table

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

Пример

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

// или

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

sql→primary_key

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

Пример

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

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

sql→has_one

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

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

Пример

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

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

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

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

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

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

sql→belongs_to

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

Пример

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

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

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

sql→has_many

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

Пример

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

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

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

sql→has_and_belongs_to_many

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

Пример

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

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

sql→check

Валидация при сохранении. В случае неудачи, выбрасывается исключение Check_Except.

Пример

class Post extends SQL {
    // это оно
    protected $check = array(
        'title' => array('int(20, 40)', 'Кривенький заголовок-то.')
    );
}

$post = new Post;
$post->title = 'Сам ты кривенький.';

try {
    $post->save();
} catch (Check_Except $e){
    echo $e;
}
post[title] Кривенький заголовок-то.

Более подробно о валидации можно почитать в описании класса Check.

sql→scope

Скопление — массив значений слздающий функции.

class Post extends SQL {
    // это оно
    public $scope = array(
        'test' => array(
            'limit' => 5,
            'order_by' => 'id'
        )
    );
}

$post = new Post(2);

// where ... order by id limit 5
print_r($post->test()->fetch());

// То же самое, но без триггера
print_r($post->order_by('id')->limit(5)->fetch());

В скоплениях можно передавать значения.

class Post extends SQL {
    public $scope = array(
        'test' => array(
            'limit' => '?', // это оно
            'order_by' => 'id'
        )
    );
}

$post = new Post(10);

// where ... order by id limit 20
print_r($post->test(20)->fetch());

Методы

sql::connect()

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

Пример

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

// или

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

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

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

sql::using()

Переключает соеденение или возвращает название текущего.

// first - текущее соеденение
print_r(sql::using());

// first - переключаем соеденение, возвращается название предыдущего
print_r(sql::using('second'));

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

sql::query()

Выполняет запрос возвращает объект SQL_Query содержаший методы fetch(), fetch_cell(), fetch_col() и fetch_row().

Пример

print_r(sql::query('select * from ?_', 'table')->fetch());

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

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

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

sql→fetch()

Возвращает массив данных.

Пример

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

// или

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

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

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

sql→fetch_cell()

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

Пример

// 5
print_r(sql::query('select id from ?_', 'table')->fetch_cell());

sql→fetch_col()

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

Пример

print_r(sql::query('select name, id as array_key from ?_', 'table')->fetch_col());

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

sql→fetch_row()

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

Пример

print_r(sql::query('select * as array_key from ?_ where id = ?', 'table', 2)->fetch_row());

/* 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->fetch());

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

sql→fetch_array()

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

Пример

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

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

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

// получаем массив
print_r($post->fetch_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->fetch_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']->fetch_array());

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

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

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

sql→select()

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

Пример

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

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

    [string] => MySQL
) */

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

sql→from()

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

Пример

// можно, но не надо
$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

Метод может принимать массивы, в которых описаны связи. То есть динамически формировать их.

// Создаём обьект несуществующей модели, но существующей таблицы
$table = sql::table('testtable');

$table->join(array(
    'has_one' => array('sometable')
));

// Предыдущее равносильно записи

class Testtable {
    public $has_one = array('sometable');
}

// Само создание обьекта существующей модели
$table = new Testtable;

И/или обьекты. Про обьекты лучше почитать «Подзапрос в join» в разделе «Чуть больше о SQL».

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 пытается анализировать все поступающие поля. Так, например, поля содержащие точку будут считаться полями из другой таблице и, если такая таблица не фигурирует в запросе явно, она будет подключена. Полям же без точки SQL сама эту точку подставляет, изменяя имя поля id (или иного) на `текущая таблица`.id. Но при написании выражения в одну строку анализ будет проведён неверно.

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()

Добавляет группировку по полю(ям).

Пример

$table->group_by('field1', 'field2');

sql→having()

Добавляет фильтр по полю(ям).

sql::union()

Объединяет результаты нескольких запросов. Возвращает объект SQL_Union поддерживающий методы order_by(), limit(), offset(), page(), fetch(), fetch_cell(), fetch_col() и fetch_row().

Пример

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

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

$song7 = sql::query('
    select songs.id, songs.title, artists.name as `artist.name`
    from ?_, ?_
    where songs.id = ? and artists.id = songs.artist_id
', 'songs', 'artists',  7);

$union = sql::union($song1, $song5, $song7);
$union->order_by('title');

print_r($union->fetch());

/* Array
(
    [0] => Array
        (
            [id] => 7
            [title] => Hang It Up
            [artist.name] => Patrice Rushen
        )

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

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

) */

sql→save()

Сохраняет данные и возвращает:

  1. число-идентификатор последней вставленной записи, если, конечно, запись была вставленна;
  2. число 1 вернётся после успешного редактирования данных;
  3. если данные редактировать нет смысла, то есть они неизменены, то вернётся 0;
  4. и лишь при неудачи в случае ошибки возвращается null.
Либо массив содержащий типы, если была попытка добавить/отредактировать несколько записей.

Пример

// вставляем данные
$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());

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

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

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

Можно добавлять или редактировать все связанные данные.

$post = new Post;

// $post[2] === new Post(3)

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

// $post[0] === new Post(1)

$post[0]->name .= ' [edited]';
$post[0]->user->name = 'Some name';
$post[0]->categories[0]->name = 'New name';

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

Обратите внимание: доступ к связаным данным осуществляется по ключу массива, где 0 первая запись, а последняя — на примере категорий — $post[0]→categories[count($post[0]→categories) - 1].

sql→into()

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

sql→values()

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

Пример

$values1 = array(
    'field1' => 'Insert 1. Value 1',
    'field2' => 'insert 1. Value 2',
    'field3' => 'insert 1. Value 3'
);
$values2 = array(
    'field1' => 'Insert 2. Value 1',
    'field2' => 'Insert 2. Value 2',
    'field3' => 'Insert 2. Value 3'
);

$table = new Table;
$table->values($values1);
$table->values($values2);

// или

$fields = array('field1', 'field2', 'field3');
$values1 = array('Insert 1. Value 1', 'Insert 1. Value 2', 'Insert 1. Value 3');
$values2 = array('Insert 2. Value 1', 'Insert 2. Value 2', 'Insert 2. Value 3');

$table = new Table;
$table->into($fields);
$table->values($values1);
$table->values($values2);

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

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::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')->fetch_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::stat()

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

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::query('select * from ?_ where id = ?', 'table', sql::raw('1 + 1'))->fetch());

/* 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 работает только с одним типом деревьев — через ключ-родитель.