Reputation: 5100
I have this model:
Proforma
->hasMany('ItemProformas', ['foreignKey' => 'proforma_id']);
->belongsTo('Customers', ['foreignKey' => 'customer_id']);
->belongsTo('ProformaStates', ['foreignKey' => 'proforma_state_id']);
->hasMany('Invoices', ['foreignKey' => 'proforma_id']);
ItemProformas
->belongsTo('Proformas', ['foreignKey' => 'proforma_id', 'joinType' => 'INNER']);
->belongsTo('ItemDeliveryNotes', ['foreignKey' => 'item_delivery_note_id']);
ItemDeliveryNotes
->belongsTo('DeliveryNotes', ['foreignKey' => 'delivery_note_id', 'joinType' => 'INNER']);
->belongsTo('ItemOrders', ['foreignKey' => 'item_order_id']);
->belongsTo('ItemOrdersTypes', ['foreignKey' => 'item_orders_type_id']);
->belongsTo('Products', ['foreignKey' => 'product_id']);
Each ItemProforma
may have one ItemDeliveryNotes
, otherwise the foreign key will be null
. Here my paginate
call:
$this->paginate = [
'contain' => [
'Customers',
'ProformaStates',
'ItemProformas' => ['ItemDeliveryNotes' => ['DeliveryNotes']]
]
];
With this model, I get all the itemProforma
that have item_delivery_note_id
set. Instead I'm interesed to get them all, even if item_delivery_note_id
is null
.
I'm not sure if belongsTo
is correct here (I mean in ItemProformas
definition). But hasOne
implies it has one associated row, not may have one.
What is the correct syntax to retrieve all itemProformas
even if they don't have any ItemDeliveryNote
associated? But if they have, I need to retrieve the ItemDeliveryNote
object as well.
Upvotes: 0
Views: 323
Reputation: 60493
The association type depends on your schema. If the foreign key is in the source table, then it's belongsTo
, if the foreign key is in the target table, then it's hasOne
.
Whether a related record must exist primarily depends on the schema too, not on the type of association. If the foreign key is nullable, then the related record is optional. If and how you implement enforcing that constraint on application level is a different story.
That being said, ItemDeliveryNotes
and DeliveryNotes
are both belongsTo
that will use joins by default, so both associations will be joined into the same query, and since you've configured the DeliveryNotes
association to use an INNER
join, it will exclude rows where no DeliveryNotes
exist, which of course is also the case when no ItemDeliveryNotes
exist.
Assuming your schema is modeled correctly/properly, you could for example change your association config to use a LEFT
join by default in case applicable, or you could change the configuration for the containment on a per query basis (being it manually, or by using a custom finder):
$this->paginate = [
'contain' => [
'Customers',
'ProformaStates',
'ItemProformas' => [
'ItemDeliveryNotes' => [
'DeliveryNotes' => [
'joinType' => \Cake\Database\Query::JOIN_TYPE_LEFT,
],
],
],
],
];
Changing the fetching strategy for ItemDeliveryNotes
could work too (though it might be quite taxing depending on the amount of records), ie using the select
strategy instead of the join
strategy, then the associated ItemDeliveryNotes
records are being retrieved in a separate query, and thus won't affect retrieval of ItemProformas
:
$this->paginate = [
'contain' => [
'Customers',
'ProformaStates',
'ItemProformas' => [
'ItemDeliveryNotes' => [
'strategy' => \Cake\ORM\Association::STRATEGY_SELECT,
'DeliveryNotes',
],
],
],
];
Upvotes: 1