Wile E. Genius
Wile E. Genius

Reputation: 185

How to extend entity classes with custom functions (business logic) in cakephp v3

In cakephp 3 (3.3.5, that is) I want to extend my entity classes with custom functions (business logic). For example:

namespace App\Model\Entity;

use Cake\ORM\Entity;

class Something extends Entity {
    public function isFoo() {
        return true;
    }
}

The corresponding table object looks like this:

namespace App\Model\Table;

use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\TableRegistry;
use App\Model\Entity\Something;   // produces an `unused import' warning

class SomethingsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);
        ...
    }

    ...
}

In the controller, I use this code to retrieve the entity from the database and call the custom function:

class SomeOtherController extends AppController {
    ...
    $this->loadModel('Somethings');
    $thing = $this->SomethingsTable->get($id);
    if ($thing->isFoo()) { ... }
    ...
}

However, this fails with a fatal error:

Error: Call to undefined method Cake\ORM\Entity::isFoo() 

Note, when I do a

<?= var_dump($thing,true); ?>

in the corresponding view, $thing is shown as of type Cake\ORM\Entity.

How can I change the table's get() function to return entities with the correct type "Something" ?

Upvotes: 1

Views: 2023

Answers (3)

user7695
user7695

Reputation: 35

This is an old post but I faced this issue today and the solution for me was slightly different. I was loading the model the right way, but my class name was not following naming conventions.

My Table: JobProfitsTable.php

My Entity: JobProfits.php (plural)

CakePhp is automatically looking for class named JobProfit.php (singular), and seems to fallback on Cake\ORM\Entity

So I had 2 options:

  1. Rename my entity into JobProfit.php
  2. Update my Table class with $this->setEntityClass('JobProfits')

Upvotes: 1

Tolga
Tolga

Reputation: 282

It should be:

$thing = $this->Somethings->get($id);

// not 
$thing = $this->SomethingsTable->get($id);

Thats why the Something entity is not used, but the default Entity class.

CakePHP autotables, since it can not find the SomethingsTableTable the default table class is used. Therefore also the default entity class is loaded. If your test method would contain a query to the db, there would have been an error thrown, saying that somethings_table does not exist.

Upvotes: 4

Holt
Holt

Reputation: 37626

The problem is probably here:

class SomeOtherController extends AppController {
    $this->loadModel('Somethings');
    $thing = $this->SomethingsTable->get($id); // <-- Here
    if ($thing->isFoo()) { ... }
}

Controller::loadModel does not set $this->SomethingsTable (which was probably set somewhere else in your code... ), but $this->Somethings, so this should be:

$this->loadModel('Somethings');
$thing = $this->Somethings->get($id);
if ($thing->isFoo()) { }

This code works, you do not need use App\Model\Entity\Something in SomethingsTable.php.

When trying to debug such thing, use debug() instead of var_dump:

Configure::write('debug', true); // If you are not already in debug mode
$this->loadModel('Somethings');
debug($this->Somethings);

Output:

object(App\Model\Table\SomethingsTable) {

    'registryAlias' => 'Somethings',
    'table' => 'somethings',
    'alias' => 'Somethings',
    'entityClass' => 'App\Model\Entity\Something', // Good!
    'associations' => [],
    'behaviors' => [],
    'defaultConnection' => 'default',
    'connectionName' => 'default'

}

Upvotes: 2

Related Questions