ORM layer that creates models, config and database on the fly

Last update: May 17, 2022

RedBeanPHP 5

Build Status

RedBeanPHP is an easy to use ORM tool for PHP.

  • Automatically creates tables and columns as you go
  • No configuration, just fire and forget
  • No complicated package tools, no autoloaders, just ONE file

Installation (recommended)

Download RedBeanPHP from the website:

https://redbeanphp.com/download

Extract the archive and put it in your PHP project, voila!

Optional: sha256sum and check signature.

Installation via Composer (not recommended)

Just open your composer.json file and add the package name (e.g. "gabordemooij/redbean": "dev-master") in your require list.

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

NOTE: You will find many examples on the RedBean website make use of RedBean's R class. Because of namespaced autoloading in Composer, this class will be available as \RedbeanPHP\R instead of R. If you desire to use the much shorter R alias, you can add a use statement at the beginning of your code:

use \RedBeanPHP\R as R;

NOTE: It is important to note that when using RedBeanPHP with Composer, there are some extra precautions needed when working with Models. Due to the namespace requirements of Composer, when creating Models we need to use the SimpleModel to extend, not RedBean_SimpleModel. Furthermore, we need to specify the namespace of the SimpleModel, so a full example of using a Model with RedBean with Composer is as follows:

use \RedBeanPHP\R;

class Model_User extends \RedBeanPHP\SimpleModel
{
    ...
}

Notice that we also need to add the use \RedBeanPHP\R statement so that we can use the R:: shortcut within the Model.

Quick Example

How we store a book object with RedBeanPHP:

$book = R::dispense("book");
$book->author = "Santa Claus";
$book->title = "Secrets of Christmas";
$id = R::store( $book );

Yep, it's that simple.

More information

For more information about RedBeanPHP please consult the RedBeanPHP website:

https://www.redbeanphp.com/

GitHub

https://github.com/gabordemooij/redbean
Comments
  • 1. Is it possible to escape a colon in a bound parameters, to prevent it from being treated as a bound parameter?

    In the screenshot, i'm using Regular expression to search in a table that contains some json. problem is, when adding a bound parameter to the query, it treats the json seperator : as the start of a new named parameter. is there a work around for this?

    Fig1: Query is valid img Fig2: Redbean seems to be treating the colon in the REGEXP as a bound parameter img2

    Reviewed by r3wt at 2015-03-30 17:22
  • 2. Proposition for a new SQLHelper

    Intent

    This issue intends to discuss a PROPOSITION to add a new SQLHelper to redbean: I was looking at this post on redbean forum and noticed a promising idea from @daviddeutsch called Rx:

    R::$x->project->name('project x')->code(200)->find();
    

    Usage

    Using SQL operators (=, >, <, <>, LIKE, BETWEEN, IN, etc):

    $R::
        $x->project
            ->name('like', '%project x')
            ->priority('>', 5)
            ->created_at('between', [$time1, $time2])
            ->find();
    

    And possibility to group SQL conditions:

    R::$x->project
        ->name('like', '%secret%')->AND->priority('>', 9)
        ->OR
        ->OPEN
            ->code('in', [007, 51])->AND->created_at('between', [$time1, $time2])
        ->CLOSE
        ->find()
    

    Sane defaults:

    Default SQL operator is = and default SQL construct between conditions is AND, so Rx original syntax would still be allowed :)

    R::$x->project->name('project x')->code(200)->find();
    

    I know redbean philosophy about query writers, but this does not looks like over engineering IMMO and would be a great addition. Maybe I could implement this feature, but need some feedback to improve the idea.

    @gabordemooij What do you think?

    cheers!

    Reviewed by marcioAlmada at 2013-11-07 13:52
  • 3. Let's talk about Instantiation

    Limitations of the monolithic Facade

    Sorry if this is a broad topic, but during my current downtime to develop some stuff, I ran into serious restrictions with RedBean, came to a number of conclusions and would love to discuss them with other users.

    I have two major use cases right now:

    Deploying RedBean across domains

    The Problem

    The monolithic Facade works well if you're developing a monolithic app. Meaning: a single database in a single domain (speaking in DDD terms). What I ran into was that I have multiple interdependent and interacting domains.

    I have one app - hotbox (a package creator similar to the packaging part composer) - that creates a main database for cross-project information and a further database for each project, all of which have their own logging and so forth. Then I use hotbox in a client-facing server app, mangrove-server which also has its own tables, including logging and so forth.

    I do not want to have both apps speak to the same database because that would mean that I have to either use prefixes or implement tons of namespacing within my tables. Also - when I kill a project in hotbox, I can get rid of the database instead of expensive sorting-out operations.

    First, cumbersome solution

    What I did initially was to use a single instance of RedBean and implement a database switcher. That only gets you so far, though, because you end up switching databases a lot. The bandaid that I used was that the only way that applications talk to eachother was through an API facade with static methods like so:

    
    public static function registerPackage( $package, $branch )
    {
        $current_db = R::$currentDB;
    
        R::selectDatabase(self::$config->database->name);
    
        // Business Logic goes here
    
        R::selectDatabase($current_db);
    
        return true;
    }
    
    

    But this only solves matters across applications (and it's highly debatable how elegant the solution is), not within an application.

    Current Solution

    What I needed here was instances, plain and simple. So I'm currently writing daviddeutsch/redbean-instance to make that happen. Right now, it's a facade wrapper that registers a facade as an instance and implement a __call() function that relays method calls to static method calls (more below under 'downsides').

    Also note that I wrote further rb plugins and in those plugins, I had to inject a facade parameter to the plugin static method, like so:

    public static function prefix( $prefix, $facade=null )
    {
        if ( is_null($facade) ) {
            $class = get_class(R::$writer);
        } else {
            $class = get_class($facade::$writer);
        }
    

    That's the only way I can ensure that I end up modifying the correct facade - again a restriction of a monolithic facade to begin with.

    Downsides of the current approach

    I had to write a translation function from static to regular method calls since:

    $r2db2 = R::instance();
    
    // Works
    $project = $r2db2::dispense('project');
    
    // --- MyApp.php ---
    
    MyApp::deploy();
    
    class MyApp
    {
        public static $db;
    
        public static function deploy()
        {
            self::$db = R::instance();
        }
    }
    
    // --- MyProject.php ---
    class MyProject
    {
        public function stuff()
        {
            // Nope.
            $user = MyApp::$db::dispense('user');
    
            // Yup, but: eww.
            $user = MyApp::$db->dispense('user');
    
            // Also completely breaks Rx:
            $user = MyApp::$db::_('user'); // Nope again
    
            // I can make _() work, but again, eww:
            $user = MyApp::$db->_('user');
    
            // FindHelper is broken though, with no recovery:
            $user = MyApp::$db::$r->user->one()->find(); // *shudders
        }
    
    }
    

    So, the bottom line is: This makes Facade calls mad uglies.

    Of course, I can (and probably will have to) convert the $x static in Rx to a property, but I'm jumping through hoop after hoop. Will have to rethink the Rx design.

    Likely new approach

    It appears, though, that I will have to copy most of the facade into a new class that emulates most of the behavior of the Facade (see below for further discussions on the concept of the facade).

    This also solves the other problem I currently have deploying RedBean with clients is that I'm still running into some with PHP 5.2. So for them, __callStatic() isn't an option anyhow, killing plugins.

    Deploying RedBean in a CMS context

    The Problem

    Usually, a CMS context means a single database, so that's all fine and dandy. But you also have lots of prefixes - one for the cms itself and one for the component that you're working on.

    Current Solution

    Right now, I have written to get around this with the daviddeutsch/redbean-prefix plugin

    Downsides

    Prefixes obviously have lots of downsides, but that's the nature of the beast and it's not in my powers to change that.

    Broader ruminations on the viability of the Facade

    To be quite honest, using Redbean "in the wild" (meaning: painful, but unfortunately non-negotiable situations) shows the weak points of a Facade approach pretty quickly. I still like the Facade a lot for quick and dirty work, but the more I think about it, conceptually, the more I see the Facade as a specialized version of an Instance.

    My current conclusion is: Maybe a RedBeanPHP\Instance should be part of Redbean, with RedBeanPHP\Facade being a wrapper for that.

    The biggest problem, of course, is that the syntax between static and instance calls are different, '->' instead of '::'. That means your code becomes less portable across implementations.

    Furthermore: design of plugins

    I've looked at a couple other plugins during my development and mostly what I see is that people write a R::ext() call straight into the class file. That's not really instance safe. Might not matter that much if you always want to have all your extensions, but can be problematic (let alone wasteful) as soon as you're in a CMS context where apps are talking to eachother, each with their own extensions.

    In my opinion, a plugin should only supply the class, not inject itself into the Facade automatically.

    Reviewed by daviddeutsch at 2014-01-01 13:17
  • 4. Replace RedUNIT

    • Use PHPUnit instead of RedUNIT
    • Replace Spike PHP Coverage with some other tool (ideas?)
    • Learn-by-test (http://derickbailey.github.io/backbone.marionette/docs/backbone.marionette.html)
    Reviewed by gabordemooij at 2013-11-02 11:51
  • 5. Get instance of database connection

    At Multiple database here https://redbeanphp.com/index.php?p=/database

    static calls are used to switch databases. Could it be made possible to get an object instance representing the database connection?

    Reviewed by flip111 at 2020-04-13 12:49
  • 6. PHP Fatal error: Class 'RedBean_QueryWriter_Cubrid' not found

    I suppose you've forgotten to include CUBRID RedBean driver, haven't you? Or should I download the DB plug-in and require_once in the code manually?

    Here is the error I receive when I try to connect to a CUBRID database.

    PHP Fatal error:  Class 'RedBean_QueryWriter_Cubrid' not found in /home/user/localhost/rb.php on line 5565
    

    Right now I am writing a small PHP app which uses RedBeanPHP to store data into a CUBRID database.

    Reviewed by CUBRID at 2012-05-29 11:56
  • 7. Website has some issues on mobile

    When visiting the website on a mobile device (specifically iPhone 13 Pro Max using Chrome), there seems to be an issue with the menu overlay.

    The overlay seems to be shown by default, and attempts to dismiss it (i.e. tapping in the overlay) just reveal the menu. Screenshots as follows:

    image

    image

    Reviewed by benmajor at 2022-03-12 09:10
  • 8. Website does not work

    Hi,

    I have been trying to gain access to the website (https://www.redbeanphp.com/) for several days and always get the following error ERR_CONNECTION_RESET. Is there any other place I can dowload the documentation?

    Thanks,

    Jerome

    Reviewed by martinjeromelouis at 2020-02-05 10:45
  • 9. Checking for active transaction

    Right now, we have rollback, commit and begin methods. There should be also a method that allows us to check if there is any active transaction. This is especially useful for databases that don't support nested transactions (SQLite). PDO already has it: http://www.php.net/manual/pl/pdo.intransaction.php

    Reviewed by rr- at 2013-08-08 10:13
  • 10. RedBean extras, community participation/plugins

    So, I think it makes sense to make this into a ticket. On the mailing list, we already talked a little about this. To recap:

    • While we are building RB4, a lot of the new and fancy stuff should and will happen in plugins - this keeps the core clean and concise
    • Ideally, each plugin should be maintained mostly by one member of the community who takes responsibility for it
    • It is also the responsibility of the maintainer to keep up the same level of testability and "documentation by test" noted in #308
    • Having a separate repository is probably the way to go. What about redbean-extras? Although I would prefer redbean-sugar, but I might be pushing it with the coated beans idea
    • One of the goals is that with redbean-sugar, we create a source for building a custom RB distribution
    Reviewed by daviddeutsch at 2013-11-10 11:05
  • 11. Feature: allow for duplicate key inserts?

    Currently, RB requires to my understanding high overhead or manual SQL for performing "upserts" against tables with duplicate keys. I'd appreciate a solution that is able to use "REPLACE INTO" or "INSERT IGNORE" or similar mechanisms.

    Reviewed by andig at 2012-05-23 11:40
  • 12. Models seem to behave strangely with var types

    We have noticed some odd behaviour in RedBean, which I suspect may be related to fetchAs and models. For instance, in our Organization model, we have the following getter defined:

    /**
     * Get the owner of the organization
     * 
     * @return User
     */
    public function getOwner()
    {
        return $this->bean->fetchAs('user')->owner;
    }
    

    This correctly returns the user bean, and we're then able to use the getId() method on that bean, but it returns a string, rather than integer, so a strict equality check fails. The below is from a method inside of our user Model:

    var_dump($organization->getOwner()->getId());
    var_dump($this->getId());
    

    Which produces:

    string(1) "1"
    int(1)
    

    Obviously this causes the following check to fail:

    if ($organization->getOwner()->getId() === $this->getId()) {
        return true;
    }
    

    Of course, we can solve this by changing to a non-strict equality check, but it would be good to try and narrow down where the behaviour is coming from, as I don't think this should be the default behaviour inside of RedBean?

    In case it helps, here's our __call() magic method that handles the getters and setters of Models via an AbstractEntity class, in case it may be useful in identifying the cause of this:

    /**
     * Magic get() and set() definition
     *
     * @param string $method The method name called
     * @param mixed $params The parameters of the method
     */
    public function __call($method, $params)
    {
        $start = substr($method, 0, 3);
    
        if ($start == 'get' || $start == 'set') {
            $property = lcfirst(substr($method, 3));
    
            // It's a getter:
            if ($start == 'get') {
                $value = $this->bean->$property;
    
                // Is it a valid datetime?
                if (is_string($value) && \DateTime::createFromFormat('Y-m-d H:i:s', $value) !== false) {
                    return \DateTime::createFromFormat('Y-m-d H:i:s', $value);
                }
    
                // Is it a valid date?
                if (is_string($value) && \DateTime::createFromFormat('Y-m-d', $value) !== false) {
                    return \DateTime::createFromFormat('Y-m-d', $value);
                }
    
                // Attempt to decode:
                if (is_string($value)) {
                    $json = json_decode($value);
    
                    // Is it a JSON string?
                    if (json_last_error() === JSON_ERROR_NONE) {
                        return $json;
                    }
                }
    
                // Return value of the object:
                return $value;
            }
    
            // It's a setter:
            else {
                // We need at least one param for a setter:
                if ( ! count($params)) {
                    throw new EntityExcpetion('Setter for '.$property.' expects at least 1 parameter.');
                }
    
                $param = $params[0];
    
                // It's a date:
                if ($param instanceof \DateTime) {
                    $param = $param->format('Y-m-d H:i:s');
                }
    
                // Now set the value:
                $this->bean->$property = $param;
    
                // Return the entity to preserve method chaining:
                return $this;
            }
        }
    }
    
    
    Reviewed by benmajor at 2022-04-23 09:07
  • 13. Duplicating site/page tree

    I cannot duplicate entire site with linked page tree.

    I just got duplicated site row, but cannot get duplicated "site_id" field in new pages.

    Here's my code:                

    $rootPage = R::findOne('page',' page_id IS NULL AND site_id = ?', [ $formData['id'] ]);
    
    $dupRootPage = R::duplicate( $rootPage );
               
    $site = R::load('site', $formData['id']);
    $dupSite = R::duplicate( $site );
    $dupSite->name = $site->name.' (copy)';
                                        
    $dupSite->ownPageList[]=$dupRootPage;
    
    $dupRootPage->traverse( 'ownPage', function( $page ) use (&$dupSite){
    
              $dupSite->ownPageList[]=$page;
    
    });
    
    
    R::store( $dupSite );
    

    Can you please help with this?

    Reviewed by marmz at 2022-04-16 22:28
  • 14. class_exists can cause performance issues.

    In my own code, I've got custom autoloader, which just scans all subfolders of application for class (there's not much), and doesn't cache results in any way, so it performs scan on every new xxx(); or class_exists().

    This causes BIG performance issues, in my case script was executing for about 2.0 - 3.5 seconds, cause class_exists() is called about 3-4 times for every SQL result row, but when I changed all class_exists($class) occurrences to class_exists($class, false), same code was executing for 0.1 - 0.2 seconds, so it's a 350 times faster.

    While I customized rb.php script myself which solves my issue, my proposal is to either add some property/constant which can force this setting, or cache subsequent calls for same class. Solution 1. seems to be easiest, as it only requires changing 4 lines of code to something like: class_exists( $modelName, defined( 'REDBEAN_CLASS_AUTOLOAD' ) ? REDBEAN_CLASS_AUTOLOAD : true ), and then const REDBEAN_CLASS_AUTOLOAD = false; would help with performance issues if someone doesn't want autoload for RB.

    class_exists is called in \RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper::resolveModel and in pure php as if (!class_exists('R')).

    Reviewed by gnysek at 2022-04-13 08:56
Related tags
A Redis based, fully automated and scalable database cache layer for Laravel
A Redis based, fully automated and scalable database cache layer for Laravel

Lada Cache A Redis based, fully automated and scalable database cache layer for Laravel Contributors wanted! Have a look at the open issues and send m

May 24, 2022
Spot v2.x DataMapper built on top of Doctrine's Database Abstraction Layer

Spot DataMapper ORM v2.0 Spot v2.x is built on the Doctrine DBAL, and targets PHP 5.4+. The aim of Spot is to be a lightweight DataMapper alternative

Apr 24, 2022
Doctrine Database Abstraction Layer

Doctrine DBAL 4.0-dev 3.0 2.13 N/A N/A Powerful database abstraction layer with many features for database schema introspection, schema management and

May 25, 2022
Laravel 5 - Repositories to abstract the database layer

Laravel 5 Repositories Laravel 5 Repositories is used to abstract the data layer, making our application more flexible to maintain. See versions: 1.0.

May 24, 2022
Database Abstraction Layer, Schema Introspection, Schema Generation, Query Builders

Cycle DBAL Secure, multiple SQL dialects (MySQL, PostgreSQL, SQLite, SQLServer), schema introspection, schema declaration, smart identifier wrappers,

Apr 22, 2022
A drop-in Doctrine ORM 2 implementation for Laravel 5+ and Lumen
A drop-in Doctrine ORM 2 implementation for Laravel 5+ and Lumen

Laravel Doctrine ORM A drop-in Doctrine ORM 2 implementation for Laravel 5+ $scientist = new Scientist( 'Albert', 'Einstein' ); $scientist->a

May 19, 2022
MongoDB ORM that includes support for references,embed and multilevel inheritance.
MongoDB ORM that includes support for references,embed and multilevel inheritance.

Introduction Features Requirements Installation Setup Database Basic Usage - CRUD Relationship - Reference Relationship - Embed Collection Inheritance

Apr 26, 2022
Doctrine Object Relational Mapper (ORM)

3.0.x 2.9.x 2.8.x Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence for PHP objects. It sits on top o

May 28, 2022
Baum is an implementation of the Nested Set pattern for Laravel's Eloquent ORM.

Baum Baum is an implementation of the Nested Set pattern for Laravel 5's Eloquent ORM. For Laravel 4.2.x compatibility, check the 1.0.x branch branch

May 20, 2022
Propel2 is an open-source high-performance Object-Relational Mapping (ORM) for modern PHP

Propel2 Propel2 is an open-source Object-Relational Mapping (ORM) for PHP. Requirements Propel uses the following Symfony Components: Config Console F

Apr 29, 2022
PHP DataMapper, ORM
PHP DataMapper, ORM

Cycle ORM Cycle is PHP DataMapper, ORM and Data Modelling engine designed to safely work in classic and daemonized PHP applications (like RoadRunner).

May 19, 2022
Extensions for the Eloquent ORM

Sofa/Eloquence Easy and flexible extensions for the Eloquent ORM. Currently available extensions: Searchable query - crazy-simple fulltext search thro

May 1, 2022
Ouzo Framework - PHP MVC ORM
Ouzo Framework - PHP MVC ORM

Ouzo is a PHP MVC framework with built-in ORM and util libraries. PHP 8.0 or later is required. We believe in clean code and simplicity. We value unit

Jan 18, 2022
Builds Cycle ORM schemas from OpenAPI 3 component schemas

Phanua OpenAPI 3 + Jane + Cycle ORM = ?? Phanua builds Cycle ORM schemas from OpenAPI 3 component schemas. Released under the MIT License. WARNING: Th

Aug 1, 2021
Simple Enum cast for Eloquent ORM using myclabs/php-enum.

Enum cast for Eloquent Simple Enum cast for Eloquent ORM using myclabs/php-enum. Requirements PHP 7.3 or higher Laravel 8.0 or higher Installation You

Apr 21, 2022
Extra RedBean ORM

RedBeanPHP 5 RedBeanPHP is an easy to use ORM tool for PHP. Automatically creates tables and columns as you go No configuration, just fire and forget

Nov 12, 2021
Articulate - An alternative ORM for Laravel, making use of the data mapper pattern

Articulate Laravel: 8.* PHP: 8.* License: MIT Author: Ollie Read Author Homepage: https://ollie.codes Articulate is an alternative ORM for Laravel bas

Jan 4, 2022
:gem: Simple MySQLi Abstraction Layer + Doctrine/DBAL support

?? Simple MySQLi Class This is a simple MySQL Abstraction Layer compatible with PHP 7+ that provides a simple and secure interaction with your databas

Mar 16, 2022
SleekwareDB is a NoSQL database storage service. A database storage service that can be used for various platforms and is easy to integrate.
SleekwareDB is a NoSQL database storage service. A database storage service that can be used for various platforms and is easy to integrate.

SleekwareDB is a NoSQL database storage service. A database storage service that can be used for various platforms and is easy to integrate. NoSQL API

May 23, 2022