Active Record-like layer for RedBean
The ActiveBean provides functionnality similar to an Active Record implementation, using RedBean as the backend. RedBean upgrades your schema on-the-fly while you code, so you never have to manually alter or create your tables.
ActiveBean is part of the Shozu library/framework but can be used alone with Redbean.
Basic usage
To use ActiveBean, I will assume that you have a Redbean installed and "kickstarted".
Defining your model is as easy as extending the base class and then adding a simple method to it:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title');
$this->addColumn('content');
}
}
Then to create and save a new Post:
<?php $post = new Post; $post->title = 'an interesting post'; $post->content = 'some blah'; $post->save();
You may use this alternative syntax:
<?php
$post = new Post;
$post->setTitle('an interesting post');
$post->setContent('some blah');
$post->save();
Each record has an id. If you know the id, you can retrieve your record by passing it to the constructor:
<?php $post = new Post(1);
If you are familiar with RedBean, you can achieve the same thing by passing a bean to the constructor:
<?php $post = new Post($post_bean);
You might as well pass an array to the constructor:
<?php
$post = new Post(array('title' => 'an interesting post', 'content' => 'some blah'));
Validate and format data
Using ActiveBean you can enforce data validation by adding validators and formatters to the table definition:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title', array(
'formatters' => array('trim'),
'validators' => array('notblank')
));
$this->addColumn('content', array(
'formatters' => array('trim')
));
}
}
Formatters and validators are simple protected methods. Validators are executed before save() and return a boolean value. Formatters are executed upon __set() and return the modified parameter. ActiveBean comes with standard validators (notblank, email, etc) and formatters (uppercase, lowercase, trim, nodiacritics, etc) and you can easily add your own:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title', array(
'formatters' => array('trim', 'ucfirst'),
'validators' => array('notblank','isscalar')
));
$this->addColumn('content', array(
'formatters' => array('trim')
));
}
protected function ucfirstFormatter($in)
{
return ucfirst($in);
}
protected function isscalarValidator($in)
{
return is_scalar($in);
}
}
You can also use callbacks as validators and formatters:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title', array(
'formatters' => array('trim', array('myNeatFormattersLib','someStaticMethod')),
'validators' => array('notblank',array('myNeatValidatorsLib','someOtherStaticMethod'))
));
$this->addColumn('content', array(
'formatters' => array('trim')
));
}
}
Invalid records will throw an exception on save().
Column typing
It is possible to enforce a type for a column. You don't have to limit yourself to scalar values: objects and arrays are automatically serialized/unserialized for you. Allowed types include string, boolean, array, datetime (automatically converts to a DateTime object), etc:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title');
$this->addColumn('content');
$this->addColumn('published', array('type' => 'boolean'));
$this->addColumn('published_at', array('type' => 'time'));
}
}
More options
You can specify unique indices for columns:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title');
$this->addColumn('content');
$this->addColumn('slug', array('unique' => true));
}
}
If you set a length to your column and add the "limiter" formatter, your values will be truncated. With no limiter, an Exception is thrown if you try to assign a value that is larger:
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
// will be truncated
$this->addColumn('title', array(
'length' => 64,
'formatters' => array('trim', 'limiter')
));
// will throw an exception if you set text that is more than 140 cars.
$this->addColumn('content', array(
'length' => 140
));
$this->addColumn('slug', array('unique' => true));
}
}
You can also automatically add columns to stamp the record on creation and modification. Their values are set on save():
<?php
class Post extends \shozu\ActiveBean
{
protected function setTableDefinition()
{
$this->addColumn('title');
$this->addColumn('content');
$this->addColumn('slug', array('unique' => true));
$this->isStampable = true; // adds modified_at and created_at cols.
}
}
Finding records
Finding records works as using RedBean's finder plugin. Just use SQL:
<?php
$posts = Post::find('title like ?', array('%test%'));
You can limit the search to one record:
<?php
$post = Post::findOne('title like ?', array('%test%'));
Relations
You can link records using the.... link() method:
<?php $post->link($comment); $post->save();
And unlink records using the.... unlink() method:
<?php $post->unlink($comment); $post->save();
You may unlink all comments of the post:
<?php
$post->unlink('Comment');
$post->save();
Please note the operation is not effective until you save the record.
Finding related records is pretty straight-forward too:
<?php
$commentsIds = $post->getRelated('Comment');
You can return only comments ids for saving memory. You can do so by setting the $hydrate param to false:
<?php
$comments = $post->getRelated('Comment', false);