How Recess Solves Common PHP/MySQL Issues

Justin Carmony wrote a great article titled 'PHP Design - Biggest Database Oversights'. The article points out 5 naive PHP/MySQL design decisions that will come back to haunt projects if they've been made. As I'm getting closer to the public preview release of the Recess! Framework this article discusses how Recess! addresses some of the most common oversights in database development.

Re: Oversight #1 - No Data Access Layer

Quality software design and engineering is all about abstracting away details and finding the proper layers of functionality. As Justin points out, if there is no layer of abstraction which wraps data access code then low-level data access code will appear everywhere. PHP projects which interleave data connections and queries throughout their code are difficult to maintain.

The database stack in Recess! has four major components: 1) SQL statement builder, 2) Data Sources, 3) Data Sets, 4) Object-Relational Mapped Models. The notion of a 'data access layer' is taken care of by Data Sources. Data sources wrap properly around PDO and introduce new methods beyond PDO's, for example: getTables and getColumns($table). The implementation of these methods is specific to the RDBMS so Recess! also has the notion of a vendor specific driver called a DataSourceProvider. Currently Sqlite and MySql are supported.

Re: Oversight #2 - Design for Only One Database Connection

Small, greenfield projects often start out with a single database. This leads to naive data access layers which only support connections to a single database. Recess! supports multiple, named Data Sources. Instead of using a singleton pattern it uses a registry to store the Data Sources by name.

Having named Data Sources in an application gets really powerful at higher layers of abstraction, such as at the ORM layer, where we can mark-up a model with a single annotation to define which Data Source the model is persisted in.

Re: Oversight #3 - No Developer Logging

This isn't as fully fleshed out yet as I'd like but the plans and hooks are in place to be able to log queries, their stack traces, as well as their EXPLAIN'ed strategies for execution in the RDBMS. In Recess! there is a distinct difference between Development mode and Production mode. Sql logging will be a toggle option on by default in development and off by default in production.

Re: Oversight #4 - Queries Written in Procedural Processes

My dislike of queries being written in procedural code may run even deeper than Justin's! Recess! abdicates SQL string manipulation to a low-level SqlBuilder class. An instance of SqlBuilder allows SQL query strings to be built incrementally using chained method calls. Let's take a look at some examples:

$sqlBuilder = new SqlBuilder();

$sql = $sqlBuilder





// $sql is now:

// 'SELECT people.*

// WHERE = :people_name

// ORDER BY people.age

$args = $sqlBuilder->getPdoArguments();

// $args is now array( 'people_name' => 'Kris' );

// Let's add another criterion

$sql = $sqlBuilder->equal('home_city', 'Charlotte')->toSql();

// $sql is now:

// SELECT people.*

// WHERE LIKE :people_name

// AND people.home_city = :people_home_city

// ORDER BY people.age

$args = $sqlBuilder->getPdoArguments();

// $args is now array(

// 'people_name' => 'Kris',

// 'people_home_city' => 'Charlotte' );

SqlBuilder can do more complex things like joins, as well as inserts, updates, and deletes. Recess! users, though, will likely never use SqlBuilder because it's still too low level of an abstraction. Internally, however, having the ability to incrementally construct query strings has made the framework code quite pretty.

Here's code at the level of abstraction Recess! developers can expect to write:

class Person extends Model { }

$person = new Person();

$person->name = 'Kris';

$person->homeCity = 'Charlotte';

$people = $person->find()->orderBy('name');

foreach($people as $person) {

echo $person->name, ' ', $person->age, '<br />';


This example just scrapes the surface of Recess! object-relational mapping. Relationships, CRUDS, cascading deletes, etc. are all handled as well. In a future post I'll step through the data access stack's capabilities in more detail. Needless to say, in Recess! queries won't be mixed with procedural code!

Re: Oversight #5 - No Separation of Reads and Writes

Once projects outgrow a single server RDBMS the next step is often to do a Master/Slave setup in MySQL. In a Master/Slave setup expensive and less frequent writes are channeled to the Master server while reads are channeled to the Slave server.

In Recess!, by using named data sources as described in #2, we can handle Data Sources on a per model basis. A natural extension of this is handling reads and writes independently on a per model basis. The pseudo-code below shows how this may look on a model:


* !Source master, For: Writes

* !Source (slave1, slave2, slave3), For: Reads

* !HasMany books


class Person extends Model {}


* !Source master

* !BelongsTo person


class Books extends Model {}

In a future post I'll describe the Recess! annotations system which will explain the constructs you're seeing in the DocComments. Recess! annotations give us a way of providing static metadata about a class and are built-in to the framework's core. Recess! annotations should be familiar to Java and .Net programmers who have used annotations.


So that's a quick look at how Recess! handles Justin Carmony's commonly made MySQL/PHP mistakes. These issues are abstracted away in the internals of Recess. If you're a PHP developer check out and sign-up to be notified when it is publicly released "very soon now".