Cakephp 3 : How to insert data on db from a behavior - cakephp

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

Related

Cakephp 3 plugin Event

I have created a plugin called WdContactForm in cakephp3.
Inside a function of the plugin controller I need to send an email
But returns me this error:
Could not send email: Declaration of WdContactForm\Controller\AppController::beforeFilter() should be compatible with App\Controller\AppController::beforeFilter()
I have already read about adding:
use Cake\Event\Event;
I have already done it.
But I can't fix the problem
This is my controller inside plugin:
namespace WdContactForm\Controller;
use Cake\Event\Event;
use WdContactForm\Controller\AppController;
use Cake\Core\App;
use Cake\Utility\Security;
use Cake\Utility\Inflector;
use Cake\ORM\TableRegistry;
use Cake\Core\Configure;
use Cake\Mailer\Email;
class ContactFormsController extends AppController
{
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Admin');
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
//other functions
//...
}
public function send_email()
{
$email = new Email('default');
$email->from(['test#test.it' => 'My Site'])
->to('test#test.it')
->subject('About')
->send('My message');
}
}
And this is my AppController inside the plugin:
namespace WdContactForm\Controller;
use Cake\Event\Event;
use App\Controller\AppController as BaseController;
class AppController extends BaseController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
}
}
How can I fix it?

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" ?
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')

Cakephp 3 callbacks, behaviors for all models

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.

Respond as XML not working since cakePHP 3.1

I need to render an XML+XSL template in my application, and it used to work with cakePHP 3.0. I have made the switch to 3.1 recently and it has stopped working. The problem is that I was having a formatted view of my XML, while now I just get a plain string.
The migration guide says something about some changes in the RequestHandlerComponent, but nothing helpful (or maybe it's just me and I don't get the point :)).
This is my controller (it is exactly as it was with Cake3.0):
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Utility\Xml;
use Cake\Event\Event;
use Cake\Routing\Router;
use Cake\ORM\TableRegistry;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
use Cake\Network\Email\Email;
use Cake\Core\Configure;
use Cake\I18n\Time;
/**
* Invoices Controller
*
* #property App\Model\Table\InvoicesTable $Invoices
*/
class InvoicesController extends AppController
{
public $components = [
'Browser',
'Reorder11'
];
public $helpers = [
'Multiple'
];
public $paginate = [];
public function initialize()
{
parent::initialize();
$this->loadComponent('Paginator');
$this->loadComponent('RequestHandler');
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow(['demo']);
}
/*
* ... several other functions ...
*/
public function viewxml($id = null)
{
$this->viewBuilder()->layout('xml');
$invoice = $this->Invoices->myInvoice($id, $this->Auth->user('id'));
$this->RequestHandler->respondAs('xml');
$this->set('invoice', $invoice);
}
}
The xml.ctp layout, which is really simple
echo $this->fetch('content');
and the viewxml.ctp template just echoes the xml as a string.
How can I obtain the formatted XML+XSL again?
Try add: $this->response->header(['Content-type' => 'application/xml']);
I had the same error but my output was pdf
working 3.0.14 using this code:
$this->RequestHandler->respondAs("pdf");
$this->layout = 'pdf/default';
$this->view = 'pdf/report1_pdf';
for 3.1.x (this works if u save the file and open later, if you try to open it directly on browser its print the plain file content as a txt/html):
$this->viewBuilder()->layout('pdf/default');
$this->viewBuilder()->template('pdf/report1_pdf');
$this->RequestHandler->respondAs('pdf');
$this->response->header(['Content-type' => 'application/pdf']);

Cakephp3.0 I am calling Postcategories controller into Appcontroller and it is error " Call to undefined method Cake\Core\App::import() "

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.

Resources