Nov 21
I’m regularly thinking about how to represent data in a relational database in OO PHP5 that doesn’t make me walk away feeling like i’ve just created something that smells bad.
The key thing for me is that my code should not care that the data is coming from a relational database. This poses one or two issues.
- In a relational database, data typically has other ‘meta’ data associated with it. Id’s, timestamps and other snippets of information that are not strictly part of what my object is trying to represent.
- If my object is not aware of how it should serialise itself, who is?
This of course isn’t a new problem. My language of choice (currently PHP5) has many ORM libraries available to it – Doctrine, Propel and more – most (or all) of which are loosely based around the Active Record design pattern.
My only problem with these frameworks is that they seem to do too much ‘magic’ for me (and I like to retain at least some control over what’s happening between my app and the database). Of course, it could also be that I have either not invested enough time in learning to use one of them to it’s maximum potential.
Despite that, the Active Record pattern appears to be quite a satisfactory way of creating that link between my application, and how it’s storing it’s data. My core objects can exist how I want them to, and their ‘datastore’ can be represented by an active record object (who’s attributes are exactly the same as the columns in the database) on the class itself. It gives me the degree of separation that i’ve been looking for.
However there’s still a piece missing. My core class still has to contain the relevant logic to load it’s associated active record. This suggests some static factory methods (I refer to my earlier comment on things that smell bad!), so i’m going to create a ‘Builder’ for my core object that’s concerned with marrying up the active record with the core object itself. Here’s how it looks (simplified) in a class diagram.

ActiveRecord class diagram
I’ve not closed the doors on Doctrine or Propel though, so it’ll be interesting so see just what an established ORM framework like Doctrine can do for me on top of this basic implementation.
Tagged with: orm • php
Nov 28
After lot’s of people spent a lot of time at work refactoring bad/old code after Alistair Darling announced that VAT would be reduced to 15% instead of 17.5% (and that people needed to ‘contact their software vendors to update the VAT field… riiight), I thought i’d stub out my own design for handling Price and Tax (whether it’s VAT or not shouldn’t really matter). Here’s a start. It follows the idea that where possible, a class should be immutable. Don’t modify an existing cost, create a new one and return that. Anyway – here’s the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| class Price
{
protected $value = 0;
protected $currency = null;
public function __construct($value, $currency = 'GBP')
{
$this->value = $value;
$this->currency = $currency;
}
public function getValue()
{
return $this->value;
}
public function getCurrency()
{
return $this->currency;
}
public function __toString()
{
return "{$this->value}";
}
} |
That’s all you should need for the price. Think about the money in your pocket – it has two property’s. It has a value, and it has a currency. I cannot change either without spending it (or converting it at a bureau de change), but then I would get a set of new coins in return. It has no concept of whether or not it is inclusive or exclusive of tax. Thats up to something else…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| class TaxMan
{
protected static $vat = array(
'GBP' => 15.0
);
protected $currency = '';
public function __construct($currency)
{
if(array_key_exists($currency, self::$vat)) {
$this->currency = $currency;
} else {
throw new Exception('Cannot build a TaxMan for this currency');
}
}
public function getVat(Price $price)
{
return new Price(($price->getValue() * (self::$vat[$this->currency]) / 100), $this->currency);
}
} |
So we can pass in a price object and get a new value representing how much vat should be added… Something like this.
1
2
3
4
5
| $price = new Price(8.00);
$taxman = new TaxMan('GBP');
$vat = $taxman->getVat($price);
$total = new Price($price->getValue() + $vat->getValue(), $price->getCurrency()); |
This is not completely finished however (and I may come back to it to complete it), as it’s completely possible for multiple different tax levels within a currency (Currency can be used in multiple countries, or different products have varying levels of VAT associated with them). This will solve some of the problem – but there’s more work to be done.
Tagged with: php