PHP – Applying DDD to a Simple App with a Configuration Twist

dependency-injectiondomain-driven-designentityPHP

I’m using the light-weight PHP Fat-Free Framework as a base to form a simple MVC based app with DDD philosophy for the Model layer. I’m aware that DDD is most suitable or enterprise solutions and that applying DDD to simple, mostly data-driven apps is kind of an overkill, but there are some concepts in DDD that I find appealing (like the Repository pattern, business logic in Entities, etc.) which I’d like to apply to my app.

Fat-Free Faramework has a Base class that represents the application (a Singleton) and the instance of Base holds a lot of useful tool methods and a registry of global framework variables (the hive) which is used, among other things, for configuration data.

As I’m writing my app, I find myself using a lot of Base class tools inside classes in the Model layer, and I’m a bit confused by how to reference the Base instance in those classes. Do I simply call Base:instance() inside model classes or do I inject it through the constructor as a dependency? Dependency injection seems like the proper way to do it, but since most of the app will depend on it, the whole reference passing through the constructor seems unnecessary. Also, how to pass for an example database config data to data persistance classes which is stored in the hive? Should it be passed by the Controllers when instantiating Repositories or called directly from the Repository (or Data Mapper)? I’m looking for a way which won’t fire back on me, so I’m looking for any insight or advice on this.

The second part of my problem is that I’m trying to write my app so that each Entity and business logic related to it is configurable from the Entity class. This is an idea inspired by Sails.js I’m still testing out, but for an example, I have a method getProperties() which returns an array of user-defined configuration data for each Entity property, e.g.:

'title' => array(
    'type' => 'text',
    'minLength' => 30,
    ...
)

or for associations:

'children' => array(
    'entity' => 'ChildClass',
    'relation' => 'oneToMany'
)

It might look a bit controversial, but I’ve tested business logic functionality and so far it works OK for me, and client code communicates with entities via usual get/set/other methods. The idea behind such configuration is to be able to automatically generate scaffolding/administration interface for each Entity, and configure Data Mappers and Repositories based on the related Entity’s getProperties() method.

What’s bugging me now is that if I want to have one place where this configuration data exists, I’d have to place some non-business-domain logic into the Entity, such as an exceptional database table name, whether a field requires a rich-text editor or not, whether a checkbox is checked by default, a certain field used as an Entity’s print identity in the admin web interface, etc.

I realise that the problem I have is a tradeoff between a clean model and the single-place configuration idea and that I’ll probably have to pollute the Entities by storing such non-business-domain data into the Entites, but I thought perhaps someone here might have an idea about how to approach this in a different, or better way?

Thanks for reading.

Best Answer

I feel you are mixing concerns here. Your entities should be exclusively about business logic; I can almost guarantee you that the minimum length of a title is not business logic (barring some very special business domains). Stuff about (initial) validation or how to render a field belongs in UI view models.
If you are unsure, find a business process that will behave differently when the minimum length of a title is not met.

I also find it odd that you would need to reference global configuration variables inside your business logic related entities. If that is indeed the case, then you are either missing concepts in your business model, or you are mixing infrastructural concerns with your model.

As for your dependency injection question: if you have e.g. repositories that need connection strings, then use constructor injection and use you IoC container to wire everything together. Don't take on static dependencies all over your code; it will seriously hamper any unit testing you may wish to undertake, it will couple a large portion of your codebase to an implementation detail and it will make baby Jezus cry.

As an aside: you've touched on this, but I want to stress this again: what you are describing is not DDD.
DDD is about making the discrepancy between how your code runs and how actual business processes run as small as possible. It is about modeling the domain of a company inside your code, using the same language that the business uses. And it is about recognizing that you'll need different models for different parts of the business, thus partitioning your application.
The patterns you describe are a means to an end; applying them without the core aspects of DDD is what is commonly referrer to as "DDD lite". Don't take this as me saying that you need to pursue DDD, but it's important to know the difference.