All relationships are stored in a relationships metadata array:
protected static $_relationships = array();
Each key in this array should be the name of a relationship. The values should be arrays describing the relationship:
protected static $_relationships = array( 'Template' => array( ... ), 'Authors' => array( ... ) );
The relationship names are used for accessing the related data. They must be uppercased and valid php variable names:
// as declared above $template = $my_model->Template; $authors = $my_model->Authors;
The array describing each relationship contains the information that allows ExpressionEngine to correctly identify the related data. By default, only the the relationship type is required.
type describes how two items are related. There are four relationship types:
These are declared by name:
protected static $_relationships = array( 'Template' => array( 'type' => 'BelongsTo' ) );
When figuring out how two items are related, consider how you would talk about them in plain english. For example, a Template Group has many Templates, but a Template belongs to a Template Group.
model declares the shortname of the model you are relating to. This is optional and will default to the relationship name:
protected static $_relationships = array( 'Authors' => array( 'type' => 'hasMany', 'model' => 'ee:Member' ) );
To specify which fields to use when matching up two models, you can specify a
from_key for the current model and a
to_key for the model being related:
protected static $_relationships = array( 'Authors' => array( 'type' => 'hasMany', 'model' => 'ee:Member' 'from_key' => 'author_id', 'to_key' => 'member_id' ) );
The keys are optional. ExpressionEngine will attempt to divine the correct columns to use based on the type of relationship and primary key names. For example, if a Comment
belongsTo an Entry, and the entry has a primary key called
entry_id, ExpressionEngine will look for a field called
entry_id in the comment. The following table describes these automatic assumptions:
|Type||Default from_key||Default to_key|
|HasOne||This primary key name||This primary key|
|HasMany||This primary key name||This primary key|
|BelongsTo||Related primary key name||Related primary key name|
|HasAndBelongsToMany||This primary key name||Related primary key name|
When a model
belongsTo another model, deleting the parent model will trigger a deletion of the child model. This is in line with the human expectation of how these types of relationships work.
If you wish to disable this behavior, you can specify the relationship as
weak. A weak relationship will zero out the foreign key column on deletion, but it will not cascade the delete:
protected static $_relationships = array( 'LastAuthor' => array( 'type' => 'belongsTo', 'model' => 'ee:Member' 'from_key' => 'author_id' 'weak' => TRUE ) );
When dealing with HasAndBelongsToMany relationships you will need to declare a pivot table that contains the relationship information:
'pivot' => 'mytable'
By default the to_key and from_key are used to determine pivot table column names. If your table uses a different name for the pivot columns, you can specify them individually:
'pivot' => array( 'table' => 'mytable', 'left' => 'some_key', 'right' => 'another_key' );
left describes the pivot table key connecting the current model and
right describes the key connecting the pivot table to the related model. Picture it like a row of dominoes with the pivot in the center:
All relationships must be declared in both associated models. This improves code consistency and predictability by allowing both sides of the relationship to be altered without creating orphaned objects. This is particularly important when creating parent-child relationships that cascade their deletions automatically.
When relating to models that are not your own, this becomes problematic since your addon cannot directly add relationships to native models. To get around this problem and to allow for native events to cascade to your models, you must declare all external dependencies in your
'models.dependencies' => array( 'MyModel' => array( 'ee:Member' ) ),
You can then declare the relationship as normal, but with the addition of an
inverse key describing how it will behave on the other model:
'Author' => array( 'type' => 'belongsTo', 'from_key' => 'author_id', 'to_key' => 'member_id', 'model' => 'ee:Member', 'weak' => TRUE, 'inverse' => array( 'name' => 'AuthoredMyModels', 'type' => 'hasMany' ) )
The inverse key is not guaranteed to be unique across all addons, so it is automatically prefixed with your prefix. In order to access the
AuthoredMyModels relationship on a member object, we must first alias it to a valid value:
$member = ee('Model')->get('Member')->first(); $member->alias('mymodel:AuthoredMyModels', 'Lastauthored'); $last_authored = $member->Lastauthored;
Caution: Aliases are mutable, you should reassign them before use if your code has shared access to the object.