0

I have a question about Cake's bake for policies on models/entities named with underscore_names.

I have an app the uses Authentication and Authorization middleware, but baking the authorization policies for entities and tables on models with two_word names doesn't generate the correct code (it seems to me).

I'll try to simplify the question with a basic example I created within my app to reproduce the problem:

  1. First, I'm using: CAKE_VERSION: 4.2.5, cakephp/authentication: 2.0, cakephp/authorization: 2.0, php: >=7.2, (also, I'm running XAMPP on windows 10)

  2. I created these two simple models within my app to demonstrate the issue:

CREATE TABLE `dogs` (
  `id` int(11) NOT NULL,
  `name` varchar(16) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=tis620;

AND

CREATE TABLE `dog_traits` (
  `id` int(11) NOT NULL,
  `dog_id` int(11) NOT NULL,
  `trait` varchar(128) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=tis620;
  1. I baked everything for these two models:
bin\cake bake all dogs
bin\cake bake policy --type entity dog
bin\cake bake policy --type table dogs

AND

bin\cake bake all dog_traits
bin\cake bake policy --type entity dog_trait
bin\cake bake policy --type table dog_traits
  1. For the Dogs model, everything works as expected. The Dog policy looks like this:
declare(strict_types=1);

namespace App\Policy;

use App\Model\Entity\dog;
use Authorization\IdentityInterface;

class dogPolicy
{
    /**
     * Check if $user can create dog
     *
     * @param Authorization\IdentityInterface $user The user.
     * @param App\Model\Entity\dog $dog
     * @return bool
     */
    public function canCreate(IdentityInterface $user, dog $dog)
    {   
        if ($user) {
            return true;
        }
        return false;       
    }
    // Etc....
}

Then in the Dogs controller:

    public function add()
    {
        $dog = $this->Dogs->newEmptyEntity();
        
        $this->Authorization->authorize($dog, 'create');
        
        if ($this->request->is('post')) {
        
        //Etc....

This works as expected, no problem.

  1. However, for all my models that have underscored names, (such as dog_traits), the baked policy doesn't seem to work properly. Here is what the default baked DogTraitPolicy.php looks like:
declare(strict_types=1);

namespace App\Policy;

use App\Model\Entity\dog_trait;
use Authorization\IdentityInterface;

class dog_traitPolicy
{
    /**
     * Check if $user can create dog_trait
     *
     * @param Authorization\IdentityInterface $user The user.
     * @param App\Model\Entity\dog_trait $dogTrait
     * @return bool
     */
    public function canCreate(IdentityInterface $user, dog_trait $dogTrait)
    {
        if ($user) {
            return true;
        }
        return false;  
    }
    //ETC....
}

Then in DogTraits Controller:

    public function add()
    {
        $dogTrait = $this->DogTraits->newEmptyEntity();
        
        $this->Authorization->authorize($dogTrait, 'create');
        
        if ($this->request->is('post')) {

        //Etc....

So now the URL http://localhost/myapp/dog-traits/add throws the error: Policy for App\Model\Entity\DogTrait has not been defined.

If I go back to DogTraitPolicy.php and change the class name to class dogTraitPolicy (camelcased rather than underscored), the I get the error: Argument 2 passed to App\Policy\dogTraitPolicy::canCreate() must be an instance of App\Model\Entity\dog_trait, instance of App\Model\Entity\DogTrait given, called in C:\xampp\htdocs\myapp\vendor\cakephp\authorization\src\AuthorizationService.php on line 93

If I change the canCreate method to this (notice the camelcased argument name):

    public function canCreate(IdentityInterface $user, dogTrait $dogTrait)
    {
        if ($user) {
            return true;
        }
        return false;  
    } 

Then this returns the error: Argument 2 passed to App\Policy\dogTraitPolicy::canCreate() must be an instance of App\Policy\dogTrait, instance of App\Model\Entity\DogTrait given, called in C:\xampp\htdocs\myapp\vendor\cakephp\authorization\src\AuthorizationService.php on line 93

If I then remove the argument name dogTrait before $dogTrait, then the policy authorizes as expected.

    public function canCreate(IdentityInterface $user, $dogTrait)
    {
        if ($user) {
            return true;
        }
        return false;  
    }

So the question is: Is entity policy bake working correctly for underscored model names? It works correctly out of the box for singleword models, but doesn't for underscored_names. Am I missing something?

Thanks in advance for any advice.

dividedbyzero
  • 181
  • 2
  • 13
  • Start over and stick to the [**naming conventions**](https://book.cakephp.org/4/en/intro/conventions.html), that is words in classnames start with and are separated by uppercase characters, not underscores, eg bake for `Dog`, `Dogs`, `DogTrait`, and `DogTraits`, these names will properly map to the underscored database table names. – ndm Apr 29 '21 at 13:36
  • Thanks ndm... I was baking with underscored database table names. Resetting and re-baking with the CamelCased class names works for both the cases in my issue. Thanks! – dividedbyzero Apr 29 '21 at 14:16
  • Just an observation here... if you bake 'all' (for models, controllers, etc.) using the raw table_name, then bake creates all those classes with the conventional class names automatically, correctly cased. But baking policies doesn't do that automatically, so one should bake with the planned class names correctly cased. Anyway... all good and thanks again. – dividedbyzero Apr 30 '21 at 08:38

1 Answers1

1

Use bake commands with 'cased' class names instead of underscored table names, eg:

bin\cake bake all DogTraits
bin\cake bake policy --type entity DogTrait
bin\cake bake policy --type table DogTraits
dividedbyzero
  • 181
  • 2
  • 13