RedBeanPHP — еще одна ORM библиотека

    RedBeanPHP logo
    На хабре нашел пару упоминаний про эту ORM, да и то давно и в комментариях. Недавно обнаружил, что вышла уже вторая версия. Желающим — вот ссылка на загрузку (GitHub) и на документацию
    Цель этой статьи — кратко познакомить читателей с этой ORM-библиотекой.
    RedBeanPHP — еще одна ORM-библиотека. Основное ее отличие от коллег, типа Propel или Doctrine, в отсутствии необходимости ручного конфигурирования объектов. Т.е. никаких xml, yml или ini-файлов. RedBenPHP на лету создает таблицы, поля и индексы. Любой объект можно связать с другим. Из БД поддерживаются MySQL, SQLite и Postgres.

    ТТХ


    Состоит библиотека из одного файла. Написана она под версию php 5.3, но по заявлению автора, должна работать и под 5.2. Для работы необходимо расширение PDO.

    Основы работы


    RedBeanPHP работает с bean'ами. Для начала вы можете просто создать bean. Это объект с публичными свойствами и типом. Тип bean'а используется для сопоставления таблице в БД и, опционально, для указания вашего класса. Bean создается таким образом:
    $book = R::dispense( 'book' );
    

    Теперь у нас есть пустой bean типа book. Зададим ему пару свойств:
    $book->title = 'Boost development with RedBeanPHP';
    $book->author = 'Charles Xavier';
    

    И сохраним в БД:
    $id = R::store($book);
    

    Теперь все данные сохранены в БД. У нашего bena'а сейчас есть два свойства, в которые мы записали строковые данные, поэтому RedBeanPHP выбрал тип VARCHAR(255) для этих свойств. Если бы мы решили сохранить число в одном из свойств ($book->price = 100), то RedBeanPHP выбрал бы тип TINYINT(3) для хранения этого свойства. Если потом нам надо будет сохранить дробную цену, то RedBeanPHP на лету поменяет тип поля в БД.
    Для загрузки из БД используется метод R::load()
    $book = R::load('book', $id);
    $books = R::batch('book',array($id1,$id2));
    

    Удаление из БД делается так:
    // одна запись
    R::trash( $book );
    // все записи
    R::wipe( 'book' );
    


    Поиск bean'ов


    Для поиска используется метод R::find()
    $needles = R::find('needle',' haystack = ?', array( $haystack ));
    

    find() принимает три аргумента: тип bean'а, SQL-запрос и массив значений, которые будут подставлены вместо знаков вопросов во втором аргументе. Вместо знаков вопроса можно использовать именованные параметры:
    $needles = R::find('needle',' haystack = :haystack
    ORDER BY :sortorder',
    array( 'sortorder'=>$sortorder, ':haystack'=>$haystack ));
    

    В RedBeanPHP можно писать обычные SQL-запросы, создавать и использовать представления и тегировать сущности.

    Связи в RedBeanPHP


    Свойства объектов могут сами быть объектами. RedBeanPHP позволяет сохранять связанные объекты:
    $farm = R::dispense('building');
    $village = R::dispense('village');
    $farm->name = 'farm';
    $village->name = 'Dusty Mountains';
    $farm->village = $village; //assign farm to village
    $id = R::store($farm);
    

    и загружать их
    $farm = R::load('building',$id);
    echo $farm->village->name; //prints 'Dusty Mountains'
    

    Связывать можно и сразу несколько bean'ов:
    list($mill,$tavern) = R::dispense('building',2);
    $village->ownBuilding = array($mill,$tavern);
    

    Если вы сохраните $village и снова загрузите из БД, то в свойстве ownBuilding обнаружите связанные bean'ы. Имя свойства должно совпадать с хранимыми в нём bean'ами. Для удаления связи используется unset(). Связанные bean'ы можно изменять прямо из родительского объекта:
    $village->ownBuilding[1]->name = 'The Old Inn';
    

    Для доступа к хранимым bean'ам в качестве ключа массива необходимо использовать ID хранимых в нем bean'ов.

    Прочее


    По умолчанию RedBeanPHP работает в свободном режиме, в котором схема БД меняется в зависимости от кода, который с ней работает. Этот режим отлично подходит для разработки. В это время вам не надо заботиться о БД. После окончания разработки нужно выполнить команду freeze().
    R::freeze( true ); //will freeze redbeanphp
    

    Эта команда отключит в RedBeanPHP проверку схемы данных, что увеличит скорость работы.
    Еще, на мой взгляд, полезная вещь — это импорт bean'ов из массивов по ключам, например:
    $book->import($_POST);
    $book->import($_POST, 'title,subtitle,summary,price');
    

    Но валидации при этом не происходит.

    Почитать


    Эта статья по сути — вольный перевод нескольких разделов мануала по RedBeanPHP.
    В мануале еще раскрываются темы по организации связей много-ко-многих, деревьев, созданию моделей и валидации, написанию плагинов для RedBeanPHP и интеграции с фреймворками.
    Поделиться публикацией

    Похожие публикации

    Комментарии 33

      0
      Спасибо за статью.
      Несколько вопросов:
      #1 Насколько вменяемый получается результирующий SQL (кстати, можно ли его как-то увидеть в отладочном режиме)?
      #2 Есть ли возможность декларативного задания отношения между сущностями (ассоциация, агрегация)?
      #3 Как обстоят дела с управлением транзакциями?
        0
        #1 есть режим отладки, включается R::debug(true);
        #2 насколько я понял, тут только между готовыми объектами можно задавать отношения. Или я ваш вопрос не понял.
        #3 Про транзакции нашел только в wiki
        +1
        Я так понимаю эта ORM нужна для ознакомления с Active Record, ибо для продакшена она не годится :)
          +2
          Насколько я понимаю, тут не Active Record (у объектов нет метода save() — их сохраняет другой объект). А продакшен — смотря какой продакшен. Я использовал первую версию в небольшой задачке, где пользователь заполнял довольно длинную форму и надо было все данные хранить в БД, чтобы потом пользователь мог продолжить заполнение или получить еще раз результат обработки своих данных. Там, как мне кажется, RedBeanPHP замечательно вписался с его import($_POST)
            +4
            Ну что-то вроде import($_POST) есть если не у всех ORM, то у многих :)
            К примеру (Yii): $model->attributes = $_POST;

            Хотя по поводу AR Вы все же правы, это больше похоже на DAO :)
              0
              А Yii разве не сломается при добавлении нового инпута? Имею в виду ошибку mysql field not found.
          0
          Подойдет для проектов на скорую руку.
            +1
            для быстреньких штук самое оно, в закладки :)
              +2
              Не люблю ORM, но в этом что-то есть… Спасибо
                +12
                Прошлой весной ковырял RedBean долго и упорно. Идея тотальной простоты и работоспособности из коробки очень понравилась, но поверх этой идеи оказалось накручено много мути.

                Например, работа с ассоциациями мне сразу показалась подозрительной. С версии 1.3 до 2.0 все поменялось, но что тогда что сейчас все ассоциации выражены через many-to-many, что (на мой взгляд) чудовищно. Автор же считеат это преимуществом: мол вы можете ассоциировать что угодно с чем угодно. В версии 2.0 появились две странные фичи (nested beans и on-the-fly views) для тех, кому не нравилось, что любая ассоциация требует junction table.

                То есть с одной стороны имеем тривиальный active record, и используем old good SQL (в старой доке была фраза «Some tools even promote their own version of SQL. To me this sounds incredibly stupid. Why should you use a system less powerful than the existing one? This is the reason that RedBean simply uses SQL as its search API.») С другой стороны, чтобы связать Product с Category приходится поступать куда более «incredibly stupid».

                Для добавления логики к моделям используется нечто под названием «fuse» (данные и логика живут отдельно). На первый взгляд приколько, но на второй понимаешь, что от этого только проблемы (теряется инкапсуляция; тихо игнорируется вызов несуществующего метода...)

                Напрягает наличие в базовой поставке каких-то экзотических вещей вроде Cooker и BeanCan Server.

                RedBean может глотать исключения там, где этого делать не надо: tinyurl.com/c3yanmp
                И один раз мне пришлось долго убеждать автора в том, что нельзя считать ноль и пустую строку эквивалентными данными: tinyurl.com/d6d3m8v

                В целом у меня возникло ощущение, что RedBean — это полигон, на котором автор пробует всякие прикольные идеи, но большого доверия качество исполнения во мне не вызвало. Возможно, дело в том, что автор голландец и курит перед написанием кода…

                Однако RedBean меня вдохновил, и я попытался сконцентрировать понравившиеся мне идеи в моем собственном проекте, который назвал orange-bean. Кому интересно, вот ссылка: code.google.com/p/orange-bean/
                  +1
                  Хотел поближе посмотреть на orange-bean…
                  А в чем смысл компресии вашего класса через php-compressor?
                  я думаю многие были бы благодарны, если исходник сразу был бы в удобно-читаемом виде.
                    0
                    Исходники не прячу: code.google.com/p/orange-bean/source/browse/#svn%2Ftrunk
                    Смысл — просто обкатываю компрессор (он тоже мой) на этом проекте.
                      0
                      зачем вам обфускация? если нужно сжать в один файл — используйте phar с autoload
                    0
                    Круто, но почему бы не следовать зендовым стандартам? framework.zend.com/manual/ru/coding-standard.coding-style.html.
                      0
                      Вариант, что автор, как и я, не любит когда открывающая { расположена на новой строке, вас устраивает? :)
                        +1
                        Прошу принять во внимание, что это правило применимо только для классов и методов. Во всех остальных случаях { располагается на той же строке.
                          +1
                          Для меня решающим при выборе того или иного стандарта является его распространенность и не более.
                            0
                            Для меня нет — если себя, то максимально приближенное к java code conventions, если существующий код, то по принятым в нём стандартам.
                              0
                              На самом деле мне режет глаз то, что не camelCase…
                    0
                    Вот бы еще были какие-то бенчмарки и сравнение с другими ORM
                      0
                      А ни у кого нет случайно списка PHP ORM, которые реализуют любой шаблон кроме ActiveRecord?
                      (приелось и хочется чего то более экзотического)
                        0
                        За что минусуют? ActiveRecord не всегда удобно использовать да и кроме него есть еще несколько более сложных, но и более удобных шаблонов (data access object, table data gateway, row data gateway, data mapper и т.д.). Было бы интересно увидеть их реализацию.
                          0
                          Подозреваю что минусуют за то, что в данном топике не ActiveRecord =)
                            0
                            Хм, как не подумал о этом. Вопрос был задан безотносительно данного топика (собственно, этот топик на данный момент единственное место где могу задать подобный вопрос :().
                          0
                          Doctrine2 — DataMapper + ещё куча паттернов. Лично мне кажется самым удобным, т. к. классы и модели объектов самые обычные PHP-классы, никак не привязанные ни то что к схеме БД, но даже к системе хранения в целом.
                          0
                          Если бы мы решили сохранить число в одном из свойств ($book->price = 100), то RedBeanPHP выбрал бы тип TINYINT(3) для хранения этого свойства. Если потом нам надо будет сохранить дробную цену, то RedBeanPHP на лету поменяет тип поля в БД.
                          Отсюда сразу следует, что это только для небольших игрушек. Где-нибудь не досмотрит программист, пропустит float и этот ОРМ начнёт шуршать таблицей, блокируя туда запись, перестраивая индекс, если таблица большая, это может повесить всё на минуты, а то и десятки минут.
                            0
                            Там есть режим блокировки изменений в схеме данных. Отключается одной командой, после этого ОРМ схему днных не трогает.
                              0
                              Спасибо. А как-то можно указать, что мне для текстовых данных мало varchar(255)?
                                0
                                Этого нельзя. Подразумевается, что после freeze вы внимательно посмотрите получившуюся схему и «расширите» типы колонок там, где получилось «мало»:
                                www.redbeanphp.com/manual/freeze
                                  0
                                  Я так понял, что bolk интересуется про тип поля до freeze(). В режиме fluid, я так думаю, RedBeanPHP должен уметь сохранять длинные текстовые данные.
                                    0
                                    Он умеет. Но для того чтобы тип колонки стал TEXT, надо хотя бы раз сохранить длинную строку, а этого в процессе разработки может и не произойти.
                            0
                            А еще есть замечательная библиотека IdiORM
                            Мини- ORM, состоящий из одного файла. Очень рекомендую.
                            • НЛО прилетело и опубликовало эту надпись здесь

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое