This is an outdated version of the Manual. Visit the NEW Manual

Models and FUSE

A model is a place to put validation and business logic. Imagine a Jazz band that can only have up to 4 members. We could implement this rule like this:


    
if (count($members) > 4)
    throw new 
Exception('Too many!');
    
    
$band->ownMember $members;
    
R::store($band);

However, now we need to add this check everytime we call R::store(). It would be much more convenient if R::store() was smart enough to do this check itself. We can accomplish this by putting the validation rule in our model. RedBeanPHP automatically discovers the models that belong to beans, so we can implement this validation like this:



    
class Model_Band extends RedBean_SimpleModel {
            public function 
update() {
                    if (
count($this->bean->ownMember)>4)
                    throw new 
Exception('Too many members!');
            }
    }

    list(
$band,$members) = R::dispenseAll('band,member*5');
    
$band->ownMember $members;
    
R::store($band); //will trigger exception

Now, every time we call store and something is wrong with the number of members, an exception will be triggered automatically. The mechanism that connects beans to models is called FUSE, because beans are fused with their models. Within a model, $this->bean refers to the bean. To create a model for your bean simply add a class and name it:


    
class Model_X extends RedBean_SimpleModel { ... }

where X is the name of the bean, starting with an uppercase character. So if you have a bean called: 'car', add a class named 'Model_Car'. Also make sure you extend RedBean_SimpleModel. On R::store(), RedBeanPHP will now call the method update() on the model instance.

Scoping rules

Within the model, the $this->bean variable refers to the bean. Simply $this also refers to the bean but without returning references, in practice this can be very confusing so I recommend to use $this->bean.

Namespaced models

If you use PHP namespaces and your model resides in namespace \Models simply add the following constant on top of your code:


    define
'REDBEAN_MODEL_PREFIX''\Models\' );

After this line a bean of type 'dog' will connect to \Model\Dog. You can also use this constant to remap model classes in other namespaces. For more complex mappings see Custom Model Mappings.

Fused methods

Besides update() RedBeanPHP FUSE calls other methods on the model as well, here is a quick overview:

Action on beanInvokes method on Model
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()

Example: all fused methods

To demonstrate the order and use of all of these methods let's consider an example:


    $lifeCycle 
'';
    class 
Model_Bandmember extends RedBean_SimpleModel {
        public function 
open() {
           global 
$lifeCycle;
           
$lifeCycle .= "called open: ".$this->id;
        }
        public function 
dispense(){
            global 
$lifeCycle;
            
$lifeCycle .= "called dispense() ".$this->bean;
        }
        public function 
update() {
            global 
$lifeCycle;
            
$lifeCycle .= "called update() ".$this->bean;
        }
        public function 
after_update(){
            global 
$lifeCycle;
            
$lifeCycle .= "called after_update() ".$this->bean;
        }
        public function 
delete() {
            global 
$lifeCycle;
            
$lifeCycle .= "called delete() ".$this->bean;
        }
        public function 
after_delete() {
            global 
$lifeCycle;
            
$lifeCycle .= "called after_delete() ".$this->bean;
        }
    }
    
$bandmember R::dispense('bandmember');
    
$bandmember->name 'Fatz Waller';
    
$id R::store($bandmember);
    
$bandmember R::load('bandmember',$id);
    
R::trash($bandmember);
    echo 
$lifeCycle;

output:


    called dispense
() {"id":0}
    
called update() {"id":0,"name":"Fatz Waller"}
    
called after_update() {"id":5,"name":"Fatz Waller"}
    
called dispense() {"id":0}
    
called open5
    called delete
() {"id":"5","band_id":null,"name":"Fatz Waller"}
    
called after_delete() {"id":0,"band_id":null,"name":"Fatz Waller"}

Custom FUSED methods

Besides the standard methods mentioned above, any method on the model can be invoked by calling it on the bean (assuming it does not collide with a native bean method):


    $dog 
R::dispense('dog');

    
//call bark() on Model_Dog:
    
$dog->bark();

Boxing and Unboxing

If you have a bean and you want to obtain the corresponding model use:


    $dogBean 
R::dispense('dog');

    
//get reference to Model_Dog
    
$dogModel $dogBean->box();

Similarly, if you have a model and you want its inner bean, call:


    $dogBean 
$dogModel->unbox();

We call this technique boxing (and unboxing). This can be handy if you want to make use of typehinting:


    
public function addDog(Model_Dog $dog) {
        ...    
    }

Otherwise, we would have to use type RedBean_OODBBean which is less descriptive.

Domain Model

This page describes how RedBeanPHP automatically finds model classes for its beans. This means you can start your application with beans and add models later, without modifying the original code. This is exactly what RedBeanPHP is made for, to allow your code to evolve from simple scripts to a full-fledged, rich domain model. There is no need to start building the domain models first, you can prototype your application first and then let it grow into a domain model. If this is the first time you work with models and a domain model I recommend to read some more about domain driven design also known as DDD.


 
 

RedBeanPHP Easy ORM for PHP © 2024 Gabor de Mooij and the RedBeanPHP community - Licensed New BSD/GPLv2