RedBeanPHP - CodeFirst PHP Framework

Redbeanphp
In this post we will talk about a very interesting ORM framework RedBeanPHP . It is notable primarily for its ability to create a database structure on the fly. In addition, the framework is easy to use as two pennies. My story will be divided into 3 parts.
In the second part, the main theme will be models. In the third - a change in the logic of the framework.

Before writing a post, I worked hard and made a test applicationwith 15,000 entries, in order to be convinced from my own experience of the possibility of incredibly lightening the work. After all, I’m probably not the only one who prescribes the fields in several places with a terrible realization of the meaninglessness of this work, especially at the initial stage of development. Finally, an analogue of the Entity Framework Code First from .NET appeared, which at one time caused me a wild delight. So in order.

The origins


This miracle was written by a man with the equally wonderful name Gabor. Gabor is a failed student who has studied cognitive psychology. The failure occurred due to the banal lack of demand for these specialists, but I am still ready to admit that Gabor is a very good psychologist. When using the framework, the feeling of simple and obvious what is happening does not leave me.

Start


To connect, you need to add only one file, which contains all the code.

require('rb.php');

Quite simple, isn't it? Let's look inside and find that the data file weighs 260 KB and is a version of the framework assembled from many files. On GitHub, you can download the regular version of about 40 files. In this case, the following code is required to connect:

require('redbean.inc.php');

Structure


The framework has a well-organized class structure. The structure includes drivers for PDO and Oracle. This means that RedBeanPHP supports a wide range of databases. The documentation indicates support for the following databases: MySQL 5, SQLite, PostgreSQL, CUBRID, Oracle. Support for the latter is not included in rb.php, it must be downloaded from GitHub separately. However, no one bothers us to write our own driver, inheriting from the RedBean_Driver class.
And in order to modify the internal logic of the framework, you need to create your own version of QueryWriter. I will touch on this topic in detail in the third part of the review.
The framework supports Plugins, and has a simple Logger class for displaying all database queries to the screen. I did not find the entry in the file, but it does not present any problems to inherit my own class.
Here is the code of the logger supplied:

class RedBean_Logger_Default implements RedBean_Logger {
  public function log() {
    if (func_num_args() > 0) {
      foreach (func_get_args() as $argument) {
        if (is_array($argument)) echo print_r($argument,true); else echo $argument;
		echo "
\n"; } } } }

All files are well documented using PHPDocs. The tooltips in the IDE work fine, except for the fields of the object associated with the columns of the table.

Using


To connect, you must specify a PDO format string:

R::setup('mysql:host=localhost;dbname=mydatabase',
        'user','password'); //mysql
R::setup('pgsql:host=localhost;dbname=mydatabase',
        'user','password'); //postgresql
R::setup('sqlite:/tmp/dbfile.txt',
        'user','password'); //sqlite

An example of creating a new record and a new table if it is missing (only in fluid mode):

// Создаем объект (bean) работающий с таблицей book
$book = R::dispense( 'book' );
// выставляем значение полей, тип поля будет автоматически модифицирован в зависимости от значения
$book->title = 'Gifted Programmers';
$book->author = 'Charles Xavier'; 
$book->price = 99.99; 
//Сохраняем, первичный ключ id создается автоматически
$id = R::store($book);

And so the existing “bean” is loaded.

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

The author calls bean objects (bin - English bean plants) containing data. This object is not a model and has the goal of simply storing data and working with records in the database. How to connect a model containing business logic with them I will describe in the second part of the review.

The framework by the presence of the id field of an object decides to create or update a record. How to change this logic I will show in the third part.

The bean is searched by specifying the WHERE clause:

$needles = R::find('needle',
        ' haystack = :haystack ORDER BY :sortorder', 
            array( 
                ':sortorder'=>$sortorder, 
                ':haystack'=>$haystack 
            )
        );

In the same place, in the second parameter, you can specify the ORDER BY and LIMIT constructs.

Communications


Working with a relational database implies the existence of connectivity between tables. RedBeanPHP supports all the necessary types of links. To create a one-to-many relationship, we use a property with the prefix own.

// Создаем bean работающий с таблицей village
$village = R::dispense('village');
// Создаем bean’ы работающие с таблицей building
list($mill,$tavern) = R::dispense('building',2);
// для связывания просто присвойте массив bean в поле с префиксом own
$village->ownBuilding = array($mill,$tavern);
R::store($village);    

The building table is created in the database. The village_id field will be added to the building table, pointing to the id field of the village table. A link to the parent table will also be created and the necessary indexes created. A link will have the property of cascading data update and deletion.

If you look at the other side of the connection, you can access the parent object in this way:

$village = $mill->village

RedBeanPHP supports the concept of “lazy loading”. That is, the loading of related data will occur at the time of accessing the object field.

// запроса к таблице building не происходит 
$village = R::load('village',$id);
// осуществляется запрос к building
$buildings = $village->ownBuilding; 

Own field is an associative array, so we can replace a separate object:

$village->ownBuilding[$id] = $house;

To remove the connection between objects, you must call the following code (the objects themselves will not be deleted):

unset($village->ownBuilding[$someID]); 
R::store($village);

To remove a bean and its associated parent objects:

R::trash( $book );
// или в случае массива
R::trashAll( $books );

To clear the table:

R::wipe( 'book' );

To create a many-to-many relationship, we use a property with the shared prefix.

$army = R::dispense('army');
$village->sharedArmy[] = $army;
$village2->sharedArmy[] = $army;

As a result, an additional army_village table will be created and the necessary links and indexes will be created. Otherwise, working with shared lists is similar to own list.

Typically, a bean type is indicated by the name of an object field.

// $village отображает таблицу village
$village = $building->village    

But sometimes it is necessary to assign bean to the fields of the object not following this rule.

list($teacher,$student) = R::dispense('person',2);
$project->student = $student; 
$project->teacher = $teacher; 

When saving, the framework is guided by the bean type specified in dispence, and both child objects will be stored in the person table, and the student_id and teacher_id fields will be created in the project table.
In this case, an ambiguous situation may occur when fetching a bean from the database, since the framework cannot determine what type is in the fields $ project-> student and $ project-> teacher. In this case, the type is specified by calling fetchAs:

$teacher = $project->fetchAs('person')->teacher;

Trees

The framework supports one-to-many, many-to-many circular links.
For example, creating a category tree:

//$subbean и $bean имеют тип category
$subbean = R::dispense('category');
$subbean->title = $title;
$subbean->url = $url;
$subbean->parent = $bean;
R::store($subbean);

In the table, the parent_id field and the necessary relationships and indexes will be created.

Performance


Framefork has 2 operating modes: fluide and frozen. In fluide mode, RedBeanPHP takes care of the structure of your table itself, sacrificing performance. After development is complete, you can increase productivity by switching the framework from frozen mode:

R::freeze( true ); 

Database Requests


ORM supports SQL queries.

R::exec( 'update page set title="test" where id=1' );

There is also a query builder:

R::$f->begin()
    ->select('*')->from('bean')
    ->where(' field1 = ? ')->put('a')->get('row');


Model Overview


I’ll run a little in the second part and describe how the model is created in RedBeanPHP.

At the beginning, you work with bean, without involving models. When you need a model, you create a class of the type Model_BeanName, for example Model_User, and there you describe additional logic. The binding of the bean and model is automatic.

$user = R::dispence('user');
$user->modelMethod();

That is, we start with ActiveRecord, and if necessary expand to models. The author calls this approach FUSE.

In the second part, we will continue the discussion about the functions of the framework for daily work:
  • Models
  • Transactions
  • and other topics

In the third part, we discuss additional features of RedBeanPHP:
  • Debugging
  • Server for Javascript application.
  • Plugins
  • A practical example of changing internal logic
  • and other topics


Resources


Official site RedBeanPHP

Also popular now: