RedBeanPHP - ORM для PHP (примеры запросов)

ORM или Object-relational mapping (рус. Объектно-реляционное отображение) — это технология программирования, которая позволяет преобразовывать несовместимые типы моделей в ООП, в частности, между хранилищем данных и объектами программирования. ORM используется для упрощения процесса сохранения объектов в реляционную базу данных и их извлечения, при этом ORM сама заботится о преобразовании данных между двумя несовместимыми состояниями. В данной статье речь пойдёт о мощной ORM для PHP - RedBeanPHP. Статья особенно будет полезна новичкам, материал изложен в виде краткого конспекта. Тем не менее, всегда можно обратиться на официальный сайт.

Создать файл composer.json с таким содержимым:

{
  "require": {
    "gabordemooij/redbean": "dev-master"
  }
}

Из консоли выполнить:

composer install

В корне проекта создать файл index.php, в нём подключить автозагрузчик композера autoload.php и подключиться к БД Mysql:

// Подключаем автозагрузчик composer
require_once __DIR__.'/vendor/autoload.php';

// Создаём псевдоним для указанного класса
class_alias('\RedBeanPHP\R', '\R');

/**
 * Подключаемся к базе данных
 * Последний (4-й) параметр по умолчанию выставлен в FALSE
 * Если нужно применить заморозку таблиц в БД (отменить создание на лету),
 * то нужно данный параметр выставить в TRUE
 * или так: R::freeze(true);
 */
R::setup( 'mysql:host=localhost;dbname=redbeanphp','root', '', false);

// Проверка подключения к БД
if(!R::testConnection()) die('No DB connection!');

/**
 * Если нужно работать с таблицами, в названии которых
 * присутствует знак подчёркивания (_), то необходимо воспользоваться 
 * таким методом
 */
R::ext('xdispense', function( $type ){
  return R::getRedBean()->dispense( $type );
});
// Использовать так:
$test = R::xdispense('test_table');
// Code...
R::store($test);
// Указываем, что будем работать с таблицей book
$book = R::dispense('book');
// Заполняем объект свойствами
$book->title = 'Призрак победы';
$book->price = 199;
// Можно обращаться как к массиву
$book['author'] = 'Макс Глебов';
// Сохраняем объект
R::store($book);

Если нужно получить данные без каких-либо условий, то легче это сделать методами load() и loadAll()

// Получаем все записи, ID которых указаны в массиве ids
$ids = [1,2,3];
$books = R::loadAll('book', $ids);
foreach ($books as $book){
  echo $book->title.'<br>';
}

// Получаем одну запись по её ID
$id = 1;
$book = R::load('book', $id);
echo $book->title;

Если по каким-то причинам вам понадобится именно массив данных, то на этот случай есть метод export():

$id = 1;
$book = R::load('book', $id);
$book = $book->export();
echo $book['title'];
$id = 1;
// Загружаем объект с ID = 1
$book = R::load('book', $id);
// Обращаемся к свойству объекта и назначаем ему новое значение
$book->price = 210;
// Сохраняем объект
R::store($book);

Удалить запись с ID = 5

$id = 5;
$book = R::load('book', $id);
R::trash($book);

Удалить записи с ID = 6, 7

$ids = [6, 7];
$book = R::loadAll('book', $ids);
R::trashAll($book);

// Начиная с версии 5.1 данную задачу лучше выполнить методом R::trashBatch(). В таком случае нет необходимости создавать (получать) бин - объект RedBeanPHP
$ids = [6, 7];
R::trashBatch('book', $ids);

// Удаление записи с ID = 3
$id = 3;
R::hunt('book', 'id = ?', [$id]);

Метод R::wipe() полностью очищает указанную таблицу:

R::wipe('book');

Метод R::nuke() полностью очищает всю базу данных. Режим заморозки должен быть выключен:

R::freeze(false);
R::nuke();

Если вы не знаете идентификатор бина, вы можете искать бины, используя метод find():

$min_price = 250;
$books = R::find('book', 'price > ?', [$min_price]);

$search = 'строка';
$books = R::find('book', 'author LIKE ?', ["%$search%"]);

$id = 1;
$min_price = 300;
$books = R::find('book', 'id > :id AND price < :price', [':price' => $min_price, ':id' => $id]);

$ids = [1, 3, 5];
$books = R::find('book', 'id IN (' . R::genSlots($ids) . ')', $ids);

Если необходимо получить только одну запись, используем метод findOne():

$id = 1;
$book = R::findOne('book', 'id = ?', [$id]);

$title = 'гостья из будущего';
$book = R::findOne('book', 'title = ?', [$title]);

Если необходимо получить все данные без особых условий, используем метод findAll():

$books = R::findAll('book');

$limit = 5;
$books = R::findAll('book', 'ORDER BY id ASC LIMIT ?', [$limit]);

Данный метод предназначен для поиска по записям (однако, в нём существует проблема с биндингом):

$search_1 = 'Джон Пристли';
$search_2 = 'Сергей Тармашев';

$books = R::findLike('book',
  ['author' => [$search_1, $search_2]],
  'ORDER BY title ASC'
);

При использовании RedBeanPHP (как и любой другой ORM) не всегда можно ограничится простыми методами поиска (Finding). Часто существует необходимость сделать более сложный запрос, который сделать простыми методами крайне проблематично. Важно! Рассмотренные выше методы Finding необходимо применять, если требуется сделать простой запрос, без каких-либо сложных условий. В рассмотренных ниже примерах всегда возвращается массив данных (а не объекты-бины), поэтому это тоже является плюсом ☺

Метод exec()

Метод для произвольного SQL запроса (чаще всего применяется для добавления, изменения и удаления):

$id = 3;
$title = 'New title';

R::exec('UPDATE `book` SET `title` = :title WHERE id = :id', [
  'id' => $id,
  'title' => $title
]);

Вернёт массив данных (все записи/несколько по условию) из указанной таблицы:

//$books = R::getAll('SELECT `title` FROM `book`');
$id = 1;
$books = R::getAll('SELECT `title` FROM `book` WHERE `id` > ?', [$id]);

foreach ($books as $book){
  echo $book['title'].'<br>';
}

Вернёт все записи, но выводит только одну. Рекомендуется добавлять LIMIT 1, чтобы и запрашивалась тоже только одна запись:

$search = 'поворот';
$book = R::getRow('SELECT * FROM `book` WHERE `author` LIKE :search LIMIT 1', [
  'search' => "%$search%"    
]);

Вернёт колонку:

// Выбрать все названия всех книг
$books = R::getCol( 'SELECT `title` FROM book' );

Вернёт ячейку одной записи:

$id = 5;
$title = R::getCell('SELECT `title` FROM book WHERE `id` = ? LIMIT 1', [$id]);

Чтобы получить ассоциативный массив с указанным столбцом ключа и значения, используйте:

R::getAssoc('SELECT id, title FROM book');

Вернёт ID последней вставленной записи:

$res = R::exec("INSERT INTO book (title, author, price) VALUES (?,?,?)", ['New Book', 'New Author', 10]);
$id = R::getInsertID();

Конвертация массива записей в бины или один бин (convertToBean)

$books = R::getAll("SELECT * FROM book");
$books = R::convertToBeans('book', $books);

$book = R::getRow("SELECT * FROM book WHERE `id` = ?", [1]);
$book = R::convertToBean('book', $book);

Метод inspect() возвращает названия таблиц в БД. Если параметром передать название таблицы, то он вернёт все поля этой таблицы:

// Какие таблицы есть в БД
$tables = R::inspect();

// Какие поля есть в указанной таблице
$fields = R::inspect('book');

RedBeanPHP предлагает три простых метода для использования транзакций базы данных: begin(), commit() и rollback(). Использование:

$category = R::dispense('category');
$book = R::dispense('book');

$category->title = 'Фэнтези';

$book->title = 'Невольный брак';
$book->price = 200;
$book->author = 'Анастасия Маркова';
$book->category_id = 5;

R::begin();
try{
  R::store($category);
  R::store($book);
  R::commit();
}catch (Exception $e){
  R::rollback();
  echo $e->getMessage();
}

One-to-many (связь Один ко многим). Достанем из БД все книги, у которых category_id = 1

$category_id = 1;
$category = R::load('category', $category_id);
$books = $category->ownBookList;

// Сортировка и лимит
$books = $category->with('ORDER BY `title` ASC LIMIT 3')->ownBookList;

// Но более предпочтительным способом является метод withCondition()
$status = 1;
$limit = 3;
$books = $category
  ->withCondition('status = ? ORDER BY title ASC LIMIT ?', [$status, $limit])
  ->ownBookList;

foreach ($books as $book){
  echo $book->title.'<br>';
}

Many-to-one (связь Многие к одному). Достанет из базы название категории, с которой связана книга

$book = R::load('book', 1);
$category = $book->category->title;

Many-to-many (связь Многие ко многим). Достанет из базы (из связующей таблицы) все книги этой категории:

$category = R::load('category', 1);
$books = $category->sharedBookList;

print_r($books);

Простой подсчёт элементов:

// Сколько записей (элементов) в таблице book
$books = R::count( 'book' );

// Сколько записей (элементов) в таблице book, у которых поле status = 1
$books = R::count( 'book', 'status = ?', [1] );

Подсчёт элементов связанных таблиц:

// Сколько записей (элементов) в таблице book, связанных с категорией с ID = 1
$category = R::load('category', 1);
$numBook = $category->countOwn('book');
// Режим вывода дебагера
R::debug(1, 3);

$logs = R::getDatabaseAdapter()
  ->getDatabase()
  ->getLogger();

debug( $logs->grep('INSERT') );
debug( $logs->grep('SELECT') );

Источник

Другие статьи

SQLite
SQLite3: Транзакции с использованием PHP PDO
SQLite3: Транзакции с использованием PHP PDO

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

SQLite
SQLite3: Работа с BLOB-типом данных
SQLite3: Работа с BLOB-типом данных

В этом уроке вы узнаете, как управлять BLOB-данными в базе данных SQLite с помощью PHP PDO. BLOB обозначает бо...

SQLite
SQLite3: Получение данных из таблиц с помощью PHP PDO
SQLite3: Получение данных из таблиц с помощью PHP PDO

В этом уроке показано, как можно различными способами запрашивать данные из таблицы SQLite с помощью PHP PDO....