1

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

dav
  • 8,931
  • 15
  • 76
  • 140

2 Answers2

4

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
{

}
ndm
  • 59,784
  • 9
  • 71
  • 110
2

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.

floriank
  • 25,546
  • 9
  • 42
  • 66
  • thanks for the answer, I had read about the callbacks, now was reading the events section from the link above, I guess I got the idea and how to connect to global event manager, but where do I put this listener code ? should I create a file for this ? if so where and how to name it ? thanks – dav Oct 19 '15 at 21:53
  • Well, if you know how to access code *without* creating a new file I would like to know how to do this as well. :p Sure you have to create a file. Put them where ever you want and name it as you want. For example src/Event/Listener/FooListener.php. Then just instantiate it like in the books examples by using the namespace and attach it to the global manager in your bootstrap.php file. – floriank Oct 19 '15 at 21:56
  • have this in my bootstrap `require_once '../src/Event/Listener/FooListener.php'; $fl = new FooListener(); use Cake\Event\EventManager; EventManager::instance()->on($fl);` , the listener's content - as it is in the answer: getting error `Argument 1 passed to FooListener::beforeFind() must be an instance of Event, instance of Cake\Event\Event given` what im doing wrong ? thanks – dav Oct 19 '15 at 22:54
  • 1
    I *highly recommend* you to spend some time learning about namespaces in php. You don't need the `require` as well if you use them right. You need to use the `use` statement on top and make the correct `Event` class available within the namespace or use the absolute namespace in the methods signature. I've added the line to the example. However, namespaces are common for a few years now and with Cake3 using them finally as well you *really* should learn how to use them right. – floriank Oct 19 '15 at 23:08
  • I put the use statement for Query as well, the errors disappeared, there was also an error `Argument 4 passed to FooListener::beforeFind() must be an instance of boolean, boolean given` which I solved by removing the word `boolean` from the last param. Thanks for the recommendation, I have just general understanding(as you can see) will read about it for sure. But about the listener, when I want to debug/var_dump the $query in the `beforeFind` of the listener, to see how it looks like, php 30 seconds of execution time is being exceeded. – dav Oct 20 '15 at 08:58
  • Increase your execution time (and probably memory as well) or don't debug huge objects. :) – floriank Oct 20 '15 at 09:37
  • I do not think this is the case here: I am trying this on bookmarks tutorial's example http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/intro.html, as in the link, there are a few simple tables only and the action is a simple find query `$bookmarks = $this->Bookmarks->find('tagged', ['tags' => $tags ])->toArray();` – dav Oct 20 '15 at 10:04
  • if I am wrong and the reason is it is big object, how do I somehow see its content, in cake2 in callbacks I would easily debug the query data to see the information ? thanks – dav Oct 20 '15 at 10:55
  • thanks, got working, for other things will ask another question, only may I ask why `use App\Event\Listener\FooListener` instead of `require_once` not working ? it says `Error: Class 'App\Event\Listener\FooListener' not found`. – dav Oct 20 '15 at 19:31
  • Not sure what you're doing, I don't know your code, it should work. If your app loads this namespace (App\...) it should be autoloaded by the class loader. Double check your class name and for typos. – floriank Oct 20 '15 at 22:06