How Would You Implement This Design Pattern?

Hi all,

I’m struggling to get a design pattern implemented, and I’m curious if anyone can think of an elegant solution.

My app is designed for customers from different industries (lawyers, real estate agents, notaries…). All customers are stored in a table called Customer, which has a TINYINT column industry_id, containing the value of a constant to identify the industry of that specific customer. The other columns in the Customer table are not influenced by a customer’s industry.

Currently, several parts of my application contain industry-specific logic, using switch statements to loop through the different industries. For example, the method checkForCompetitors() is different, depending on the customer’s industry.

I’d like to get rid of these repetitions and dependencies by turning the Customer model into an abstract class, and making concrete classes such as LawyerCustomer, RealEstateCustomer, NotaryCustomer,… etc. My idea is to put the industry-specific logic into these concrete classes. Thus I could call $customer->checkForCompetitors() and be confident that the appropriate code is executed.

I guess I need some kind of abstract factory to create my customer objects. This factory would require an industry_id as its input parameter to determine the right class for the resulting Customer model. However, this poses a problem when loading a customer from the database, for which I do not know the industry in advance, since the industry_id is stored in the Customer table!

So my problem is: how can I combine the abstract factory approach with Yii’s find() and findOne() methods? My goal is that I could call Customer::findOne(5) and it would return an object of customer number 5 as a model of the class associated with this customer’s industry_id.

For example, if customer number 5 is a notary (as indicated by the industry_id column in the Customer table), a lookup using Customer::findOne(5) should return a model of class NotaryCustomer.

Does any of you have a decent solution for this? Obviously, the solution should not do any additional DB queries to determine the customer’s industry_id upfront.

Looking forward to your thoughts on this!

Single table inheritance. There is an example that fits your use case perfectly in the yii cookbook.

The example is for 1.1. I plan doing it for 2.0 cookbook as well but it’s not there yet.

Thanks for the replies: I wasn’t aware that this is the so-called single table inheritance.

Using your suggestions, I found that BaseActiveRecord has a static method instantiate($row) that I can override. The $row variable apparently contains the data from the DB row.

@samdark: looking forward to your book. Can I pre-order it somewhere?

It will be OpenSource one: https://github.com/samdark/yii2-cookbook/tree/master/book I’ll probably sell some hardcopies or PDFs when it will be ready.

Hi Sam,

Do you take pull requests for contributions?

I loved the first book and would like to contribute to this effort.

Yes, I do.