SilverStripe 3’s new ORM

Posted by Sam Minnée on 9 November 2011

Sam Minnée, Chief Executive Officer and co-founder of SilverStripe, has shaped the SilverStripe Suite and is part of its success story as an internationally respected Open Source CMS.

One of the parts of SilverStripe 3 that I was most heavily involved with was the development of the new ORM. ORM stands for “Object-relational mapper” and it’s the part of the system that turns your DataObject::get() calls into SQL queries, and constructs relevant DataObjects with the results. In other words, it maps our PHP objects to a relational database for storage.

The biggest change we’ve made to the ORM in SilverStripe 3 is how it fetches sets of records. In SilverStripe 2, if you wanted to query some fields you would call this:

$pages = DataObject::get(‘SiteTree’, ‘“ParentID” = 5’);

The query would be executed straight away. On the face of it, this might not be such a problem, and for simple cases it works okay.

But what about if I just want to get the number of records that match that query? Maybe I would call this: 

$pages = DataObject::get(‘SiteTree’, ‘“ParentID” = 5’);
$count = $pages ? $pages->Count() : 0;

However, in SilverStripe 2 what that would do is query every single matching record from the database, create a DataObject for them, get the size of, and then throw all of those objects away. This is very inefficient. 

As a result, a more common way to get the number of records was to run something like this: 

$count = DB::query(‘SELECT COUNT(*) FROM “SiteTree” WHERE
“ParentID” = 5’)->value();

This is more efficient, but it bypasses the ORM and is really just an admission that the ORM isn’t giving us what we need.

In SilverStripe 3, a DataObject::get() call won’t query the database immediately. Instead, it will create an internal representation of that ORM query and save it for later. There is a new class for storing these, called DataList. It will only call the query once a result is needed. For example:

// Query isn’t executed here 
$pages = DataObject::get(‘SiteTree’, ‘“ParentID” = 5’);
// Query is executed here
foreach($pages as $page) echo “<li>$page->Title</li>”;

As part of these changes, we have made a new API better indicate that you are creating an option that represents the query, rather than querying straight away. The old syntax still works:

DataObject::get(‘SiteTree’, ‘“ParentID” = 5’);

But, going forward, we recommend this new syntax: 

DataList::create(‘SiteTree’)->where(‘“ParentID” = 5’);

Another advantage of this syntax is that you don’t need to remember the order of all the DataObject::get() arguments.

What’s more, when you call the Count() method, it won’t call the full query at all. Instead it will create a suitable “SELECT COUNT(*) …” query based on the original query. As a result, this code is now much more efficient: 

$count = DataList::create(“SiteTree”)->where(‘“ParentID” = 5’)->Count();

So, efficiency is a benefit, but the new ORM also lets us make our code more loosely coupled and easier to maintain. We can pass DataLists to other parts of the system, without needing to explain how that DataList has been created. For example, ComplexTableField has a large number of configuration fields for specifying the data that should be displayed. In SilverStripe 3, we are replacing ComplexTableField with GridField, which takes one parameter for specifying data: a DataList. GridField doesn’t need to know the query behind that DataList. Instead, it can just call limit(), sort(), and filter() to limit the query to the appropriate page of results.

There’s more to the new ORM than what I can cover in a single blog post. You can find out more on the doc site. If you would like to try this out right now, you can download SilverStripe 3.0.0-alpha1.

Post your comment

Note: Comments are moderated and won't show until they are approved

Comments

  • useful blog. Thank you sam for posting it.

    Posted by mike, 2 years ago @carribean

  • In the past I've been using the dataobjectManager plugin to input has_one has_many etc data in CMS. I'm just wondering how to manage the data within the CMS in version 3

    Posted by Jon, 3 years ago

  • I totally agree the new ORM also lets us make our code more loosely coupled and easier to maintain. Thank you for the post, Jason!

    Posted by Morgan Homes, 3 years ago

  • The new ORM is certainly superior than the previous ways. I can't way to check out the stuff!

    Posted by Trish Homes, 3 years ago @anitttta123yahoocom

  • Hi Jason,

    Thanks for the feedback about the method name. We're trying not to change the API too much post-alpha but it's not set in stone. silverstripe-dev@groups.google.com is the place where we discuss this kind of thing, feel free to chime in there!

    Thanks,
    Sam

    Posted by Sam, 3 years ago

  • Hrmmm, don't like the "create", replacing "get"... I understand it's creating a datalist but... :(

    Posted by Jason, 3 years ago

  • Hi Sam,
    our whole firm is looking forward to work with SS3. As our web applications deal with large amounts of data these performance advantages of the new ORM are very promising.
    Thanks for sharing the results of your hard work with us!

    Posted by Roland Lehmann, 3 years ago

  • Sounds great. I always forget the order of those DataObject::get() arguments!

    Posted by Jono, 3 years ago

  • The new ORM of SS3 is definitely a more elegent way to solve Dataobject looping with improved proformance!

    Thumb up guys!

    Posted by alex, 3 years ago

  • Thanks for the post. Was already wondering where that DataList would fit in.

    Posted by Stijn De Lathouwer, 3 years ago @dendeffe

RSS feed for comments on this page | RSS feed for all comments

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.