RedBeanPHP (The Power ORM)

RedBeanPHP is an easy to use ORM for PHP. It’s a Zero Config ORM lib that ‘automagically’ builds your database schema.

Welcome

RedBeanPHP is an easy to use ORM for PHP. It’s a Zero Config ORM lib that ‘automagically’ builds your database schema.

IMPORTANT! RedBeanPHP 3.5 is approaching EOL status!

After 1 October, RedBeanPHP 3.5 will no longer be supported nor maintained !
If you want to continue to use a maintained version of RedBeanPHP, upgrade to version 4.3!
UPDATE: Due to popular demand, support has been extended until December 2016

News

2016-10-25: RedBeanPHP 4.3.3 has been released !
2016-10-02: RB 3.5 support has been extended until December 2016
2016-05-01: RedBeanPHP 4.3.2 has arrived !
2016-01-09: RedBeanPHP 4.3.1 has been released!
2015-10-01: RedBeanPHP 4.3 has been released!
2015-09-11: RedBeanPHP 4.3 beta 2 has been released!
2015-09-02: RedBeanPHP 4.3 Beta 1 has been released!
2015-07-29: RedBeanPHP 4.2.5 has been released!

 

Code Example

This is how you do CRUD in RedBeanPHP:

    require 'rb.php';
R::setup();
R::setAutoResolve( TRUE );        //Recommended as of version 4.2
$post = R::dispense( 'post' );
$post->text = 'Hello World';
$id = R::store( $post );          //Create or Update
$post = R::load( ‘post’, $id );   //Retrieve
R::trash( $post );                //Delete

This automatically generates the database, tables and columns… on-the-fly. It infers relations based on naming conventions. RedBeanPHP is written by BDFL Gabor de Mooij and the RedBeanPHP community.

Zero Config

No verbose XML files, no annoying annotations, no YAML or INI. Zero Config. Just start coding.

Fluid Schema

During development, RedBeanPHP will adapt the database schema to fit your needs, giving you the NoSQL experience. When deploying to production servers, you can freeze the schema and benefit from performance gains and referential integrity.
RedBeanPHP offers the best of both worlds!

Powerful

RedBeanPHP is a compact library yet packed with features: auto-discovery of models, deep copying and smart import features will boost your productivity!
Write less, do more!

Compatible

RedBeanPHP strives to support all ALL Free, Open Source databases.
Currently, RedBeanPHP supports: MySQL, MariaDB, SQLite, PostgreSQL and CUBRID.

Download

Download the easy-to-use one-in-all package, one single file containing the entire RedBeanPHP library! No composer, no auto-loaders, no configuration, just download and run! Go to the download page and download to latest version of RedBeanPHP!

 

CRUD

CRUD stands for Create, Update, Retrieve and Delete. CRUD operations are the core of many web applications.

Working with beans

RedBeanPHP works with beans. Most interactions with the database are accomplished using beans. Beans are used to carry data from and to the database.

Every bean has a type and an ID. The type of a bean tells you which table in the database is used to store the bean. Every type maps to a corresponding table. The ID of a bean is the primary key of the corresponding record.
You can create a new bean by dispensing one.

Create

To create a new bean (of type ‘book’) use:

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

You can now add properties:

    $book->title = 'Learn to Program';
$book->rating = 10;

You can also use array notation if you like:

    $book['price'] = 29.99; //you can use array notation as well

and store the bean in the database:

    $id = R::store( $book );

At this point, the bean will be stored in the database and all tables and columns have been created.
The bean will now have an ID, which is also returned for your convenience.

RedBeanPHP will build all the necessary structures to store your data. However custom indexes and constraints have to be added manually (after freezing your web application).

Conventions

You can dispense any type of bean you like, as long as the type name consists of lowercase alphabetical characters:

    $page = R::dispense('page'); //valid

$page = R::dispense( ‘Page’ ); //invalid: uppercase
$page = R::dispense( ‘cms_page’ ); //invalid: _
$page = R::dispense( ‘@#!’ ); //invalid

However dispense also offers some shortcuts:

    $twoBooks = R::dispense( 'book', 2 );

list($book, $page) = R::dispenseAll( ‘book,page’ );
list($book, $pages) = R::dispenseAll( ‘book,page*2’ );

Properties of beans may contain alphanumeric characters and underscores. Camelcased properties will automatically convert to snake_case:

    $book->isSoldOut = TRUE; //is_sold_out
$book->hasISBNCode = TRUE; //has_isbn_code

Retrieve

To load a bean, simply pass the type and ID of the bean you’re looking for:

    $book = R::load( 'book', $id ); //reloads our book

If the bean does not exist an empty bean with ID 0 will be returned.

Update

To update a bean in the database, add or change properties:

    $book->title = 'Learn to fly';
$book->rating = 'good';
$book->published = '2015-02-15';
R::store( $book );

Note that we added a new property ‘published’, RedBeanPHP will add a new column of type ‘date’ for this property. Also, it will widen the ‘rating’ from INTEGER to VARCHAR to support text as well as numbers.

    //Examples of other data types
$meeting->when = '19:00:00'; //Time
$meeting->when = '1995-12-05'; //Date
$photo->created = '1995-12-05 19:00:00'; //Date time
$meeting->place = '(1,2)'; //SPATIAL only works in postgreSQL
$price->amount = '12.37'; //FIXED POINT NUMERIC - MySQL and Postgres
$price->amount = '$25.00'; //MONEY TYPE - Postgres only

If you want a suitable data type of monetary values, use the ‘XX.XX’ format and you’ll get a fixed precision number data field. To make use of Postgres special purpose, currency-aware money data type, prefix the value with a common currency symbol.

You can use R::isoDate() and R::isoDateTime() to generate the current date(time) if you like.

As of RedBeanPHP 4.1 you can also use spatial columns for MySQL, learn more.

RedBeanPHP will dynamically add new columns to your database. It determines the column type to use by looking at the value you are trying to store. For instance, a short text might be stored as a VARCHAR while a large text might be stored as TEXT. Similarly, a boolean value will probably get stored as TINYINT but when you put a float in that property the column will probably be changed to FLOAT or DOUBLE (depending on your database).
Some column types behave differently, for instance if you store a valid ISO formatted date (i.e. 2015-01-01) RedBeanPHP builds a DATE column, but this column will not change. In general, RedBeanPHP tries to adapt the database to your application. If you’re done developing, you can freeze the database using the freeze() function. After that, the database schema will no longer change (because it is very unlikely you want to store something other than a date in a column you filled with perfectly formatted date in the first place).
Note that RedBeanPHP will never throw away columns or ‘shrink’ columns (from TEXT to VARCHAR) to avoid data loss. RedBeanPHP also only manipulates column types it recognizes, so if you change a VARCHAR(255) to a VARCHAR(254) it will leave that column alone, since it no longer recognizes the type. This means that if you customize columns, RedBeanPHP leaves them alone from that point on.
If RedBeanPHP alters the database in a way you don’t like, don’t worry, you can always tune the schema to your liking (just use your database management tool or phpmyadmin), you can even freeze certain tables only.

Delete

To delete a bean:

    R::trash( $book ); //for one bean
R::trashAll( $books ); //for multiple beans

To delete all beans of a certain type:

    R::wipe( 'book' ); //burns all the books!

To destroy the entire database simply invoke the nuclear method (be careful!):

    R::nuke();

Batch

To load a series of beans use:

    $books = R::loadAll( 'book', $ids );

Reload

To quickly reload a bean:

    $bean = $bean->fresh();

Finding Beans

Instead of loading beans, you can also use the find() method to search for beans using certain criteria. Learn how to query beans in RedBeanPHP.

Finding

If you do not know the ID of a bean, you can search for beans using the find method:

    $book  = R::find( 'book', ' rating > 4 ');

The find() method uses good old SQL. No fancy, custom query language — just plain old SQL.

The find operation in this example returns all beans of type book having a rating of four stars or more.

Find and SQL

The following example demonstrates how to use find() with bindings.

    $books = R::find( 'book', ' title LIKE ? ', [ 'Learn to%' ] );

This find operation will return all beans of type ‘book’ having a title that begins with the phrase: ‘Learn to’.

If find() has no results it will return an empty array.

There is no need to use mysql_real_escape. Always use the bindings.
Never use PHP variables in your query!

IN-queries

To use a ‘SELECT-IN’ style query use the R::genSlots function to generate the correct number of ‘?’ slots:

    $promotions = R::find( 'person',
' contract_id IN ('.R::genSlots( $contractIDs ).')',
$contractIDs );

Find One

If you want a single bean instead of an array, use:

    $book  = R::findOne( 'book', ' title = ? ', [ 'SQL Dreams' ] );

If no beans match the criteria, this function will return NULL.

Find All

Use findAll if you don’t want to add any conditions (but you want to order or limit… )

    $books = R::findAll( 'book' );
$books = R::findAll( 'book' , ' ORDER BY title DESC LIMIT 10 ' );

If no beans match your criteria, this function returns an empty array.

Named slots

All find methods: find, findOne and findAll also accept named slots:

    $books  = R::find( 'book', ' rating < :rating ', [ ':rating' => 2 ] );

Besides querying beans, you can also use regular SQL queries.

Cursors (4.2+)

You can also use find with cursors:

    $collection = R::findCollection( 'page', ' ORDER BY content ASC LIMIT 5 ' );
while( $item = $collection->next() ) {
...
}

The advantage of using a cursor is that the entire collection will not be loaded into memory all at once. This is handy for dealing with large bean collections.

Find like (4.2+)

To find a bean matching certain criteria, you can use R::findLike(). The following code returns all flowers that are either yellow OR blue:

    R::findLike( 'flower', [
'color' => ['yellow', 'blue']
], ' ORDER BY color ASC ' );

Note that you can append some SQL here along with bindings.

Find or create (4.2+)

This works like R::findLike() but also creates (and stores) the bean if it does not exist yet…

    $book = R::findOrCreate( 'book', [
'title' => 'my book',
'price' => 50] );

Find Multiple (4.2+)

findMulti() takes a query and turns the result into several bean collections having different types:

    $beans = R::findMulti( 'book,page', '
SELECT book.*, page.* FROM book
INNER JOIN page.book_id = book.id
WHERE book.category = ?
', [ $cat] );

The first parameter of this function lists the types to load, the second parameter is the query, then come the optional query parameter bindings. The result of this operation will be something like:

    array(
'book' => book beans...
'page' => page beans...
)

Besides loading various bean types at once from a query, this method can also restructure them, for instance to ‘put the pages in the book’ use (example of 4th parameter):

    array(array(
'a'       => 'book'
'b'       => 'page'
'matcher' =>  function( $a, $b ) {
return ( $b->book_id == $a->id );
}
'do'      => function( $a, $b ) {
$a->noLoad()->ownPageList[] = $b;
}
));

The fourth parameter of findMulti takes an array containing arrays like the one above. The array in the example tells findMulti how to restructure the pages and the books. First it defines two variables ‘a’ and ‘b’ it then defines a matcher function, telling RedBeanPHP to execute the ‘do’ clause if the book_id of a page matches the id of a page. The ‘do’ clause then puts the page in the pageList of the selected book. While you can specify mappings like this, a better idea might be to write your own set of mapping functions returning structures like this.

Querying

Querying the database manually is also possible with RedBeanPHP. You can use the SQL query functions provided by RedBeanPHP. To execute a query:

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

To get a multidimensional array:

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

The result of such a query will be a multidimensional array:

    Array
(
[0] => Array
(
[id] => 1
[title] => frontpage
[text] => hello
)
...
)

Note that you can use parameter bindings as well:

    R::getAll( 'SELECT * FROM page WHERE title = :title',
[':title' => 'home']
);

To fetch a single row:

    R::getRow( 'SELECT * FROM page WHERE title LIKE ? LIMIT 1',
[ '%Jazz%' ]
);

To fetch a single column:

    R::getCol( 'SELECT title FROM page' );

And finally, a single cell

    R::getCell( 'SELECT title FROM page LIMIT 1' );

To get an associative array with a specified key and value column use:

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

In this case, the keys will be the IDs and the values will be the titles. getAssocRow will return complete rows.

In my examples, I like to use the short array notation.
In PHP < 5.4 you’ll have to use the classic array notation:

array( ‘key’ => ‘value’ ).

Get the insert ID (4.2+)

To get the ID after an insert in MySQL/MariaDB compatible databases use:

    R::exec( 'INSERT INTO ... ' );
$id = R::getInsertID();

Converting records to beans

You can convert rows to beans using the convertToBeans() function:

    $sql = 'SELECT author.* FROM author
JOIN club WHERE club.id = 7 ';
$rows = R::getAll( $sql );
$authors = R::convertToBeans( 'author', $rows );

As of version 4.3.2 you can also use: R::convertToBean, without the s, for single rows.

Remember:
There is no need to use mysql_real_escape as long as you use parameter binding.

Besides querying you can also use other database functionality (like transactions) in RedBeanPHP. Learn more about database functions.

How to use queries

Sometimes using a plain query is more efficient than using beans. For instance, consider the following example:

    $books = R::findAll( 'book' );
foreach( $books as $book ) {
echo $book->title;
echo $book->author->name;
foreach( $book->sharedCategoryList as $cat ) {
echo $cat->name;
}
}

Using a plain query this task could be accomplished far more efficiently:

    $books = R::getAll( 'SELECT
book.title AS title,
author.name AS author,
GROUP_CONCAT(category.name) AS categories FROM book
JOIN author ON author.id = book.author_id
LEFT JOIN book_category ON book_category.book_id = book.id
LEFT JOIN category ON book_category.category_id = category.id
GROUP BY book.id
' );
foreach( $books as $book ) {
echo $book['title'];
echo $book['author'];
echo $book['categories'];
}

One of the biggest mistakes people make with ORM tools is to try to accomplish everything with objects (or beans). They forget SQL is a very powerful tool as well. Use SQL if you are merely interested in generating reports or lists.