Reputation: 1097
I have an Orders
and a Users
table, such that Orders
belongsTo
Users
.
I want users to be able to soft-delete their account, so I added a deleted field and modified the delete method. The user info is needed for administrative purposes, hence no hard deletes.
I also overrode the default finder of UsersTable
such that deleted users will not pop up in lists or as results of Users->get()
:
public function findAll(Query $query, array $options)
{
return $query->where(['Users.deleted' => false]);
}
I am satisfied with the way it works, mostly that I now cannot forget to exclude deleted users as the default finder already does the job.
The problem is I still want to include the user when it is contained from an order:
$order = $this->Orders->get($id, ['contain' => 'Users']);
And apparently when using contain() findAll()
is used, because this does not include the deleted user.
How can I still include the soft-deleted entities in a contain()
?
Is it possible to set a different default finder for contains?
Upvotes: 1
Views: 1422
Reputation: 60493
You can for example use the finder
option for contain to specify which finder to use, like:
$this->Orders->get($id, [
'contain' => [
'Users' => [
'finder' => 'withDeleted'
]
]
]);
or modify the query directly:
$this->Orders->get($id, [
'contain' => [
'Users' => function (\Cake\ORM\Query $query) {
return $query->find('withDeleted');
}
]
]);
See also Cookbook > Database Access & ORM > Query Builder > Passing Conditions to Contain
However any custom finder would circumvent your modified all
finder, which shows a flaw in your approach, once a query uses a different finder, and doesn't also explicitly use the all
finder, your conditions will not be applied, which you most likely wouldn't want to happen so easily.
A better approach would probably be to use the Model.beforeFind
event/callback. Here's a basic, rather strict example that uses an options approach:
public function beforeFind(\Cake\Event\Event $event, \Cake\ORM\Query $query, \ArrayObject $options)
{
if (!isset($options['findWithDeleted']) ||
$options['findWithDeleted'] !== true
) {
$query->where(['Users.deleted' => false]);
}
}
public function findWithDeleted(\Cake\ORM\Query $query, array $options)
{
return $query->applyOptions(['findWithDeleted' => true]);
}
This would ensure that only when the findWithDeleted
option is present, and set to true
, the condition would not be applied.
You might also want to have a look at plugins that can handle this, like for example https://github.com/usemuffin/trash.
Upvotes: 2