How to pass current user ID to buildRules method of CakePHP model

246 Views Asked by At

I use AuthComponent with CakePHP 3.8 and now I need to do some logic in Model buildRules method but for this I need to get the current user ID. Is there any way to pass/retrieve it without using hacks such as accessing directly from the session. I know that it is possible to pass id via validator from controller as described in CakePHP's documentation https://book.cakephp.org/3/en/core-libraries/validation.html#using-custom-validation-rules

And it works for validation, however, I am unable to access the validator from the inside of build rules.

When I do as described in here, I get an empty object. https://book.cakephp.org/3/en/orm/validation.html#using-validation-as-application-rules

It seems that I am able to attach new validation rules but unable to retrieve the "Passed" provider to get the User ID.

It seems a trivial thing but a I spent quite a few hours trying to get the id in a proper way.

2

There are 2 best solutions below

5
On

The proper way to handle this is usually using either events, or saving options.

For example to make the ID available for the application rules of all tables, you could do something like this:

$this->getEventManager()->on('Model.beforeRules', function (
    \Cake\Event\Event $event,
    \Cake\Datasource\EntityInterface $entity,
    \ArrayObject $options
) {
    $options['current_user'] = $this->Auth->user('id');
});

It would be available in the $options argument of the rule accordingly, ie as $options['current_user'].

For a specific save operation you can pass it to the options of the save() call:

$this->ExampleModel->save($entity, [
    'current_user' => $this->Auth->user('id')
]);

There's also plugins that can help you with it, for example muffin/footprint.

0
On

OK, After working a bit more, I found how to retrieve user_id inside build rules. Might be helpful to someone.

Do this in the controller

         $this->ExampleModel->validator('default')->provider('passed', [
            'current_user' => $this->Auth->user('id')
         ]);

And then put this in you buildRules method

public function buildRules(RulesChecker $rules)
{
    $user_id = $this->validator('default')->provider('passed')['current_user'];
    $rules->add(
       function ($entity, $options) use($user_id) {

         //return boolean for pass or fail
        },
        'ruleName',
        [
          'errorField' => 'some_id',
          'message' => 'Some ID field is inconsistent with App logic.'
        ]
    );

    return $rules;
}