Добро пожаловать в русскую документацию по Idiorm!

Здесь вы найдете полный перевод официальной документации.

Автор перевода: Кирилл skv1991 Салтыков

Содержание:

Философия

Закон Парето гласит, что 20% действий приносит 80% результата. В терминах разработки ПО, это можно перевести приблизительно так: 20% сложностей дают 80% результата. Другими словами, вы можете многого добиться, будучи не особо умным.

Idiorm умышленно создан простым. В то время, как другие ORM состоят из множества классов с сложной иерархий наследования, у Idiorm только один класс, ORM, который функционирует и как беглый API для создания запросов SELECT и как простой класс модели CRUD. Если моя догадка верна, этого должно быть достаточно для многих современных приложений. Посмотрим правде в глаза: большинство из нас не создает свой Facebook. Мы работает над проектами от маленьких до больших размеров, где акцент делается на простоту и быстрое развитие, а не на бесконечную гибкость и возможности.

Можно рассматривать Idiorm как микро-ORM. Он может быть как “галстук, идущий вместе со смокингом Slim” (заимствованный оборот из фразы в DocumentCloud). Или может быть одним из инструментов в генеральной уборке этих ужасающих, заваленных SQL-мусором наследников PHP приложений, которые вы должны поддерживать.

Idiorm также может предоставить хорошую базу, на которой строится более высокоуровневые, более сложные абстракции базы данных. Например, Paris это реализация паттерна Active Record pattern построенная на базе Idiorm.

Установка

Packagist

Данная библиотека доступна через Packagist с идентификаторами vendor и package: j4mie/idiorm

Пожалуйста, ознакомьтесь с Packagist documentation для более исчерпывающей информации.

Загрузка

Вы можете склонировать git-репозиторий, скачать idiorm.php или release tag и затем поместить файл idiorm.php в директорию vendors/3rd party/libs вашего проекта.

Конфигурация

Первое, что нужно знать об Idiorm - вам не нужно объявлять какие-либо классы модели для её использования. С почти любой другой ORM, первым шагом является установка моделей и их связка с таблицами из базы данных (через переменные конфигурации, XML файлы и тому подобное). С Idiorm, вы можете приступить к использованию ORM сразу же.

Установка

Первым делом, укажите файл исходного кода Idiorm в require:

<?php
require_once 'idiorm.php';

Затем передайте Data Source Name строку соединения в метод configure класса ORM. Он используется PDO для соединения с вашей базой данных. Для более детальной информации, смотри документацию PDO.

<?php
ORM::configure('sqlite:./example.db');

Вы так же можете передать имя пользователя и пароль в драйвер базы данных, используя параметры конфигурации username и password. Например, если вы используете MySQL:

<?php
ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

Смотрите так же секцию “Конфигурация” ниже.

Конфигурация

Помимо передачи DSN строки для подключения к базе данных (смотри выше), метод configure можно использовать и для установки некоторых других простых настроек ORM класса. Изменение настроек подразумевает передачу в метод configure пар ключ/значение, представляющих название параметра, который вы хотите поменять, и значение, которое хотите ему установить.

<?php
ORM::configure('название_параметра', 'значение_для_параметра');

Следующий метод используется для передачи множества пар ключ/значение за раз.

<?php
ORM::configure(array(
    'название_параметра_1' => 'значение_для_параметра_1',
    'название_параметра_2' => 'значение_для_параметра_2',
    'etc' => 'etc'
));

Для чтения текущей конфигурации, используйте метод get_config.

<?php
$isLoggingEnabled = ORM::get_config('logging');
ORM::configure('logging', false);
// какой-то бешенный цикл, который мы не хотим добавлять в лог
ORM::configure('logging', $isLoggingEnabled);

Подробности аутентификации в базе данных

Параметры: username и password

Некоторые адаптеры баз данных (такие как MySQL) требуют раздельной передачи имени пользователя (username) и пароля (password) в DSN строке. Эти параметры позволяют вам передать их. Типичная настройка соединения MySQL может выгялдеть так:

<?php
ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

Или вы можете соединить настройку соединения в одну строку, используя массив конфигурации:

<?php
ORM::configure(array(
    'connection_string' => 'mysql:host=localhost;dbname=my_database',
    'username' => 'database_user',
    'password' => 'top_secret'
));

Наборы результатов

Параметр: return_result_sets

Коллекция результатов данных может быть возвращена в качестве массива (по-умолчанию) или в виде результирующего набора. Смотрите документацию о find_result_set() для более подробной информации.

<?php
ORM::configure('return_result_sets', true); // возвращает результирующий набор

PDO Параметры драйвера

Параметр: driver_options

Некоторые адаптеры базы данных требуют (или позволяют использовать) массив параметров конфигурации для конкретного драйвера. Это позволяет вам передавать эти параметры через конструктор PDO. Для более подробной информации, смотрите документацию PDO. Например, чтобы заставить драйвер MySQL использовать кодировку UTF-8 для соединения:

<?php
ORM::configure('driver_options', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));

PDO Режим ошибок

Параметр: error_mode

Можно использовать для установки параметра PDO::ATTR_ERRMODE у класса соединения с базой данных, используемой Idiorm. Должна быть передана одна из объявленных в классе констант PDO. Пример:

<?php
ORM::configure('error_mode', PDO::ERRMODE_WARNING);

Параметром по-умолчанию является PDO::ERRMODE_EXCEPTION. Для более подробной информации о доступных режимах ошибок, смотри документация PDO - присвоение атрибута.

PDO доступ к объекту

Если он когда-то потребуется, то объект PDO, используемый в Idiorm может быть получен напрямую через ORM::get_db(), или установлен напрямую через ORM::set_db(). Однако это редкое явление.

После того, как заявление было выполнено с помощью любых средств, таких, как ::save() или ::raw_execute(), испольуземый экземпляр PDOStatement может быть получен через ORM::get_last_statement(). Это может быть полезно для доступа к PDOStatement::errorCode(), если исключения в PDO отключены, или для доступа к методу PDOStatement::rowCount(), который возвращает различные результаты, относительно основной базы данных. Чтобы узнать больше, смотри PDOStatement документация.

Идентификатор символа кавычек

Параметр: identifier_quote_character

Устанавливает символ, используемый для идентификации кавычек (например имени таблицы, имени столбца). Если не задан, то будет определен автоматически в зависимости от драйвера базы данных, используемого в PDO.

ID столбца

По-умолчанию, ORM предполагает, что у всех ваших таблиц есть колонка первичного ключа(primary key)
с именем id. Есть два способа это переопределить: для всех таблиц в базе данных, или на основе каждой таблицы.

Параметр: id_column

Этот параметр используется для конфигурации имени столбца первичного ключа (primary key) всех таблиц. Если ваша ID-колонка имеет название primary_key, используйте:

<?php
ORM::configure('id_column', 'primary_key');

Вы можете указать составной первичный ключ, используя массив:

<?php
ORM::configure('id_column', array('pk_1', 'pk_2'));

Примечание: Если вы используете столбец с auto-increment в составном первичном ключе, то он должен быть объявлен первым в массиве.

Параметр: id_column_overrides

Этот параметр используется для указания имени столбца первичного ключа для каждой таблицы отдельно. Он принимает ассоциативный массив, описывающий название таблиц и имен столбцов. Например, если, имена ID-столбца включают имя таблицы, то вы можете использовать следующую настройку:

<?php
ORM::configure('id_column_overrides', array(
    'person' => 'person_id',
    'role' => 'role_id',
));

Как и параметр id_column, вы можеите указать составной первичный ключ, используя массив.

Limit clause style

Параметр: limit_clause_style

Вы можете установить стиль ограничения в конфигурации. Это делается для облегчения ограничений в стиле MS SQL, использующий синтаксис TOP.

Допустимыми значениями являются ORM::LIMIT_STYLE_TOP_N и ORM::LIMIT_STYLE_LIMIT.

Лог запросов

Параметр: logging

Idiorm может записывать в лог все вызываемые запросы. Для включения лога запросов, установите параметр logging на true (по-умолчанию он имеет значение false).

Когда лог запросов включен, вы можете использовать два статических метода для доступа к логу. ORM::get_last_query() возвращает самый последний вызванный запрос. ORM::get_query_log() возвращает массив всех вызванных запросов.

Logger запросов

Параметр: logger

Можно передать в этот параметр конфигурации callable, который будет вызываться для каждого запроса, вызываемого idiorm. В PHP callable зовется все, что может быть вызвано, как если бы это была функция. Чаще всего это будет представляться в виде анонимной функции.

Это полезный параметр, если вы хотите отслеживать лог запросов с помощью внешней библиотеки, так как он позволяет получить все то, что происходит внутри функций.

<?php
ORM::configure('logger', function($log_string, $query_time) {
    echo $log_string . ' in ' . $query_time;
});

Кэширование запросов

Параметр: caching

Idiorm может кэшировать выполняемые запросы во время обращения. Для включения кэширования запросов, установите параметру caching значение true (по-умолчанию имеет значение false).

<?php
ORM::configure('caching', true);

Параметр: caching_auto_clear

По-умолчанию, кэш Idiorm никогда не очищается. Если вы хотите, чтобы он очищался после сохранения, установите параметр caching_auto_clear на значение true

<?php
ORM::configure('caching_auto_clear', true);

Когда включено кэширование запросов, Idiorm будет кэшировать результаты каждой выборки SELECT, которая была вызвана. Если Idiorm сталкивается с запросом, который уже был вызван, то он извлечет результаты прямо из кэша и не будет обращаться к базе данных.

Предупреждения и подводные камни
  • Обратите внимание что для кэширования используется внутренняя память, сохраняющаяя данные в пределах одного запроса. Это не замена для существующих систем кэширования вроде Memcached.
  • Кэш Idiorm построен очень просто, и не пытается стать недействительным, если данные изменились. Это означает, если вы выполните запрос для извлечения каких-то данных, измените их и сохраните, а далее вызовите такой же запрос снова, то результаты будут устаревшими (т.е., они не будут отражать изменений). Это может привести к потенциальным трудоуловимым ошибкам в вашем приложении. Если у вас включено кэширование и вы заметили странное поведение, отключите его и попробуйте снова. Если вам все-таки нужно выполнять такие операции, но вы хотите оставь кэш включенным, то можно вызвать метод ORM::clear_cache() для очистки всех кэшированных запросов.
  • Включение кэширования увеличивает расход памяти для приложения, так как все строки базы данных, полученные по время каждого запроса будут храниться в памяти. Если вы работаете с большими объемами данных, то лучше будет отключить кэш.
Произвольное кэширование

Если вы хотите использовать произвольные функции кэширования, вы можете задать их в параметрах конфигурации.

<?php
$my_cache = array();
ORM::configure('cache_query_result', function ($cache_key, $value, $table_name, $connection_name) use (&$my_cache) {
    $my_cache[$cache_key] = $value;
});
ORM::configure('check_query_cache', function ($cache_key, $table_name, $connection_name) use (&$my_cache) {
    if(isset($my_cache[$cache_key])){
       return $my_cache[$cache_key];
    } else {
    return false;
    }
});
ORM::configure('clear_cache', function ($table_name, $connection_name) use (&$my_cache) {
     $my_cache = array();
});

ORM::configure('create_cache_key', function ($query, $parameters, $table_name, $connection_name) {
    $parameter_string = join(',', $parameters);
    $key = $query . ':' . $parameter_string;
    $my_key = 'my-prefix'.crc32($key);
    return $my_key;
});

Запросы

Idiorm предоставляет fluent interface позволяющий построение простых запросов без единого использования SQL. Если вы использовали jQuery вообще, то будете уже знакомы с концепцией fluent interface. Просто напросто это значит что вы можете сцеплять в цепочку вызов методов вместе, один после другого. Это может сделать ваш код более читабельным, нанизывая методы друг на друга, как-будто вы составляете предложение.

Все запросы в Idiorm начинаются с вызова статического метода for_table класса ORM. Это сообщает ORM какую таблицу использовать при построении запроса.

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

Вызовы метода добавляют фильтры и ограничения в ваш запрос, нанизываясь друг на друга. Наконец, цепочка заканчивается вызовом метода find_one() или find_many(), которые выполняют запрос и возращают результат.

Начнем с простых примеров. Скажим у нас есть таблица person содержащая столбцы id (первичный ключ записи - Idiorm предполагает что столбец первчиных ключей называется id но это можно настроить, смотри ниже), name, age и gender.

Примечание по PSR-1 и стилю camelCase

Все методы, описанные в документации могут так же быть вызваны, используя стандарт PSR-1: подчеркивания (_) заменяются на стиль написания camelCase. Далее приведен пример одной цепочки запроса, конвертированной в совместимый с PSR-1 стиль.

<?php
// документация и стиль по-умолчанию
$person = ORM::for_table('person')->where('name', 'Fred Bloggs')->find_one();

// PSR-1 совместимый стиль
$person = ORM::forTable('person')->where('name', 'Fred Bloggs')->findOne();

Как вы можете заметить, любой метод может быть изменен из формата с подчеркиваниями (_) как в документации в стиль camelCase.

Одиночные записи

Любая цепочка методов, заканчивающаяся на find_one() вернет либо единичный экземпляр класса ORM представляющий ряд из базы данных по указанному запросу, или false если не было найдено удовлетворяющих запросу записей.

Чтобы найти одиночную запись, где столбец name имеет значение “Fred Bloggs”:

<?php
$person = ORM::for_table('person')->where('name', 'Fred Bloggs')->find_one();

Грубо переводя на язык SQL, это: SELECT * FROM person WHERE name = "Fred Bloggs"

Чтобы найти единичную запись по ID, вы можете передать ID прямо в метод find_one:

<?php
$person = ORM::for_table('person')->find_one(5);

Если вы используете составной первичный ключ, то можете найти записи используя массив в качестве параметра:

<?php
$person = ORM::for_table('user_role')->find_one(array(
    'user_id' => 34,
    'role_id' => 10
));

Множество записей

Любая цепочка методов, заканчивающаяся на find_many() вернет массив экземпляров ORM-класса, по одному для каждой удовлетворяющей запросу строки. Если не было найдено ни одной строки, то будет возвращен пустой массив.

Чтобы найти все записи в таблице:

<?php
$people = ORM::for_table('person')->find_many();

Чтобы найти все записи, где gender равен female:

<?php
$females = ORM::for_table('person')->where('gender', 'female')->find_many();

Как результирующий набор

Вы так же можете найти множество записей в качестве результирующих наборов вместо массива экземплятров Idiorm. Это дает преимущество в том, что вы можете запустить пакетные операции на наборе результатов.

Итак, для примера, вместо этого:

<?php
$people = ORM::for_table('person')->find_many();
foreach ($people as $person) {
    $person->age = 50;
    $person->save();
}

Вы можете использовать это:

<?php
ORM::for_table('person')->find_result_set()
->set('age', 50)
->save();

Чтобы это сделать, замените любой вызов метода find_many() методом find_result_set().

Результирующий набор ведет себя так же, как и массив, так что вы можете использовать на нем count() и foreach как и с массивом.

<?php
foreach(ORM::for_table('person')->find_result_set() as $record) {
    echo $record->name;
}
<?php
echo count(ORM::for_table('person')->find_result_set());

Как ассоциативный массив

Так же вы можете найти множество записей в виде ассоциативного массива, вместо экземпляров Idiorm. Для этого замените любой вызов метода find_many() на метод find_array().

<?php
$females = ORM::for_table('person')->where('gender', 'female')->find_array();

Это полезно, если вам нужно преобразовать результат запроса в последовательную форму записи(сериализация массива) для JSON, и вам не нужно дополнительной возможности обновлять возвращаемые данные.

Подсчет результатов

Для подсчета числа строк, возвращаемых запросом, вызовите метод count().

<?php
$number_of_people = ORM::for_table('person')->count();

Фильтрация результатов

Idiorm предоставляет семейство методов, позволяющих извлечь только те записи, которые удовлетворяют определенному условию(ям). Эти методы можно вызывать множество раз для построения запроса, а fluent interface у Idiorm позволяет строить цепочку из таких методов, для построения читабельных и простых к пониманию запросов.

Предостережения

Только подмножество доступных условий, поддерживаемых SQL доступны при использовании Idiorm. Кроме того, все пункты WHERE будут соединены с использованием AND при выполнении запроса. Поддержка OR в пунктах WHERE в настоящее время отстутствует.

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

Некоторая поддержка более сложных условий и запросов реализована в методах where_raw и raw_query (смотрите ниже). Если вы поймете, что чаще нуждаетесь в в большем функционале, нежели содержит Idiorm, то возможно пришло время рассмотреть более полнофункциональный ORM.

Равенство: where, where_equal, where_not_equal

По-умолчанию, вызывая where с двумя параметрами (название столбца и значение), они будут соединены, используя оператор равенства (=). Например, вызов where('name', 'Fred') вернет следующее: WHERE name = "Fred".

Если ваш стиль написания кода направлен на ясность написанного, а не на краткость, то можно использовать метод where_equal идентичный методу where.

Метод where_not_equal добавляет пункт WHERE column != "value" к вашему запросу.

Можно указать множество столбцов и их значений в пределах одного вызова. В этом случае, вам нужно передать ассоциативный массив в качестве первого параметра. В нотации массива, ключи используются как названия стобцов.

<?php
$people = ORM::for_table('person')
            ->where(array(
                'name' => 'Fred',
                'age' => 20
            ))
            ->find_many();

// Создаст следующий запрос SQL:
SELECT * FROM `person` WHERE `name` = "Fred" AND `age` = "20";

Короткая запись: where_id_is

Это простой вспомогательный метод, для составления запроса по первичному ключу таблицы. Смотрит относительно ID столбца, указанного в конфигурации. Если вы используете составной первичный ключ, то нужно передать массив, где ключом является название столбца. Столбцы, не принадлежащие к этому ключу будут игнорироваться.

Короткая запись: where_id_in

Этот вспомагательный метод аналогичен where_id_is, но он ожидает массив первичных ключей для выборки. Так же понимает и составной первичный ключ.

Меньше чем / больше чем: where_lt, where_gt, where_lte, where_gte

Есть четыре метода, доступные для неравенств:

  • Меньше чем (less than): $people = ORM::for_table('person')->where_lt('age', 10)->find_many();
  • Больше чем (greater than): $people = ORM::for_table('person')->where_gt('age', 5)->find_many();
  • Меньше или равен (less than or equal): $people = ORM::for_table('person')->where_lte('age', 10)->find_many();
  • Больше или равен (greater than or equal_: $people = ORM::for_table('person')->where_gte('age', 5)->find_many();

Сравнение строк: where_like и where_not_like

Для добавления пункта WHERE ... LIKE, используйте:

<?php
$people = ORM::for_table('person')->where_like('name', '%fred%')->find_many();

Аналогично и для WHERE ... NOT LIKE, используйте:

<?php
$people = ORM::for_table('person')->where_not_like('name', '%bob%')->find_many();

Множественные условия OR

Можно добавить простое условие OR в тот же пункт WHERE используя where_any_is. Если вам нужно указать множество условий, используйте массив элементов. Каждый элемент будет ассоциативным массивом, содержащим множество условий.

<?php
$people = ORM::for_table('person')
            ->where_any_is(array(
                array('name' => 'Joe', 'age' => 10),
                array('name' => 'Fred', 'age' => 20)))
            ->find_many();

// Создаст SQL запрос:
SELECT * FROM `widget` WHERE (( `name` = 'Joe' AND `age` = '10' ) OR ( `name` = 'Fred' AND `age` = '20' ));

По-умолчанию, оператор равенства используется для каждого столбца, но его можно переопределить для любого столбца, используя второй параметр:

<?php
$people = ORM::for_table('person')
            ->where_any_is(array(
                array('name' => 'Joe', 'age' => 10),
                array('name' => 'Fred', 'age' => 20)), array('age' => '>'))
            ->find_many();

// Создаст SQL запрос:
SELECT * FROM `widget` WHERE (( `name` = 'Joe' AND `age` > '10' ) OR ( `name` = 'Fred' AND `age` > '20' ));

Если вы хотите задать свой оператор по-умолчанию для всех столбцов, то нужно передать его как второй параметр:

<?php
$people = ORM::for_table('person')
            ->where_any_is(array(
                array('score' => '5', 'age' => 10),
                array('score' => '15', 'age' => 20)), '>')
            ->find_many();

// Создаст SQL запрос:
SELECT * FROM `widget` WHERE (( `score` > '5' AND `age` > '10' ) OR ( `score` > '15' AND `age` > '20' ));

Определение принадлежности: where_in и where_not_in

Для добавления пунктов WHERE ... IN () или WHERE ... NOT IN (), используйте методы where_in и where_not_in соответственно.

Оба метода принимают два аргумента. Первый - название столбца, с которым сравнивать. Второй - массив возможных значений. Как и во всех методах where_, вы можете указать множество столбцов, используя ассоциативный массив в качестве параметра.

<?php
$people = ORM::for_table('person')->where_in('name', array('Fred', 'Joe', 'John'))->find_many();

Работа с NULL значениями: where_null и where_not_null

Для добавления пункта WHERE column IS NULL или WHERE column IS NOT NULL, используйте методы where_null и where_not_null соответственно. Оба метода принимают один параметр: название столбца для сравнения.

Необработанный WHERE

Если вам необходимо создать более сложный запрос, то можно использовать метод where_raw для указания нужного SQL-фрагмента для пункта WHERE. Данный метод принимает два аргумента: строку, добавляемую к запросу, и (опционально) массив параметров, который будет связан со строкой. Если параметры были переданы, строка должна содержать знаки вопроса (?) как плейсхолдеры, для подстановки вместо них значений из массива, а массив должен содержать значения, которые будут подставлены в строку в соответствующем порядке.

Данный метод можно использовать в цепочке методов вместе с другими методами where_* а так же с методами вроде offset, limit и order_by_*. Содержимое переданной строки будет соединено с предыдущими и последующими пунктами WHERE с AND в качестве соединения.

<?php
$people = ORM::for_table('person')
            ->where('name', 'Fred')
            ->where_raw('(`age` = ? OR `age` = ?)', array(20, 25))
            ->order_by_asc('name')
            ->find_many();

// Создаст SQL запрос:
SELECT * FROM `person` WHERE `name` = "Fred" AND (`age` = 20 OR `age` = 25) ORDER BY `name` ASC;

Обратите внимание, что этот метод поддерживает только синтакс “плейсхолдера в виде вопроса”, а НЕ синтакс “именной плейсхолдер”. Все потому, что PDO не позволяет создавать запросы, содержащие смешанные типы плейсхолдеров. Так же, необходимо убедиться в том, что число вопросов-плейсхолдеров в строке соответствует числу элементов в массиве.

Если вам нужно ещё больше гибкости, вы можете вручную указать всю строку запроса. Смотрите Необработанные запросы ниже.

Limit и offset

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

Методы limit и offset очень похожи на эквивалентные им в SQL.

<?php
$people = ORM::for_table('person')->where('gender', 'female')->limit(5)->offset(10)->find_many();

Порядок

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

Доступны два метода для добавления к запросу пункта ORDER BY. Это order_by_desc и order_by_asc, каждый из которых принимает название столбца для сортировки. Имена столбцов будут писаться в кавычках.

<?php
$people = ORM::for_table('person')->order_by_asc('gender')->order_by_desc('name')->find_many();

Если вы хотите упорядочить по какому-то другому признаку, отличному от названия столбца, то используйте метод order_by_expr для добавления SQL выражения без кавычек, как в пункте ORDER BY.

<?php
$people = ORM::for_table('person')->order_by_expr('SOUNDEX(`name`)')->find_many();

Группировка

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

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

<?php
$people = ORM::for_table('person')->where('gender', 'female')->group_by('name')->find_many();

Так же возможно использование GROUP BY с выражениями из базы данных:

<?php
$people = ORM::for_table('person')->where('gender', 'female')->group_by_expr("FROM_UNIXTIME(`time`, '%Y-%m')")->find_many();

Having

При использовании агрегирующих функций в комбинации с GROUP BY вы можете использовать HAVING для фильтрации, относительно этих значений.

HAVING работает точно таким же способом, что и все методы where* в Idiorm. Замените where_ на having_ для использования этих функций.

Например:

<?php
$people = ORM::for_table('person')->group_by('name')->having_not_like('name', '%bob%')->find_many();

Столбцы в результате

По-умолчанию, все столбцы в выражении SELECT будут возвращены после запроса. То есть, вызывая:

<?php
$people = ORM::for_table('person')->find_many();

В результате сформирует запрос:

<?php
SELECT * FROM `person`;

Метод select дает контроль над тем, какие столбцы будут возвращены. Вызовите select несколько раз для указания нужных столбцов или используйте select_many для указания нескольких столбцов за раз.

<?php
$people = ORM::for_table('person')->select('name')->select('age')->find_many();

В результате сформирует запрос:

<?php
SELECT `name`, `age` FROM `person`;

Опционально, можно передать второй аргумент в select для указания алиаса столбца:

<?php
$people = ORM::for_table('person')->select('name', 'person_name')->find_many();

В результате сформирует запрос:

<?php
SELECT `name` AS `person_name` FROM `person`;

Названия столбцов, переданные в select автоматически заносятся в кавычки, даже если содержат идентификаторы в стиле table.column:

<?php
$people = ORM::for_table('person')->select('person.name', 'person_name')->find_many();

В результате сформирует запрос:

<?php
SELECT `person`.`name` AS `person_name` FROM `person`;

Если вы хотите переопределить это поведение (например, для передачи выражения из базы данных) то вместо этого метода нужно использовать метод select_expr. Он так же принимает алиас в качестве второго аргумента. Можно указать несколько выражений, вызвав select_expr несколько раз или использовать select_many_expr для указания нескольких выражений за раз.

<?php
// Примечание: Только для иллюстрации. Для выполнения подсчется, используйте метод count().
$people_count = ORM::for_table('person')->select_expr('COUNT(*)', 'count')->find_many();

В результате сформирует запрос:

<?php
SELECT COUNT(*) AS `count` FROM `person`;

Короткая запись для указания множества столбцов

select_many и select_many_expr очень похожи, но позволяют указать более одного столбца за раз. Например:

<?php
$people = ORM::for_table('person')->select_many('name', 'age')->find_many();

В результате сформирует запрос:

<?php
SELECT `name`, `age` FROM `person`;

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

<?php
$people = ORM::for_table('person')->select_many(array('first_name' => 'name'), 'age', 'height')->find_many();

В результате сформирует запрос:

<?php
SELECT `name` AS `first_name`, `age`, `height` FROM `person`;

Вы можете использовать такой стиль при передаче аргументов в select_many и select_many_expr путем смешивания и сопоставления массивов и параметров:

<?php
select_many(array('alias' => 'column', 'column2', 'alias2' => 'column3'), 'column4', 'column5')
select_many('column', 'column2', 'column3')
select_many(array('column', 'column2', 'column3'), 'column4', 'column5')

Все методы выборки могут быть соединены в цепочку друг с другом, так что вы могли сделать следующий аккуратный запрос на выборку включающий в себя выражения:

<?php
$people = ORM::for_table('person')->select_many('name', 'age', 'height')->select_expr('NOW()', 'timestamp')->find_many();

В результате сформирует запрос:

<?php
SELECT `name`, `age`, `height`, NOW() AS `timestamp` FROM `person`;

DISTINCT

Для добавления ключевого слова DISTINCT перед списком результирующих столбцов в запросе, добавьте вызов метода distinct() в цепочку запроса.

<?php
$distinct_names = ORM::for_table('person')->distinct()->select('name')->find_many();

В результате сформирует запрос:

<?php
SELECT DISTINCT `name` FROM `person`;

Соединения Join

Idiorm содержит семейство методов для добавления различных типов JOIN(объединение) при построении запросов:

Методы: join, inner_join, left_outer_join, right_outer_join, full_outer_join.

Каждый из этих методов принимает одинковый набор аргументов. В описании будет использоваться базовый метод join в качестве примера, но то же самое применимо и к остальным методам.

Первые два аргумента являются обязательными. Первым идет имя таблицы для соединения, вторым условия для объединения. Рекумендуемым способом указания этих аргументов является массив содержащий три компонента: первый столбец, оператор, второй столбец. Название столбца и таблицы автоматический заключается в кавычки. Пример:

<?php
$results = ORM::for_table('person')->join('person_profile', array('person.id', '=', 'person_profile.person_id'))->find_many();

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

<?php
// Не рекомендуется, потому что условие объединения не экранируется.
$results = ORM::for_table('person')->join('person_profile', 'person.id = person_profile.person_id')->find_many();

Методы join так же принимают необязательный третий параметр, который служит как alias для таблицы в запросе. Это полезно, если нужно соединить таблицу с собой для создания иерархической структуры. В этом случае, лучше всего скомбинировать с методом table_alias, который добавит алиас к основной таблице, связанной с ORM, и методом select для управления возвращаемыми столбцами.

<?php
$results = ORM::for_table('person')
    ->table_alias('p1')
    ->select('p1.*')
    ->select('p2.name', 'parent_name')
    ->join('person', array('p1.parent', '=', 'p2.id'), 'p2')
    ->find_many();

Необработанные соединения JOIN

Если вам нужно построить более сложный запрос, то можно использовать метод raw_join для указания SQL-фрагмента для пункта JOIN. Этот метод принимает четыре обязательных аргумента: строку, добавляемую к запросу, условия в виде массива, содержащего три компонента: первый столбец, оператор, второй столбец, алиас таблицы и (необязательно) массив параметров. Если параметры переданы, строка должна содержать знаки вопроса (?) для представления подставляемых значений, и массив параметров должен создержать значения для подстановки в строку в корректной последовательности.

Этот метод может использоваться в цепочке наравне с другими методами *_join так же, как и методы вроде offset, limit и order_by_*. Содержимое переданной строки будет соединено с предшествующими и последующими пунктами JOIN.

<?php
$people = ORM::for_table('person')
            ->raw_join(
                'JOIN (SELECT * FROM role WHERE role.name = ?)',
                array('person.role_id', '=', 'role.id'),
                'role',
                array('role' => 'janitor'))
            ->order_by_asc('person.name')
            ->find_many();

// Создаст SQL запрос:
SELECT * FROM `person` JOIN (SELECT * FROM role WHERE role.name = 'janitor') `role` ON `person`.`role_id` = `role`.`id` ORDER BY `person`.`name` ASC

Обратите внимание, этот метод поддерживает только синтаксис “плейсхолдеров в виде знака вопроса”, а не синтаксис “именованных плейсхоледров”. Потмоу что PDO не позволяет создавать запросы с различным типом плейсхоледров. Так же нужно убедиться, что число знаков вопроса в строке совпадает с числом передаваемых значений в массиве.

Если вам нужно ещё больше гибкости, вы можете вручную написать весь запрос. Смотрите Необработанные запросы ниже.

Агрегатные функции

Существует поддержка MIN, AVG, MAX и SUM в дополнение к COUNT (описанно ранее).

Для получения минимального значения столбца, вызовите метод min().

<?php
$min = ORM::for_table('person')->min('height');

Остальные функции (AVG, MAX and SUM) работают таким же способом. Укажите название столбца для выполнения агрегатных функций, и в результате получите значение integer.

Необработанные запросы

Если вам нужно выполнять более сложные запросы, то можно полностью указать текст запроса, используя метод raw_query. Данный метод принимает строку и необязательный массив параметров. Строка может содержать плейсхолдеры, либо в виде знака вопроса, либо именованный плейсхолдер, который будет использоваться для внедрения параметров в запрос.

<?php
$people = ORM::for_table('person')->raw_query('SELECT p.* FROM person p JOIN role r ON p.role_id = r.id WHERE r.name = :role', array('role' => 'janitor'))->find_many();

Возвращаемый экземпляр(ы) класса ORM будет содержать данные для всех столбцов, возвращаемых запросом. Обратите внимание, что все так же нужно вызывать метод for_table для связки экземпляра с нужной таблицей, даже если нет ограничений на установку другой таблицы в запросе. Это сделано для того, чтобы при желании выполнить метод save, ORM знал какую таблицу обновлять.

Нужно так же иметь в виду, что использование raw_query требует дополнительных навыков и может быть опасным, и Idiorm не будет пытаться защитить вас от ошибок, которые могут появиться при использовании этого метода. Если вы заметите у себя частое используете raw_query, то возможно вы неправильно поняли цель использования ORM, или ваше приложение может быть слишком сложным, для использоваия Idiorm. Рассмотрите возможность использования более полнофункциональной системы абстракции базы данных (ORM).

Модели

Получение данных из объектов

Итак, когда вы получили набор записей (объектов) в результате запроса, то можете получить доступ к свойствам у этих объектов (значениям, которые хранятся в столбцах соответствующих таблиц) двумя способами: используя метод get, или напрямую обращаясь к свойству объекта:

<?php
$person = ORM::for_table('person')->find_one(5);

// Следующие два варианта записи являются эквивалетными
$name = $person->get('name');
$name = $person->name;

Так же есть возможность получить все данные внутри экземпляра ORM используя метод as_array. Он вернет ассоциативынй массив, описывающий имена столбцов (ключи) с их значениями.

Метод as_array принимает в качестве необязательного аргумента названия столбцов. Если был передан один или более таких аргументов, будут возвращены только совпадающие имена столбцов.

<?php
$person = ORM::for_table('person')->create();

$person->first_name = 'Fred';
$person->surname = 'Bloggs';
$person->age = 50;

// Вернет array('first_name' => 'Fred', 'surname' => 'Bloggs', 'age' => 50)
$data = $person->as_array();

// Вернет array('first_name' => 'Fred', 'age' => 50)
$data = $person->as_array('first_name', 'age');

Обновление записей

Для обновления базы данных, измените одно или более свойств объекта, затем вызовите метод save для принятия измененных данных. Опять же, можно изменять значения свойств объектов используя метод set или напрямую указать значение свойства. Используя метод set можно так же обновить множество свойств за раз, передав в метод ассоциативный массив:

<?php
$person = ORM::for_table('person')->find_one(5);

// Следующие два вида записи эквивалентны
$person->set('name', 'Bob Smith');
$person->age = 20;

// А это эквивалентно двум присваиваниям выше
$person->set(array(
    'name' => 'Bob Smith',
    'age'  => 20
));

// Синхронизируем объект с базой данных
$person->save();

Свойства, содержащие выражения

Можно задать свойства модели, содержащие выражения из базы данных, используя метод set_expr.

<?php
$person = ORM::for_table('person')->find_one(5);
$person->set('name', 'Bob Smith');
$person->age = 20;
$person->set_expr('updated', 'NOW()');
$person->save();

Значение у updated столбца будет вставлено в запрос в чистом виде, позволяя тем самым базе данных выполнить любую нужную нам функцию - в данном случае NOW().

Создание новых записей

Для добавления новой записи, сначала нужно создать “пустой” экземпляр объекта. Затем задать значения объекта как у обычного, и сохранить их.

<?php
$person = ORM::for_table('person')->create();

$person->name = 'Joe Bloggs';
$person->age = 40;

$person->save();

После сохранения объекта, вы можете вызвать его метод id() для определения сгенерированного первичного ключа, который был присвоен базой данных.

Проверка, было ли изменено свойство

Для проверки, было ли свойство объекта изменено с тех пор, как он был создан (или последний раз сохранен), вызовите метод is_dirty:

<?php
$name_has_changed = $person->is_dirty('name'); // Вернет true или false

Удаление записей

Для удаления объекта из базы данных, вызовите его метод delete.

<?php
$person = ORM::for_table('person')->find_one(5);
$person->delete();

Для удаления более одного объекта из базы данных, постройте запрос:

<?php
$person = ORM::for_table('person')
    ->where_equal('zipcode', 55555)
    ->delete_many();

Транзакции

Idiorm не поставляет каких-либо специальных методов для работы с транзакциями, но можно с легкостью использовать встронные в PDO меетоды:

<?php
// Начало транзакции
ORM::get_db()->beginTransaction();

// Коммит транзакции
ORM::get_db()->commit();

// Откат транзакции
ORM::get_db()->rollBack();

Для более подробной информации, ознакомьтесь с документацией PDO по Transactions.

Множественные подключения

Idiorm теперь работает со множественными подключениями. Большинство статических функций работают с опциональным именем соединения в качестве дополнительного параметра. Касательно метода ORM::configure, это означает, что при передаче строки соединения для установки нового соединения, второй параметр, который обычно опускается, должен быть равен null. Во всех случаях, если имя соединения не предоставлено, то оно примет значение по-умолчанию ORM::DEFAULT_CONNECTION.

При составлении цепочки, как только метод for_table() был использован, оставшиеся вызовы в цепочке будут использовать корректное соединение.

<?php
// Соединение по-умолчанию
ORM::configure('sqlite:./example.db');

// Именованное соединение, где 'remote' произвольное имя ключа
ORM::configure('mysql:host=localhost;dbname=my_database', null, 'remote');
ORM::configure('username', 'database_user', 'remote');
ORM::configure('password', 'top_secret', 'remote');

// Используя соединение по-умолчанию
$person = ORM::for_table('person')->find_one(5);

// Используя соединение по-умолчанию явным образом
$person = ORM::for_table('person', ORM::DEFAULT_CONNECTION)->find_one(5);

// Используя именованное соединение
$person = ORM::for_table('different_person', 'remote')->find_one(5);

Поддерживаемые методы

В каждом из этих случаев, параметр $connection_name необязательный, и является произвольным ключем, идентифицирующим название соединения.

  • ORM::configure($key, $value, $connection_name)
  • ORM::for_table($table_name, $connection_name)
  • ORM::set_db($pdo, $connection_name)
  • ORM::get_db($connection_name)
  • ORM::raw_execute($query, $parameters, $connection_name)
  • ORM::get_last_query($connection_name)
  • ORM::get_query_log($connection_name)

Среди этих методов, только ORM::get_last_query($connection_name) не использует соединение по-умолчанию, если не передано название подключения. Вместо этого, если не передавать название подключения (или значение null) то метод вернет самый последний запрос любого соединения.

<?php
// Используя соединение по-умолчанию явным образом
$person = ORM::for_table('person')->find_one(5);

// Используя именованное подключение
$person = ORM::for_table('different_person', 'remote')->find_one(5);

// Последний запрос *любого* соединения
ORM::get_last_query(); // вернет запрос в 'different_person' используя имя 'remote'

// Вернет запрос 'person' используя переданную строку соединения из настроек по-умолчанию
ORM::get_last_query(ORM::DEFAULT_CONNECTION);

Примечания

  • Нет поддержки объединений (join) по подключениям
  • Множественные подключения не делятся настройками конфигурации. Это означает, что если у одного соединения параметр логов имеет значение true а у другого нет, то только запросы из соединения со включенным логом будут доступны для методов ORM::get_last_query() и ORM::get_query_log().
  • Был добавлен новый метод, ORM::get_connection_names(), возвращающий массив с именами соединений.
  • Кэширование должно работать со множеством соединений (не забудьте включить кеширование для каждого соединения), однако это не надежно в отношении unit-тестирования. Пожалуйста, сообщайте об ошибках.