I'm currently in requirements mode for an upcoming project that should prove to be pretty complex. The current active record/table gateway patterns just aren't going to cut it for the complex business logic that's approaching. I'm starting to lean towards the domain model approach which would increase the initial complexity of the design but allow for the flexibility for future changes and features. The issue is with where to put your business logic? Most of the rails and Zend framework examples show a more active record type pattern which means that the business logic is tied into the persistence storage layer.

For example...
$user = new User();
$user->salary = 100;
$user->updatePayroll();
$user->save();

This works well for smaller apps where your models are tied tightly to your database structure however in my case I'll need to add the application layer above an existing database structure that may have 5 tables per object. For the example above I've diagrammed a possible solution



In this example I've created a User and Company class. Each one holds it's own data and basic operations. There is no sql in these, no direct knowledge of the outside world. Each model has a corresponding Mapper class (data mapper pattern) that knows how to save, find, create and delete it's own model. On top of those layers will sit a service layer that handles the real business logic. The UserPayrollService deals specifically with managing payroll for a user. UserAuthService is strictly for authenticating and logging out a user. As more and more complexity is added such as the need to have a User as part of a workflow engine I can simply create a new service or modify an existing one to implement the new business logic. Some additional benefits are that you can show the diagrams to your stakeholders and they can see concrete evidence that you've captured their business requirements as well as having the components testable on an individual level.

here are some examples of how it could be used...


/**
* high level use case for an immediate login and update of salary
*/

$userAuth = new UserAuthService();

if($user = $userAuth->authorize($_request['email'], $_request['password'])) {
$payroll = new UserPayrollService($user);
$payroll->updateSalary(100000);
$currentPay = $user->getSalary();
// currentPay would now equal 100000
} else {
// auth fail
}



/**
* example of creating a new user
*/
$userMapper = new UserMapper();
if(!$userMapper->userExists($_request['email'])) {
$user = new User();
$user->email = $_request['email'];
$user->firstName = $_request['firstName']
$user->lastName = $_request['lastName']
$userMapper->save($user);
redirect('/home');
} else {
// user already exists
}


Anyone have any thoughts on this implementation? What has served you well?

Ready for More?

Follow Me @jimplush