I just started reading cakephp 3 docs (I have been developing with cake 2.x for some time) and want to migrate some website from 2.x to 3. In cake 2 in my AppModel I have some callbacks, particularly beforeFind and beforeSave, that contain some logic concerning almost all tables in a database.
Now in cake 3 there is no AppModel, how do I get the same thing done ? The best I can think of is to put that code in some behavior's callbacks, but I have like 30 models, should I load the behavior in all models one by one ?
Thanks
You can also create an AppTable in your src/Model/Table Folder:
namespace App\Model\Table;
use Cake\ORM\Table;
class AppTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->addBehavior('myBehavior');
$this->addBehavior('myBehavior2');
$this->addBehavior('myBehavior3');
}
}
And then extends your Table class by AppTable:
namespace App\Model\Table;
use App\Model\Table\AppTable;
class ArticlesTable extends AppTable
{
}
Use an event listener that listens to the events Model.beforeSave, Model.beforeFind and Model.initialize and apply whatever you want to do there. Read the chapter about events and the documentation for table callbacks.
use Cake\Event\EventListenerInterface;
use Cake\Event\Event;
class SomeListener implements EventListenerInterface
{
public function implementedEvents()
{
return [
'Model.beforeFind' => 'beforeFind',
];
}
public function beforeFind(Event $event, Query $query, ArrayObject $options, boolean $primary)
{
// Your code here
}
}
And attach it to the global event manager. It will now listen to the callbacks of all table object.
Related
I've created a custom behavior on my CakePHP3 project and I would like to insert data on db from this behavior
Here is an clean exemple of my behavior, the function is well called and save of the form but the ADD Articles request doesn't work...
<?php
namespace App\Model\Behavior;
use Cake\ORM\Table;
use Cake\Event\Event;
use Cake\Core\Configure;
use Cake\I18n\I18n;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use Cake\ORM\TableRegistry;
use Cake\Utility\Inflector;
use App\Controller\AppController;
class HistorizeBehavior extends Behavior
{
public function beforeSave(Event $event, Entity $entity)
{
$this->historize($event, $entity);
}
public function historize(Event $event, Entity $entity) {
$articlesTable = TableRegistry::getTableLocator()->get('Articles');
$article = $articlesTable->newEntity();
$article->title = 'A New Article';
$article->body = 'This is the body of the article';
$articlesTable->save($article);
}
}
There is no error, no warning...but the data isn't saved..
Any idea why ?
Thanks
because my component, controller and model has the same name:
<?php
namespace Plug\Controller;
use Plug\Controller\AppController;
class SettingController extends AppController
{
public function initialize(){
parent::initialize();
$this->loadModel('Setting');
$this->loadComponent('Plug.Setting');
}
How do I know how to refer to component or model ?
Check the manual, almost everything is there. Please consider checking the documentation, it's there to be read.
Aliasing Components
One common setting to use is the className option, which allows you to alias components. This feature is useful when you want to replace $this->Auth or another common Component reference with a custom implementation:
// src/Controller/PostsController.php
class PostsController extends AppController
{
public function initialize()
{
$this->loadComponent('Auth', [
'className' => 'MyAuth'
]);
}
}
// src/Controller/Component/MyAuthComponent.php
use Cake\Controller\Component\AuthComponent;
class MyAuthComponent extends AuthComponent
{
// Add your code to override the core AuthComponent
}
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" ?
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.
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'
}
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:
Rename my entity into JobProfit.php
Update my Table class with $this->setEntityClass('JobProfits')
My Code tries to fetch all Main categories of the posts into Appcontroller to show on the homepage:
namespace App\Controller;
use Cake\Core\App;
use Cake\Controller\Controller;
class AppController extends Controller
{
public $helpers = ['Html', 'Form', 'Session','Time','Tree'];
public function initialize()
{
parent::initialize();
$this->loadComponent('Flash');
$this->maincategories();
}
function maincategories(){
App::import('Controller','Postcategories');
$postcates = new PostcategoriesController;
$postcates = $postcategory->find('threaded');
}
}
Your maincategories() method is wrong. You need the model, not the controller to retrieve the data from. You need to use TableRegistry::get('Postcategories') to get the Postcategories model and then call the find on that:-
public function maincategories()
{
$Postcategories = TableRegistry::get('Postcategories');
$this->set('postcategories', $Postcategories->find('threaded'));
}
$this->set() is setting the categories as a view variable ($postcategories). You will need to make sure you include use Cake\ORM\TableRegistry; at the top of your AppController file.
Make sure you've fully read the docs on retrieving data.
I've got a problem overhere with my newest CakePHP application.
I've made a model and controller for Categories.
Model: Categorie.php
class Categorie extends AppModel{
public $name = 'Categorie';
}
Controller: CategoriesController.php
class CategoriesController extends AppController {
public function index(){
$this->set('list', $this->Categorie->find('all'));
}
}
But when I visit the page I get the error:
Fatal error: Call to a member function find() on a non-object
When I add
$this->loadModel('Categorie');
to the index-function in my controller it will work.
So I guess the connection between the model and controller is not working but I'm not sure and I don't know how to fix this.
Please help me out.
thnx
CakePHP uses the controller names singular variant for matching the model, and the singular of categories is category, not categorie.
As #ndm said, you should use CakePHP conventions.
Your table should be called categories, then your model should look like this:
class Category extends AppModel{
}
And then you can include it with:
$this->loadModel('Category');
On CategoriesController you can use it like this:
class CategoriesController extends AppController {
public function index(){
$this->set('list', $this->Category->find('all'));
}
}
If you want to name your table otherwise, you can make use of $useTable variable in controller to specify the name of the table the model will work with.
You could also make use of the controller's $uses property:
public $uses = array('Categorie');