- Basic Concepts
- Models and Schemas
- Column Types
- Collections
- Filtering
- Groups
- Inverting Filters (not)
- Back references
- Advanced Filters
- Creating Your Own Filter
- Default Filters
- Relationships
- Data Decorators
- Data Storage and Typing
- Repositories
- Data Typing and Data Transforms
- Advanced Techniques
- Joins and Intersections
- Aggregates
- Model Events
- Custard Commands
- Updating DocBlock comments
- Migrating Schemas
- Common Patterns and Anti-Patterns
- Inter-Model Strategies
Inter-Model Strategy
The purpose of our model classes is to house all of our state changing application logic. However a change to a model may be a trigger for other models to change as well. Consider these examples:
- A
Transaction
is added to a ledger. TheAccount
balance needs to update. - A
User
password is changed. An entry into theLog
must be made. Stock
adjustments are made when stock is received in. Orders waiting on the stock must be flagged as awaiting despatch.- A
Stock
item is flagged as "Not For Sale". AllOrders
containing that stock must be marked "Held"
There are two types of inter model changes:
1. Updating 'children'
A model's children can be viewed as all other models related to this one as part of a one to many
relationship. For example an Invoice
model would have InvoiceLine
models as children as part of
the $Lines
property. A Customer
model would have Order
models as children as part of the
$Orders
property.
In these cases the best practice is for the model to manipulate it's children directly as we can assume a parent knows all about their children.
class Invoice extends Model
{
// ...
public function applyDiscount( $percentage )
{
foreach( $this->Lines as $line )
{
$line->applyDiscount( $percentage );
}
}
// ...
}
2. Updating a 'parent' or 'stranger'
A 'parent' is a model which can be navigated to through a one to one relationship. For example the
parent of an InvoiceLine
is an Invoice
.
An 'stranger' is a model which is not navigable from the model via a relationship.
For example the InvoiceLine
model has no relationship with the Address
model and so should not
control it directly.
In both cases the event should be handled by an external agent that is listening for the event being
raised on the ModelEventManager
. The best candidate for this agent is the application's
SolutionSchema
object where the models and relationships are registered.
class MyDatabaseSchema extends SolutionSchema
{
public function __construct()
{
parent::__construct( 0.1 );
$this->AddModel( "GoodsReceived", "My\App\Model\Contracts\GoodsReceived" );
$this->AddModel( "Contract", "My\App\Model\Contracts\Contract" );
ModelEventManager::AttachEventHandler( "GoodsReceived", "AfterSave", function( $goodsReceived )
{
// Update the contract totals as a goods received has been adjusted.
$goodsReceived->Contract->UpdateTotals();
});
}
}
The solution schema knows best how the models inter-relate and so can be seen as good choice of co-ordinator for inter-model events.