Класс для работы с базой данных
Класс состоит из двух частей: 1) простая обёртка для DbSimple плюс пара заплаток и исправлений для Berry; 2) ORM. Поэтому данная документация состоит как бы из двух частей тоже: статичных методов (в названиях метода есть ::) и методов вызываемые от обьекта (в названиях метода есть →). Некоторые методы могут работать и как статичные, и как динамические — разница в знаках (на кукурузных полях).
Полную информацию касательно самой DbSimple вы сможете найти на официальном сайте.
Устанавливает реальное название табицы. Можно указать таблицу из другой БД.
class Table extends SQL {
public $table = 'example_table';
}
// или
class Table extends SQL {
public $table = 'some_db.prefix_table';
}
Установка первичного ключа, идентификатора. По умолчанию это id. Можно выбрать и нечисловой идентификатор.
// по id
$table = new Table(2);
// по какому-то иному полю с ключом unique
$table = new Table('Сосиски');
Описывает связь типа
Обратите внимание: связи строятся не на отношении класса к таблице, а на отношениях класса к классу.
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'));
}
Описывает связь типа
class Post extends SQL {
public $has_one = array('user');
}
class User extends SQL {
public $table = 'profiles';
// это оно
public $belongs_to = array('post'); // тут один post
}
Сзязь
class Post extends SQL {
public $has_one = array('user');
}
class User extends SQL {
public $table = 'profiles';
// это оно
public $has_many = array('posts'); // много данных из post поэтому posts
}
Описывает тип связи
class Post extends SQL {
// это оно
public $has_and_belongs_to_many = array('categories');
}
class Category extends SQL {
// обратная сторона много-ко-многим точно такая же
public $has_and_belongs_to_many = array('posts');
}
Валидация при сохранении. В случае неудачи, выбрасывается исключение 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.
Скопление — массив значений слздающий функции.
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(array(
'username' => 'пользователь',
'password' => 'пароль',
'database' => 'сервер/база данных',
'prefix' => 'префиккс'
));
// или
sql::connect(array(
'first' => array(
'username' => 'пользователь',
'password' => 'пароль',
'database' => 'сервер/база данных',
'prefix' => 'префиккс'
),
'second' => array(
'username' => 'пользователь',
'password' => 'пароль',
'database' => 'сервер/база данных',
'prefix' => 'префиккс'
)
));
Названия ключей не имеют значения. Главным соеденением будет то, что стоит раньше. В примере это first.
Переключает соеденение или возвращает название текущего.
// first - текущее соеденение
print_r(sql::using());
// first - переключаем соеденение, возвращается название предыдущего
print_r(sql::using('second'));
// second
print_r(sql::using('first'));
Выполняет запрос возвращает объект 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, а именно квадратные скобки вокруг имени таблицы. После обработки к имени таблицы будет подставлен префикс, если он был указан в настройках соеденения.
Возвращает массив данных.
$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
)
) */
Возвращает результат в виде одной ячейки.
// 5
print_r(sql::query('select id from ?_', 'table')->fetch_cell());
Возвращает результат в виде одной колонки. Хорошо использовать с array_key.
print_r(sql::query('select name, id as array_key from ?_', 'table')->fetch_col());
/* Array (
[1] => Some
[2] => Test
) */
Возвращает результат в виде одного ряда.
print_r(sql::query('select * as array_key from ?_ where id = ?', 'table', 2)->fetch_row());
/* Array (
[id] => 2
[name] => Test
) */
Возвращает число найденых строк.
$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() тоже возвращает массив. Но 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
)
) */
Напрямую указывает что нужно получить и таким образом сократить
$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() напрямую лучше не использовать, а описывать связи в моделях.
// можно, но не надо
$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() напрямую лучше не использовать.
$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».
Добавляет критерии поиска. Первым параметром должна идти строка или массив (для 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 (или иного) на
Добавляет сортировку. Можно указывать как отдельным методом на каждую сортировку, так и любым количеством параметров метода.
$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() позволяет сортировать данные по страницам, а не по количеству.
$table->limit(10);
// синоним sql->offset(40)
$table->page(5);
select […] limit 10, 20, где 20 и есть этот самый offset. Как
// limit 10, 40
$table->limit(10);
$table->offset(40);
Добавляет группировку по полю(ям).
$table->group_by('field1', 'field2');
Добавляет фильтр по полю(ям).
Объединяет результаты нескольких запросов. Возвращает объект 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
)
) */
Сохраняет данные и возвращает:
// вставляем данные
$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)
См. описание 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→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 = 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();
Проверяет является ли соеденение удачным.
Возвращает ссылку используемого соеденения.
Возвращает последний вставленный ID.
print_r(sql::last_id());
// или
print_r(sql::last_id('table'));
// или
$table = new Table;
print_r($table->last_id());
Возвращает массив с данными о последней ошибки. Указав первый параметр можно получить конкретный ключ массива.
Возвращает массив с данными о последнем запросе. Указав первый параметр можно получить конкретный ключ массива.
Возвращает массив с данными по статистике. Указав первый параметр можно получить конкретный ключ массива.
Устанавливает функцию, которая послужит логером для запросов и ошибок.
Строит карту связей между таблицами.
Возвращает рабочую информацию по таблице.
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] =>
)
) */
Метод используется как плейсхолдер для «чистого» запроса.
print_r(sql::query('select * from ?_ where id = ?', 'table', sql::raw('1 + 1'))->fetch());
/* Array (
[0] => Array (
[id] => 2
[name] => Test
)
) */
Возвращает идентификаторы «детей».
// второй параметр - идентификатор, для которого следует получить "детей"
print_r(sql::childrens('table', 2));
// или
$table = new Table(2);
print_r($table->childrens());
Обратите внимание: на данный момент SQL работает только с одним типом деревьев — через