
I would like to start a series of articles on the development of the LiveStreet engine, namely its
framework part. LiveStreet has become quite popular as a
blog social blog , but in 2 years it has grown into something much larger. Especially with the release of version 0.4. *, When there were ample
opportunities for writing plug-ins with the
functionality of inheritance and delegation .
Quite a
large number of large social networks have already been
built on LiveStreet using these technologies.
In this regard, developers need to develop functionality, modules and hacks for their projects. The introduction of plug-ins has simplified this process at times. We continue to work in this direction: now I will talk about the alpha version of the implementation of the
ORM approach based on the
ActiveRecord pattern, which we developed (and continue to develop) in LiveStreet.
')

What is ORM (in a nutshell)
The idea of ​​ORM lies in the presentation, mapping of database tables as classes (models), and records from them as objects of this class. The main goal of the ORM approach is to automate standard routine functions (
CRUD ) for working with data in the database, eliminate the unnecessary need to write SQL queries and generate responses.
As it was before
Previously, when creating a model (
Sample ), it was necessary to perform a series of uniform actions and write or copy a good amount of code. Only according to the LS structure, it was necessary to create 3 large files:
/ modules/
sample/Sample.class.php - module file: a set of functions for managing models:
AddSample (), UpdateSample (), GetSampleById (), GetSampleByBlablabla () , etc., most of which elicit a synonym from mapper (see below) and handles caching.
/modules/sample/entity/Sample.entity.class.php - the essence of the model, has a list of methods a la
getId (), getBlablabla (), setId (), setBlablabla () ;
/modules/sample/mapper/Sample.mapper.class.php is a sql-mapper of the model, which contains almost the same functions as in the module file, only with sql queries to the tables.
And all these methods had to be registered / rewritten manually each time a new model was created. In addition, it was necessary to prescribe additional settings, such as the name of the table in the database, etc.
What can be done now
What does the ORM implementation give us? In fact, the opportunity will get rid of
~ 80% of the uniform code .
Modules, entities and mappers that inherit the corresponding ORM classes automatically possess most of the standard methods:
get * (), Add (), Save (), GetBy * (), GetItemsBy * (), Delete () , etc.
I will give a more detailed, classic example. Suppose we want to create a “photo album” module.
1) First, create the “Album”
prefix_album and “Photo”
prefix_photo entity tables in the database of the form:
album_id | author_id | album_title
and
photo_id | album_id | photo_title | photo_img_src
2) Create a module file of our gallery:
/classes/modules/gallery/Gallery.class.php :
<?php class ModuleGallery extends ModuleORM { public function Init() { parent::Init(); } } ?>
3) Create the entities files
/classes/modules/gallery/entity/Album.entity.class.php and
/classes/modules/gallery/entity/Photo.entity.class.php :
<?php class ModuleGallery_EntityAlbum extends EntityORM {} ?>
and
<?php class ModuleGallery_EntityPhoto extends EntityORM {} ?>
4) And ... that's all. Now we can manage our entities through singleton Engine:
According to our estimates, even this small set is enough to implement 30% -40% of the methods (read the lines of code) described in the standard modules, entities and mapers by the old method.
I think ... it's great! :)
What else? ... Relationships
An important element in any web application is connections (relationships) of models. Typically, these relationships are created through the database using primary keys in the tables.
Let's go back to our example: it’s obvious that the photos in the gallery are related to the album, and therefore I don’t know how you are, but I think it would be cool to
we could just write ...
$aPhotos = $oAlbum->getPhotos();
Yes, it would definitely be cooler! No problem :) To bind entities you just need to configure their relationships using the
$ aRelations array in the entity class description.
Let's return to our
currently empty file
/classes/modules/gallery/entity/Album.entity.class.php and add the following code to it:
<?php class ModuleGallery_EntityAlbum extends EntityORM { protected $aRelations = array( 'photos' => array(self::RELATION_TYPE_HAS_MANY,'ModuleGallery_EntityPhoto','album_id'), 'author' => array(self::RELATION_TYPE_BELONGS_TO,'ModuleUser_EntityUser','author_id'),
And for the file
/classes/modules/gallery/entity/Photo.entity.class.php we write this:
<?php class ModuleGallery_EntityPhoto extends EntityORM { protected $aRelations = array( 'album' => array('belongs_to','Gallery_Album','album_id'), ); } ?>
And that's all. Now we can even more easily operate with entities,
attention :
$aPhotos = $oAlbum->getPhotos(); $sUserLogin = $aPhotos[0]->getAlbum()->getAuthor()->getLogin();
We will understand the syntax of the
$ aRelations array .
Its keys are the names of the related entities, which will then be accessible via
get * . Values ​​in most cases are also arrays consisting of the following elements:
- Relationship type Currently available types are belongs_to, has_one, has_many, many_to_many and tree
- Essence that we cling to
- A field in a table that contains the primary key of a clingable or current entity, depending on the type of relationship
- The name of the join join-table for the type many_to_many
What's next?
For the first time, I think it’s enough for now, in the next article I’ll dwell on the description of relationship types, I’ll tell you about the type of
tree , which allows you to manage tree structures; about the possibilities of automatic loading of related entities in
GetBy * () ; as well as additional methods such as
GetByFilter (), GetCountItemsBy * (), GetByArray * (), Update (), Delete (), Reload (), reload * () and others.
Why is this all?
We call the developers. Despite a successful start, the community framework is now almost in its childhood, and we understand perfectly well that without good people, without a real team, it will be much more difficult for us to bring LiveStreet to an international level. Yes, and we strive for this :)
I sincerely hope that our innovations will help developers (as well as all the rest: users and startups, copywriters and PR managers, specialists and investors) to become interested in the truly wonderful, young and promising
LiveStreet engine.
And, finally, I would like to ask in advance not to make holivars on the topic “And have RoR / ZF / Yii ActiveRecord in a different way” and “don't worry, put Doctrine for yourself!”, Etc. Let's be optimistic.
Thanks for attention.
Respectfully,
Alexander Zinchuk (Ajaxy).