This article is primarly intended for developers, describing some techniques behind a new feature of our upcoming version of Community Framework.
Starting with Community Framework 2.0 we will provide a clear and consistent API to access all database tables, this includes editors, listings and even centralized actions, furthermore we implemented decorators to add specific data on the fly without polluting the original object.
The next step was to increase the abstraction on each object to massively reduce redundant code found in almost every
DatabaseObject derivations and editor classes - using
late static binding we can gather all necessary data at runtime.
Decorators encapsule the original object and extend it with additional data and methods for accessing those without polluting the object and making it reusable everywhere. Okay, I have to admit this might not be that clear and it sounds like rocket science, but it is not! Please bear in mind that the editor classes are actually decorators, even though they’re not explicitly called this way.
Imagine you have a thread with 20 posts within and you want to track how often each post is displayed. With WCF 1.1 you would have to create a
PostEditor object for each post individually (causing 20 additional SQL queries!) or by writing a manual query which updates all posts at once. On the one hand you gain poor performance (but can work with a nice object) or feel the pain of writing plain SQL queries for something the framework should handle on itself. Doesn’t sound smart? You’re right and that’s the reason we implemented decorators.
Let’s go one step back and think of what is already provided: We have a thread object and a post list which holds an object for each post. Each time you create a new instance of
PostEditor you fire up a query which fetches all this stuff you already have, that’s weird. With WCF 2.0 you can simply take each
Post object and wrap it within a
PostEditor object enabling you to edit the object without querying anything.
|
PHP Source code
|
1
2
3
4
|
foreach ($posts as $post) {
$postEditor = new PostEditor($post);
$postEditor->update(array('views' => $postEditor->views + 1));
}
|
This looks clearly better, but you might wonder how the
PostEditor knows which post he should edit – remember we’ve never told him. Sure, we could write a few lines of code which directly fetches the ID using something among
$post->postID, but this would force a developer to write additional code. Instead we just implemented a few methods on the
DatabaseObject which tells anyone how it’s database table is called, what’s his primary index name (e.g.
postID).
Now take a look at the (working!) implementation of
EventListenerEditor and you will realize that you will waste most of your time writing comments
|
PHP Source code
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
namespace wcf\data\event\listener;
use wcf\data\DatabaseObjectEditor;
/**
* (stripped the comment)
*/
class EventListenerEditor extends DatabaseObjectEditor {
/**
* @see wcf\data\DatabaseObjectDecorator::$baseClass
*/
protected static $baseClass = 'wcf\data\event\listener\EventListener';
}
|
This works because we already told the
DatabaseObject everything we need to know about our table. Sounds like you have to write tons of code for the original object? You’re wrong again, take a look at the
EventListener class:
|
PHP Source code
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
namespace wcf\data\event\listener;
use wcf\data\DatabaseObject;
/**
* (stripped the comment)
*/
class EventListener extends DatabaseObject {
/**
* @see wcf\data\DatabaseObject::$databaseTableName
*/
protected static $databaseTableName = 'event_listener';
/**
* @see wcf\data\DatabaseObject::$databaseTableIndexName
*/
protected static $databaseTableIndexName = 'listenerID';
}
|