Introduction to Redbean

An Introduction to Redbean

When it comes to RAD and prototyping, there are lots of tools available to help get projects up-and-running quickly. From quick-starts to micro-frameworks, from build tools such as Composer to one-click installers, and of course ORMs – there are all sorts of ways to speed up development time. I'm going to look at Redbean, an ORM with a difference, which is ideal for prototyping.

Enter Redbean

Redbean is an ORM (Object Relational Mapper), but it does more than that – it creates and modifies the underlying schema on-the-fly. Traditionally, you would use an ORM as a wrapper to a pre-planned, pre-existing database schema. That's fine for most projects, but when you're prototyping – or making it up as you go along! – having it done for you behind the scenes can speed things up even more.

When you create an object with Redbean – or bean, to use the specific terminology – as soon as you save it to the database, the schema adapts itself to fit. This applies even if you're trying to save an object without a corresponding table!

Installation

The easiest way to install Redbean is to download the all-in-one package. Then, you simply need to require the single file, rb.php.

You can also install it via Composer; however, the author of the library does not recommend this approach – see the installation page for details .

Dispensing

The first step when using Redbean is to “dispense” a bean – which is basically an object. Note that I'll be using the term “bean” and object interchangeably throughout the rest of the post.

Dispensing is done via a static method of the overarching Redbean class, “R”, which takes the type as an argument.

For example:

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

This will create an empty object for a user, to which you can then assign properties. You can also dispense several at the same time by adding the number you want as a second parameter:

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

It doesn't matter at this stage whether there's a table in the database to hold it; as soon as we try and store it, Redbean will take care of that.

Let's try this – note the use of the static method store, which is used to write to the database:

$user->name = 'Joe Bloggs';
$user->email = 'joe.bloggs@example.com';
$id = R::store($user);
print $id;

In most ORM's, you'd expect this to fail if you haven't yet created a table to hold users. However, using Redbean this succeeds because it creates the table for you. If you take a look in your database at this stage, you should see a table like this:

user
----

id      int(11) UN PK AI
name    varchar(255)
email   varchar(255)

By necessity, the naming convention is pretty strict; it's a singular, lower-case representation of the type you specified.

Now let's look at how the schema changes as we iterate. A user record will likely need a password field – but we forgot to create one.

If you do this:

$user->password = 'secret';
R::store($user);

This time, Redbean knows how to store a user but there's a new field that the database table can't accommodate. No matter – it simply adds one, and your table will now look like this:

user
----

id          int(11) UN PK AI
name        varchar(255)
email       varchar(255)
password    varchar(255)

Field Data Types

Redbean tries to guess the data type of a field based on the information you provide. So if you did this:

$user->age = 30;
R::store($user);

You'll find that the age field has been created as a tiny integer.

If a field type doesn't prove sufficient later, Redbean simply alters it on-the-fly. If you tried to assign 3000 to the age now, the column would be changed to a normal integer. If you spelt out the name as “thirty”, it would be changed to a varchar. Set a varchar field to something greater than 255 characters and it becomes a TEXT field, and so on.

Finding Beans

You can load a specific object by primary key using load:

$user = R::load('user', 1);

You can load several objects at a time (by primary key) by using the batch method:

$users = R::batch('user', array(1, 2, 3));

This returns an array of beans.

You can also find beans using SQL. The second argument to the find method is essentially SQL from the WHERE clause onwards, excluding the WHERE keyword itself. For example, to find users who aren't yet twenty:

$users = R::find('user', 'age < ?',
    array(20)
);

Note that we're binding the parameters, hence the array as the third argument. This returns an array of beans using their ID's as keys.

You can add more clauses to your SQL, for example:

$users = R::find('user', 'age < ? ORDER BY age ASC',
    array(20)
);

Counting

You can find out the number of records using the count method:

$number_of_users = R::count('user');

Deleting

To remove a single bean, use trash:

R::trash($user);

To remove more of a particular type, use trashAll:

R::trashAll('user');

To delete all beans of a particular type, use wipe:

R::wipe('user');

Or, to wipe out everything – which can be useful while prototyping – you nuke it:

R::nuke();

Relations

As with any ORM, relationships between objects are supported.

One-to-many relations are referred to using the concept of “owning” related objects. For example if orders have a single user, that user is said to “own” those orders. By using a specific variable name, we can build that relationship like this:

$orders = R::dispense('order', 2);
$orders[0]->order_id = '000001';
R::store($orders[0]);
$orders[1]->order_id = '000002';
R::store($orders[0]);

$user->ownOrders = $orders;
R::store($user);

The key element here is the property ownOrders. If you now inspect your database, you should find that Redbean has added the field user_id to the order table, along with a corresponding foreign key.

The user that “owns” the order can simply be accessed as a property, e.g.:

$user = $order->user;
print 'This order belongs to ' . $user->name;

In order to demonstrate many-to-many relationships, let's create some roles:

$roles = R::dispense('role', 3);

$roles[0]->name = 'member';  
R::store($roles[0]);
$roles[1]->name = 'admin';  
R::store($roles[1]);
$roles[2]->name = 'super_admin';
R::store($roles[2]);

Roles don't just belong to individual users; they are shared. So to assign the first two roles to a user, and in doing so build the relationship in the database, we can do this:

$roles = R::batch('user', array(1,2));
$user->sharedRole = $roles;
R::store($user);

This time, you should find a new table called role_user, which defines this relationship as a many-to-many.

You can get the roles belonging to a user by reading the property:

$roles = $user->sharedRole;

This lazy-loads the roles the first time they're accessed.

There's a lot more to relationships, including the ability to add properties to the relation using link, filtering by link, eager loading, and so on – check out the documentation for details.

Models

You can create models to correspond to bean types simply by following naming certain conventions. Models are then connected to beans using FUSE; as in, by following the relevant naming convention they are FUSEd together.

The convention is simple; separate “Model” and the type with an underscore, e.g. Model_Type. So for example, to create a model for users, you simply do this:

class Model_User extends RedBean_SimpleModel { }

Once you've defined a model, there are a number of methods you can implement which will get called at different points in the bean's lifecycle. This is illustrated in the table below, which maps the CRUD operations to the “hooks” you can implement:

R::store        $model->update()
R::store        $model->after_update()
R::load            $model->open()
R::trash        $model->delete()
R::trash        $model->after_delete()
R::dispense        $model->dispense()

So, for example, you could add validation by implementing update():

class Model_User extends RedBean_SimpleModel { 
  public function update() {
    if (strlen($this->password) < 8) {
      throw new Exception('Password must be at least 8 characters long');
    }
  }
}

You can also create your own methods, of course, as well as custom GETters.

Querying the Database

You can execute a raw SQL query like this:

R::exec('UPDATE user SET status = 1');

You can return a multidimensional array of rows like this:

R::getAll('SELECT * FROM user');

Additionally, you can use parameter binding:

R::getAll('SELECT * FROM user WHERE status = :status',
    array(':status' => 1)
);

You can fetch a single column like this:

R::getCol('SELECT email FROM user');

You can also get an associative array using two columns of a table like so:

R::$adapter->getAssoc('SELECT id, email FROM user');

Deploying your Application

Although it's arguably best suited for prototyping – or at least development – there's no reason you can't continue your use of Redbean into production, provided you follow certain steps.

Redbean's mechanism for updating the schema on-the-fly is called “fluid mode”; however this isn't appropriate for production, and has a pretty significant performance overhead. However, you can turn it off by “freezing” it:

R::freeze( true );

In going into production, you're going to want to follow a few more steps:

  • review the column data types
  • review the foreign keys and relations
  • check the indexes – Redbean creates a few – and modify appropriately

Summary

In this article, I've introduced Redbean as a handy way to kick-start your development process, by allowing you to play around with your domain models without worrying about building the underlying schema first. Whether it's viable for production remains to be seen – but for prototyping and rapid iterations, it's a great little tool. There's much I haven't covered, so be sure to check out the documentation.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Anonymous

    Good introduction Lukas.

  • Mike

    This looks really fantastic, I’ll surely give it a try soon.

  • Anonymous

    I don’t think using these on-the-fly manipulations of tables is good idea, it can lead to unexpected bugs and makes harder bugfixing even if its prototyping i don’t really see the point of using this method.

    • Anonymous

      Really??

      What if you are a front end developer, and you are willing to pay someone else to deal with Schema Design / Database development, wouldn’t you build your front-end and use RedBean as a way to prototype your front-end to see how it works? I don’t think anyone would expect it to be flawless…

      As soon as I read this post that’s exactly what I thought I would try, a simple, framework-less prototype to concentrate on the front end / UI aspects.

      I think you’re thinking to much about the practicality of running this as production quality build, which you probably wouldn’t do….

      Another way this could save you time, is by the fact that once you build a front end you might identify missing links or opportunities towards the end of the lifecycle, which means if you where using a strict schema you may need to make massive changes just so you can implement something trivial like “liking” for images, which could set you back a lot of time in schema design, but in the case of redbean you can simply update the image object like in the password example…

  • Rick Kuipers

    @Zsolt, don’t forget Redbean was made for fast prototyping/development and such. It’s not recommended to use this on production but I can see it’s potential with certain cases.

  • Anonymous

    Oh Man. Love Red Bean.

    Have been using RedBean in production for 2-3 years now and it really has made me so much more productive.

    I think I have used it in about 20 projects now and I can really saw that I spent very little time looking for bugs with the data layer (well caused by RedBean, sometimes the issues are mine).

    RedBean is fast enough, provides a safe interface for Sql Injection. Allows you write very terse can clean code and I find it great when working with CRUD layers.

    I have done some really complicated many to many relationships with information in the joins and RedBean has delivered with a terse readable one line of code.

    Debugging is also easy as the RedBean code is not that massive at all and is clearly written IMHO. Anyway love it. Use it, it has made my life simpler. John.

    • Arun

      Sponno, will you be able to help me with any sample project, to Quick start with RedBean, i ran sample of examples,
      Thanks for your detailed explanation about RedBean, i have started by seeing your comment.

  • Anonymous

    I personally recently moved on MongoDB for projects that need quick prototyping, but if you need relational data MySQL Redbean is probably the faster way to start a project, because you don’t need to design your schema. It comes also with all the advantage of an ORM, so you can treat tables as object and do join as easy as one PHP line.

    I totally recommend it to everyone.

    Bonus, it’s stay all in one file, so you use it with:
    require “rb.php”;

  • Alex

    I think it’s for nube’s. It will make an ALTER every time when developer will make a mistake? OMG %)
    If I will need shema-less, I’l chose a shemaless document-oriented DB engine such as mongoDB.
    Prototyping relational databases without calculations becomes harmful with real load, and I think it’s a wrong way.
    But , I’m interested in the project. It’s a new way.

    • Anonymous

      Alex3 you can turn fluid mode off by freezing it:
      R::freeze( true );

  • gen

    Hi, nice tutorial.

    In the text above regarding to relations instead of:
    $roles = R::batch(‘user’, array(1,2));
    should be:
    $roles = R::batch(‘role’, array(1,2));

  • Arun

    Thank You Lukas and everyone, I also started with RegBean.