The only possible solution I can think of is to wrap ResultSet and your desire models.
In Product::find()
, don't return the result of parent::find()
. Instead, store it in a variable and pass it to a new object, along with the discriminator information:
$results = parent::find();
return new MultiTypeResultSet(
$results, // Original result set
'product_type', // Discriminator column
[ // map of value to class
'physical' =>'Namespace\For\Product\Physical',
'downloadable' =>'Namespace\For\Product\Downloadable'
]
);
You could probably even abstract that out a little more and put that type of info in initialize()
.
I believe it has to be done this way because Phalcon will return \Phalcon\Mvc\Model\Resultset and there's nothing we can do to change that so we can't properly extend, only wrap.
MultiTypeResultSet can then define magic __call()
and __callStatic()
methods that simply call the requested method on the ResultSet. The real magic is done by overriding current()
. In that method, you call parent::current(), but then check the value of the passed discriminator column - product_type
- and create a new model object based on the mapping that was passed. This will, unfortunately, require 2 queries - one to get the original Product model, another to get the Physical or Downloadable model. Alternatively, you could write code in Physical and Downloadable to import values from a passed Product object, into themselves.
It's a bit dirty, but I think the concept is functional at least.