Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

RapidDataMapper, a new Object-Relational-Mapper

December 13, 2009 9:24pm

Subscribe [12]
  • #1 / Dec 13, 2009 9:24pm

    m4rw3r's avatar

    m4rw3r

    647 posts

    RapidDataMapper

    I’ve finally managed to get my new Object-Relational-Mapper to a stage where I can release it to the public. It has taken a long time, but finally I also have a complete? manual ready (over 26k words, it was a bit of a pain to write).

    RapidDataMapper is both a stand alone Object-Relational-Mapper and a mapper which can be integrated into different frameworks. I have made it CodeIgniter-compatible as a first step, but other frameworks will also follow (when I or someone else has time to create compatibility files, making it officially compatible).

    The CodeIgniter specific variant replaces the $this->db object with the main connection object of RapidDataMapper, this to make it easier to use. But you can also skip replacing it (by modding the supplied MY_Loader.php) if you want to be able to use both simultaneously.

    RapidDataMapper is based on the DataMapper pattern, and I have taken this to the “extreme” by completely decoupling the objects from the mapper and hiding the mappers behind a proxy object. Compared to IgnitedRecord (my previous ORM), RapidDataMapper does not affect the model, at all. Instead the model is supposed to do what it always has done: fetching and storing data. RapidDataMapper is a tool which is to be used *by* the model to simplify database interaction (it is not strictly so, you can use it in the controller or even in the view, but it “makes more sense” to place all db interaction in a few select files).

    A somewhat new idea which I use in RapidDataMapper is the Descriptors. They are objects which describe how the objects should be mapped to the database, which columns that map to properties etc. They can be extended and modified in innumerable ways, making it possible to create your own defaults and override normal behaviour of the mappers.

    RapidDataMapper uses an autoloader to load the files, and they are stored in the directory application/data_model/ with the name of the class + .php.

    Example usage:

    // application/data_model/user_obj.php
    <?php
    class User_obj
    {
        public $name;
        public $id;
    }
    
    // application/data_model/user_objdescriptor.php
    class User_objDescriptor extends Db_Descriptor
    {
        function __construct()
        {
             $this->setClass('User_obj');
             $this->setSingular('user'); // this makes the other default adjust themselves, eg. table becomes users
    
             $this->add($this->newPrimaryKey('id'));
             $this->add($this->newColumn('name'));
        }
    }
    
    // Usage:
    
    $u = new User_obj();    // the User_obj class is autoloaded
    
    $u->name = 'Martin';
    
    Db::save($u);    // here is the "magic" done
    
    echo $u->id;
    
    $u = Db::find('User_obj', 1);
    
    echo $u->name;

    That was just a very very simple example of the usage of RapidDataMapper, it is capable of a lot more.

    RapidDataMapper is extremely configurable but it is still aimed to be easy: It assumes a lot of defaults but you can replace almost any of them. By using a code builder and mapper cache can RapidDataMapper really be rapid: only a few files needs to be loaded once the mapper has been built.

    Suggestions and comments are extremely welcome!
    (and I’m happy to help people start with it, but check the manual first, it should cover the most of it)

    Link: http://www.rapiddatamapper.com

  • #2 / Dec 14, 2009 5:12am

    happydude

    45 posts

    Yay!

    First to comment!

    If Rapid Datamapper makes it big, my name will be in the hall of fame.

    Now, lets go test this shiny new library out.

  • #3 / Dec 14, 2009 9:42pm

    Johan André's avatar

    Johan André

    412 posts

    Wow!
    You really put alot of work into this!

    I have’nt been able to try it, but I read the docs and it looks awesome!

    Good work!

  • #4 / Dec 15, 2009 12:40am

    helmutbjorg's avatar

    helmutbjorg

    167 posts

    Just had a go and this looks REALLLY nice. Great work! Just wondering why you chose to create a new folder called data_model and not put the models in the models folder? And on the same note not use the system/cache folder to cache the models too?

    Is that because you want it to not be codeigniter specific? Perhpas in that case you could add some configuration settings that would allow you to set the path to those locations.

  • #5 / Dec 15, 2009 12:49am

    helmutbjorg's avatar

    helmutbjorg

    167 posts

    Also noticed that the autoload doesn’t seem to work when you do a find(). For example


    This autoloads the track model and descriptor

    $t = new Track();

    However using this line doesn’t trigger the autoload

    $tracks = Db::find('track');

    I get the following error

    Fatal error:  Uncaught exception 'Db_DescriptorException' with message 'RapidDataMapper: Descriptor for class "track": Descriptor is missing.' in /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/application/libraries/Db.php:364
    Stack trace:
    #0 /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/application/libraries/Db.php(397): Db::getDescriptor('track')
    #1 /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/application/libraries/Db.php(494): Db::getMapper('track')
    #2 /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/application/controllers/welcome.php(16): Db::find('track')
    #3 /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/codeigniter/CodeIgniter.php(236): Welcome->index()
    #4 /Applications/MAMP/htdocs/CodeIgniter_1.7.2/index.php(115): require_once('/Applications/M…')
    #5 {main}
      thrown in /Applications/MAMP/htdocs/CodeIgniter_1.7.2/system/application/libraries/Db.php on line 364
  • #6 / Dec 15, 2009 1:34am

    helmutbjorg's avatar

    helmutbjorg

    167 posts

    I like this alot. I’m one of your die hard ignitedrecord fans. Obviously I understand the benefits of the separation of the object model from the interaction methods, and I especially like the fact that you have abstracted this one step further (away from codeigniter). However I have become quite attached to the methods and code names that are used by both codeigniter active record and also ignitedrecord. Why have you chosen to change little things like ‘order_by’ to ‘orderBy’?

    Also would be keen to see some tests to compare Ignitedrecord vs RDM in both speed and memory!

    Anyway sorry to blab on! Once again great work!

  • #7 / Dec 15, 2009 5:38am

    m4rw3r's avatar

    m4rw3r

    647 posts

    @All:

    Thanks for the appreciation!

    @helmutbjorg:

    First: The data objects are not models, they are usually just data containers with some convenience methods for application specific tasks, eg. generating an image path.
    But you can make them into whatever you like (you can even make them into some kind of ActiveRecord-ish data object, but that might not really be optimal raspberry ).

    So the reason they aren’t stored in app/models is that they do not behave like CI models. Unless you make them so, but that would require a lot of unnecessary code compared to when you just have create a normal CI model which uses the data objects.

    Second: And the reason I use an app specific mapper cache: What would happen if you share the mapper cache between two apps and they have different settings for the same class name?

    Third: The reason you get that error is because RapidDataMapper cannot find the descriptor, it may be because the CI specific autoloader (MY_Loader::load_data_object, added in My_Loader::initRDM) is not loaded (or it can also be so that the class name is not correctly spelled (and the filename should be lowercase, but that won’t matter on mac)).

    Four: The reason I changed from underscore_separated_methods to camelCaseMethods is that a lot of other PHP projects prefer to use camelCase. I still use underscore_separated_variable_names, but that is only internally in the classes. Another reason is that it requires less keystrokes to write.

  • #8 / Dec 15, 2009 1:42pm

    m4rw3r's avatar

    m4rw3r

    647 posts

    About the models, I’ve written about an alternative to CI’s models if you don’t want to use them while using RapidDataMapper.

    The post can be found here: http://www.rapiddatamapper.com/#blog

    And about that performance comparison, what type of tests do you want me to do?

  • #9 / Dec 17, 2009 3:07pm

    m4rw3r's avatar

    m4rw3r

    647 posts

    Has anyone tested RapidDataMapper with a somewhat advanced configuration (ie. more than one mapped class)?
    (Just curious, and no, I haven’t found a fatal flaw raspberry)

    Or is it that:

    a) Everyone is preparing for Christmas?
    b) My library is missing a feature you must have?
    c) The manual is too large?
    d) The manual sucks?

    PS.
    @helmutbjorg:

    Did you get it to work?

  • #10 / Dec 17, 2009 3:22pm

    helmutbjorg's avatar

    helmutbjorg

    167 posts

    Yeah just been really busy (and the snow was calling me too) but I did have another play around with it. I found I was rebuilding the functionality of Ignitedrecord using RDM. Is that the idea? Do I create a model that interacts with the data model on top of RDM? You mentioned on your website that you have not yet finished implementing all of the features. I’m keen to see your todo list..

    Nope I didn’t fix that error.

    I put the ‘track’ model and the ‘trackDescriptor’ all in the one file ‘track.php’ and put it in the ‘data_model’ folder. I then tried to put the trackDescription into its own file ‘trackDescriptor.php’ in the same folder and that didn’t fix the problem. I guess i’m not perfectly clear (even from your examples in the manual) on exactly what files to create and where to put them. You say what to put in them but not where and how.

  • #11 / Dec 17, 2009 3:47pm

    m4rw3r's avatar

    m4rw3r

    647 posts

    The idea, at least this is how I have used RDM, is that I create a “method lib” which is the model.
    This method lib contains a lot of the common operations (eg. get all artworks + their users + a cover image and make sure that it is active) which I use throughout my app, some of them perform queries and return the result, others return a query object which already has some data in it and to which I can add extra conditions (for edge cases) and eg. pagination.

    I guess many used IgnitedRecord just as it was and wrote the lot of the queries in the model?
    (Instead of adding new methods to the class inheriting from IgnitedRecord)
    You can do that with RDM too, just use Db::find(‘classname’) and then you have a query object you can manipulate.

    So, to help with your error:

    * Have you added the supplied MY_Loader.php?
    * If you use a case sensitive system (Linux, Unix and the like (not mac OS X, strange enough)), then make sure that the files are all lowercase (in app/data_model).
    * Have you called either MY_Loader::initRDM() or $this->load->database() (after adding the MY_Loader) before you try to load anything RDM related (like the descriptor or the class in data_model)?
    * A note about putting them in the same class: That will work as long as you *always* try to load the Track class before the descriptor.

    PS. I’ve added a vote about which upcoming feature that is most important in the feature requests section in the RDM forum here: here.

    Of course, if you have another suggestion, either post it here or in RDM forum’s Feature Requests section.

  • #12 / Dec 17, 2009 3:59pm

    helmutbjorg's avatar

    helmutbjorg

    167 posts

    Ahhh… you hit it with ‘make sure that the files are all lowercase’. I’ll have a bit more of a play around with this tomorrow! Better get some work done right now.

  • #13 / Dec 17, 2009 4:02pm

    m4rw3r's avatar

    m4rw3r

    647 posts

    Ok, good smile

    I’m making that a warning then, it was written in the manual, but apparently it is buried beneath all the text raspberry.
    (It will have a nice little header saying Warning before the paragraph, located in both sections dealing with CI wink )

  • #14 / Dec 17, 2009 4:54pm

    Jelmer's avatar

    Jelmer

    436 posts

    Hi m4rw3r,

    I read the manual and love your approach. However, I’m already building 2 systems on top of a self-written ORM (probably very much inferior to yours) which was inspired in part by IgnitedRecord.
    I’ll probably switch to RapidDataMapper on my next project though as especially like the seperation of object & logic. I’ll let you know my experiences when I’ve done some real stuff with it, but that won’t be for another 2 months.

    I might give it an early try if I get round to rewriting my own business’s administration software - which I wrote in a hurry about a year ago when I needed it and still has a lot of db usage in the controllers. I’ll let you know any experiences I have.

    Regards & complements on the library!

    Jelmer

  • #15 / Dec 17, 2009 4:57pm

    happydude

    45 posts

    For me, I think the library packs a lot of punch but is kinda complicated and so will need some time for people to wrap their heads around.

ExpressionEngine News

#eecms, #events, #releases