Пишем на SQL без SQL: основы по RedBean PHP

Пишем на SQL без SQL: основы по RedBean PHP
PHP скрипты 0    66818 +2

Что такое ORM, в частности RedBean PHP и какие у неё требования?

RedBeanPHP был создан для значительного облегчения жизни программистов в процессе работы с базами данных. RedBeanPHP требует версию PHP >= 5.3.4. Под капотом используется драйвер PDO, поэтому защита от SQL- инъекций при правильном применении гарантированна. К поддерживаемым СУБД RedBeanPHP относятся MySQL, MariaDB, PostgreSQL, SQLite, CUBRID.

ORM это способ задания связи объектов и РСУБД. Всего есть 2 модели ORM-систем: Data Mapper и Active Record. Так вот RedBeanPHP это Data Mapper и каждый объект записи здесь называется бином. Эти бины можно воспринимать как самые обычные объекты, свойства которых представляют собой записи в Ваших таблицах. То есть одна запись это один бин, а его свойства это поля Вашей записи. Работать с бином можно точно также как с обычным массивом.

Как подключить RedBean PHP

Скачать библиотеку RedBeanPHP можно на официальном сайте.

Подключить библиотеку можно через функцию require:

require 'libs/rb.php';

Как подключиться к базе данных посредством RedBean PHP?

Для подключения к базе данных в RedBeanPHP есть статичный метод setup, который принимает 4 опциональных аргумента. Опциональными они являются, потому что Вы можете никакой аргумент не задать и тогда RedBeanPHP создаст временную базу данных в формате SQLite в Вашей временной директории. Вызывается метод setup для MySQL следующим образом:

R::setup( 'mysql:host=127.0.0.1;dbname=redbean','login', 'password' ); 

if ( !R::testConnection() )
{
		exit ('Нет соединения с базой данных');
}

Метод testConnection проверяет есть ли у нас фактическое подключение к базе.

Подробнее о подключении к базам данных можно прочесть в разделе Connection.

Как закрыть соединение с базой данных?

Закрыть соединение с базой данных Вы можете при помощи метода close. Вызывается он вот так:

R::close(); 

Как выполнить произвольный запрос к базе данных?

Какой в RedBeanPHP есть аналог функции mysqli_query? Этим аналогом является метод exec. У него всего 2 аргумента: sql и bindings. Бинды (bindings) – это специальная техника подготовленных запросов, при помощи которых можно обезопасить себя от SQL-инъекций. Также бинды увеличивают производительность при частых запросах. Вызывается метод exec следующим образом:

Пример #1

Вторым элементом мы передаем массив с данными, которые будут подставлены вместо знака ? (плэйсхолдер). В данном случае это id.

$id = $_POST['id'];
R::exec('DELETE FROM `users` WHERE `id` = ?', array(
    $id
));

Пример #2

Плэйсхолдеров может быть много. В этом случае в качестве первого знака ? будет вставлена первая ячейка массива, то есть цифра 32. В качества второго ? слева на право будет вставлена цифра 51. В качестве последнего ? будет вставлена цифра 73.

R::exec('DELETE FROM `users` WHERE `id` = ? OR `id` = ? OR `id` = ?', array(
    32,
    51,
    73
));

Пример #3

Если Вы уже работали с PDO, то возможно будет привычней использовать следующий подход:

$id = $_POST['id'];
R::exec('DELETE FROM `users` WHERE `id` = :id', array(
    ':id' => $id
));

Пример #4

R::exec( 'UPDATE `page` SET `title`="test" WHERE `id` = 1' );

4 операции CRUD (Create, Read, Update, Delete)

1. Как создавать данные (Create)

Метод dispense принимает всего 1 аргумент – название таблицы. RedBeanPHP умеет создавать таблицы налету. Достаточно вызвать dispense и указать какие поля будут у таблицы. После этого мы вызываем метод store и передаем в него бин user.

Пример #1

$user = R::dispense('users'); //передаем название таблицы users

//поле id можно не создавать, так как RedBeanPHP автоматически его создает с автоинкрементом
$user->login = $data['login'];
$user->email = $data['email'];

R::store($user); // сохраняем объект $user в таблице 

Пример #2

$user = R::dispense('users');

$user->name = 'Alex';
$user->age = 35;

R::store($user);

2. Как получать данные (Read/чтение)

Для чтения данных есть множество методов, например, метод load. Первым параметром мы передаем имя таблицы, из которой мы хотим прочесть данные. Второй параметр – id записи, которую мы хотим получить. С полученными данными мы можем работать, как с объектом или массивом.

$cat = R::load('category', 2);
echo $cat->title; // работаем с данными, как с объектом
echo $cat['title']; // работаем с данными, как с массивом

3. Как изменять данные (update)

Чтобы изменить запись в БД её нужно:
1 - получить в виде объекта;
2 – написать новое значение;
3 – сохранить через метод store.

$cat = R::load('category', 2);
$cat->title = "Новое значение"; 
R::store($cat);

echo $cat->title; // выводим наше новое значение

4. Как удалять данные/записи (delete)

Чтобы удалить запись из БД мы её должны:
1 - получить в виде объекта;
2 – использовать метод trash, который удалит одну запись. Есть ещё метод trashAll, который может удалить сразу несколько объектов.

$cat = R::load('category', 2);
R::trash($cat); //удаляем запись с id=2 из таблицы category

Как полностью очистить таблицу

R::wipe('category'); // удаляем все записи из таблицы category

Режим заморозки

Режим заморозки в RedBeanPHP нужен для того, чтобы включить или выключить поведение автоматического создания и изменения таблиц в БД. Сервер сильно нагружается, поэтому, когда Вы разрабатываете сайт, то режим заморозки можно выключить (false). Тогда автоматическое создание таблиц будет работать. Когда Вы зальете готовый сайт на хостинг, то нужно поставить режим заморозки в значение true.

R::setup(); // тут подключение к БД
R::freeze( true ); // тут выключение режима заморозки


Видеоучебник по RedBeanPHP

Статья была написана на основе видеоуроков Хауди Хо, который Вы можете посмотреть ниже.

Таймкоды:

2:00 Проверяем/Меняем версию PHP
6:10 Качаем/Подключаем RedBeanPHP
8:40 Подключаемся к базе данных R::setup()
9:50 В чём разница между utf8_general_ci и utf8mb4_general_ci
11:45 Почему нужно прописывать IP в качестве хоста базы данных

14:45 Закрытие соединения с базой данных R::close()
15:10 Проверяем соединение с базой данных R::testConnection()
16:00 Выполняем произвольный SQL код R::exec()
20:20 Что такое CRUD
21:00 Создание записей R::dispense()
27:50 О режиме заморозки R::freeze()

30:45 Конвенция именования таблиц
32:20 Пишем обход конвенций именования таблиц R::ext()
34:00 Конвенция именования свойств бина
34:40 Конвенция автосоздания индексов

37:20 Загружаем записи R::load()
41:00 Загружаем сразу несколько записей R::loadAll()
42:30 Поиск записей R::find()
44:20 Генерируем бинд слоты R::genSlots()
46:40 Ищем только одну запись R::findOne()
47:25 Загружаем все записи сразу R::findAll()
48:10 Итерация по всем записям R::findCollection()
49:40 Ищем записи по значениям R::findLike()
51:30 Загружаем запись если есть, создаем и загружаем если нет R::findOrCreate()
53:15 Считаем количество записей R::count()

54:35 Обновляем данные в записях
59:00 Удаляем записи из таблиц
1:00:18 Вайпаем данные таблиц (очищаем таблицы) R::wipe()


Таймкоды:

1:33 Почему нельзя копировать вообще весь код из урока
2:45 Метод R::getAll()
6:09 Метод R::getRow()
10:45 Метод R::getCol()
15:00 Методы R::convertToBean() и R::convertToBeans(), перекидываем массивы в бины
16:44 Метод R::getInsertID()

19:42 Что такое отношения вообще?
23:45 Отношения One-to-Many (1:M)
40:06 Отношения Many-to-One (M:1)
44:35 Отношения One-to-X (One-to-Fixed)
53:30 Отношения Many-to-Many (M2M)

57:40 Сортировка отношений
59:55 Фильтрация отношений
1:02:55 Добавляем отношения без их подгрузки
1:04:30 Подсчёт отношений/связей


Ещё один урок, но уже от другого человека.


Поделиться с друзьями


Похожие статьи:

Парсер на PHP с записью контента в БД
Разрабатываем exploit
Парсер курсов валют на PHP
Удобная форма обратной связи без перезагрузки страницы
Счетчик онлайн посетителей на сайте
Защищенная Авторизация и Регистрация на PHP + MySQL через PDO
Универсальный и очень простой PHP парсер

Комментарии ()

  1. Влад Климов 26 мая 2018, 22:04 # 0
    Здравствуйте, столкнулся с проблемой, что у объекта который я пытаюсь сохранить слетает русская кодировка и выводится просто код клавиш (\u0414\u043c\u0438\u0442\u0440\u0438\u0439), а если вывожу по отдельности каждый элемент поля то выводит все как надо. В чем может быть проблема? Код брал по примеру, просто значения ввел русскими буквами. (с выводом из бд русским языком проблемы не возникло)
    1. Алексей Власов 27 мая 2018, 13:16 # 0
      я когда с кодировками балуюсь, то обычно помогает:

      — указать кодировку при подключении к базе
      — проверить кодировку файла
      — указать кодировку в htaccess
      — указать кодировку в скрипте

      а под конец еще и iconv все кодировать
    2. Kill Mania 22 сентября 2018, 14:44 # 0
      Здравствуйте, Алексей.
      Запутался я в корень… Поставил себе задачу, что из таблицы «clients» мне нужно получить все поля «name», которые там есть и внести из значения в веб-таблицу. При условии, что ID записей и их количество в базе данных я не знаю.
      Такой вариант мне не подходит, так как здесь нужно выбрать определенные значения ID:
      $cllients = R::load('clients', 2); echo $clients->name;
      Я решил попробовать вариант такой:
      $clients = R::findAll('clients'); print_r ($clients);
      Но так я вывел массив.
      Мне кажется, что можно как-то решить мою проблему с помощью loadAll. Но в таком случае я не могу понять, как обозначить тот факт, что id неизвестны. Например, в видео у Хауди Хо id именно перечисляются. А мое условие в том, что я не знаю, сколько записей, сколько id, но хочу получить все name.
      Может быть сможете подсказать, в какую сторону надо смотреть?
      1. Kill Mania 22 сентября 2018, 15:06 # 0
        Вывел с помощью findAll и foreach в итоге))
        $clients = R::findAll('client'); foreach ($clients as $client) { echo $client['name']; }
        1. Kill Mania 22 сентября 2018, 20:00 # 0
          А теперь я точно в патовой ситуации))

          В общем, сделал я с помощью findAll и foreach выборку нужных мне значений в веб-таблицу. И возле каждой строки этой таблицы я сделал ссылку на редактирование оной, вида href="edit.php?id=<?php echo $clients['id']; ?>"

          По моим представлениям, это должна быть страница, на которой выводятся все остальные данные из таблицы «clients» (которые не вошли в веб-таблицу), и это должна быть также страницей редактирования (формы там всякие и так далее).

          И вот, в чем загвоздка: я не понимаю, как по умолчанию при переходе на эту страницу объяснить базе данных, что сюда нужно выгружать данные только из определенного id таблицы. То есть вот я перешел по ссылке edit.php?id=6, значит тут все должно быть связано только с id=6 и никак иначе. А у меня там либо выгрузка со всех id, либо с определенного, но которое я указываю вручную((

          А я хочу как-то так:
          $clients = R::load('clients',id=тот_же_что_и_в_url); echo $clients['name']; //имя нужного клиента echo $clients['balance']; //баланс клиента и так далееНо никак — тупик…
          1. Kill Mania 22 сентября 2018, 20:03 # 0
            Самое печальное, что как это все сделать стандартными запросами, вида mysql_query я знаю. Но, как вычитал, это не безопасно. Поэтому решил познать этот redbeanphp, но похоже, что вместо обучения php, только себя еще больше запутал…
            1. Kill Mania 22 сентября 2018, 20:17 # 0
              Смастерил вот такую конструкцию:
              $id = $_GET['id']; $clients = R::load('clients',$id);

              Но на сколько это правильно в плане безопасности?

              З.Ы.: я очень извиняюсь, что просто заполонил собой комменты, но почему-то как сюда напишу с вопросом, сразу какие-то решения приходят в голову))) Хотя до этого по несколько часов мог голову ломать.
              1. Алексей Власов 23 сентября 2018, 11:35 # 0
                Здравствуйте, Kill Mania!

                Я так понимаю, — всё получилось?

                Данная конструкция выглядит безопасно, на мой скромный взгляд. Собственно используя RedBean PHP можно сильно не переживать о безопасности, данная библиотека самостоятельно обрабатывает переменные. Поэтому она такая удобная. Главное всё делать, как в документации.

                Я бы ещё на всякий случай (int) поставил.

                Вот так: $id = (int) $_GET['id']; $clients = R::load('clients',$id);

                Если писать комменты помогает, то отлично! Единственное, что я из-за работы могу ответить не сразу, а через 1-2 дня. А решения всегда так, не сразу приходят, приходится поломать голову какое-то время.
                1. Kill Mania 23 сентября 2018, 14:16 # 0
                  Доброго времени суток, Алексей!

                  Спасибо большое, добавил еще и (int) — лишним не будет точно))

                  Да, все получилось. Я для себя осознал одно (в свои уже 33 года!) — не зря в школе учителя говорили, что математика пригодится! Самое сложное в программировании (по крайней мере для меня), как я для себя понял, это выстроить нужный алгоритм действий, как оно все должно работать и взаимодействовать, логика. А вот когда это все в голове выстраивается, то написать код худо-бедно уже не так сложно. А в выстраивании алгоритмов очень бы пригодилась математика, так как там все это развивается на «ура»))

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

                  И по итогу оказывается, что мои тормоза заключаются именно в слабом понимании логики построения кода и получения данных (почему именно так, а не иначе; откуда взять те или иные данные, чтобы работать с ними; откуда взять нужные значения; почему нужно это прописать именно тут, а не там), отсюда и тупик. Но как только я все это осознаю, то написать сам код уже не проблема. Благо, что много мануалов и таких замечательных блогов, как Ваш, Алексей, где все очень подробно разжевывается.

                  Ну, и еще я понял, что надо учить параллельно английский — столько мануалов есть на нем…

                  Знал бы я, что мне в 33 года приспичит написать достаточно сложное веб-приложение и это меня так увлечет, выбор будущей специальности был бы однозначен. А так, гуманитарий я)))

                  Ох, опять многобукв… Простите))

                  В общем, спасибо большое Вам за подсказки, помощь и за отличный блог!)

                  Не прощаюсь!)))

                  З.Ы.: Прекрасно понимаю, что быстро отвечать Вы не можете — все же есть масса нужных дел, помимо этого. Но я, когда задаю вопрос, всегда уверен, что завис на нем надолго, поэтому готов ждать ответа столько, сколько нужно)) Просто почему-то пока получается так, что перечитав я понимаю — вот же он ответ, на самой поверхности!
      2. Александр Петров 30 сентября 2018, 20:54 # 0
        Подскажите, пожалуйста, как узнать последний id в базе?
        Указанный метод в видео добавляет новую запись в бд. Можно узнать как-то без добавления?
        Спасибо
        1. Андрей Карманов 07 марта 2019, 13:34 # 0
          Доброго!
          Прошу помощи! Не могу понять, в чем моя ошибка?

          Таблица такая: yadi.sk/i/-891uZ4ynTUzDw yadi.sk/i/EGEU2Z3b1XpFcg
          Делаю запрос по старинке и при помощи RedBeanPHP — два разных результата. почему ReBeanPHP отдает только один пин?
          <?php
          require_once 'sys/db.php';

          function dump($what)
          {echo '
          ';print_r($what);echo '
          ';}

          $db1 = mysqli_connect('localhost', 'test', 'root', '');
          mysqli_set_charset($db1, 'utf8');
          $q1 = $db1->query(«SELECT * FROM `pins` WHERE `direction` = 'output' ORDER BY `pin` ASC»);
          dump($q1);

          $db = R::findAll('pins', 'direction = ?', [«output»]);
          dump($db);

          ?>

          Возврат:

          1. mysqli_result Object
          (
          [current_field] => 0
          [field_count] => 4
          [lengths] =>
          [num_rows] => 7
          [type] => 0
          )

          2. Array
          (
          [] => RedBeanPHP\OODBBean Object
          (
          [properties:protected] => Array
          (
          [pin] => 26
          [name] => Предпоследний
          [direction] => output
          [status] => 1
          )

          [__info:protected] => Array
          (
          [type] => pins
          [sys.id] => id
          [sys.orig] => Array
          (
          [pin] => 26
          [name] => Предпоследний
          [direction] => output
          [status] => 1
          )

          [tainted] =>
          [changed] =>
          )

          [beanHelper:protected] => RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper Object
          (
          )

          [fetchType:protected] =>
          [withSql:protected] =>
          [withParams:protected] => Array
          (
          )

          [aliasName:protected] =>
          [via:protected] =>
          [noLoad:protected] =>
          [all:protected] =>
          )

          )
          1. Алексей Власов 07 марта 2019, 21:44 # 0
            Здравствуйте!

            Меня смущает вот это:

            $db1 = mysqli_connect('localhost', 'test', 'root', '');

            Для соединения с БД в RedBeanPHP используется метод setup. И работая с RedBeanPHP любые mysqli функции не используются.

            Либо RedBeanPHP, либо mysqli, но не одновременно.
            1. Андрей Карманов 08 марта 2019, 08:05 # 0
              На самом деле оба варианта работают сразу. В начала файла есть вызов 'sys/db.php', в котором прописано подключение к безе: require_once 'libs/rb.php';
              R::setup( 'mysql:host=127.0.0.1;dbname=test','root', '' );

              Вопрос в другом, почему в таблице 27 записей, а редбин возвращает только одну, даже если сделать запрос всех записей: $db = R::find('pins'); => возвращает только одну запись(последнюю)
          2. Рулинский Владислав 01 августа 2019, 09:45 # 0
            После подключения rb.php, делаю header(«Location...»)
            Пишет, что ReadBean уже отправил заголовки.
            Вызывался только метод setup().
            Есть ли решение данной проблемы?
            1. Дмитрий Луговской 01 сентября 2020, 10:27 # 0
              Все замечательно, но в обычных функция mysql при неудачной обработке запроса всегда можно вывести сообщение об ошибке exit(mysql_error()), а как быть с Readbeen?
              1. Андрей Голуб 13 декабря 2022, 23:42 # 0
                Здравствуйте!

                Подскажите, пожалуйста, по возможности.
                Использую метод dispense для добавления данных.
                Запрос имеет следующий вид:

                $user = R::dispense('users_list'); $user->login = $data['login']; $user->email = $data['email']; $result = R::store($user);Но при выполнении запроса получаю исключение:
                Invalid type: users_list

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

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

                Вы можете авторизоваться на сайте через:
                YandexVkontakte
                Требуется программист