How to call a controller method from an action - cakephp

I'm new in CakepHP and I want to use a method (that returns a value) in an action in CakePHP 3. Sort of like this:
public function specify(){
if(isObject1){
// do something}
}
private isObject1($objname){
return true;
}
What is the right syntax?

CakePHP is PHP
The way to call a method from another method of the same class is the same as with any php project using objects - by using $this:
public function specify() {
$something = 'define this';
if($this->isObject1($something)) {
// do something
}
}
private function isObject1($objname) {
return true;
}
There's more info on how to use objects in The PHP manual.

The answer by #AD7six suggests adding a method within the controller which is not right if it is not going to be used as an action.
I think you should consider creating classes under vendor and including them in your controller and calling your class/method. The convention is vendor/$author/$package. You can either autoload them with composer or use a require call to include your file. If you don't want to create a class and just want to have functions, that can be done too.
Do take a look at cakephp's loading vendor files section.

Related

How can I call custom function from Model?

I'm using CakePHP3.0.5 and I'm just calling custom function from Model.
But it shows Unknown method error.
How can I call custom function from controller?
// Controller
class TopController extends AppController {
public function initialize() {
parent::initialize();
$this->loadModel('TopRawSql');
}
public function showTop(){
$data = TableRegistry::get('TopRawSql');
$data->getTest(); // Unknown method error occur
}
}
// Model
class TopRawSql extends Table {
public function getTest() {
return 'OK';
}
}
I tracked the error message and found following the code.
Does it mean, can't I use custom function name without 'find' prefix?
// vendor->cakephp->src->ORM->Table.php
public function __call($method, $args)
{
if ($this->_behaviors && $this->_behaviors->hasMethod($method)) {
return $this->_behaviors->call($method, $args);
}
if (preg_match('/^find(?:\w+)?By/', $method) > 0) {
return $this->_dynamicFinder($method, $args);
}
throw new \BadMethodCallException(
sprintf('Unknown method "%s"', $method)
);
}
Your table class name is wrong, all table classes must end in Table, ie TopRawSqlTable.
Given the wrong class name, I assume that the filename might be wrong too. And I don't know if you have the correct namespace set in the file, or any namespace at all since it's not shown in your question, but that needs to adhere to the conventions accordingly too, and would usually be App\Model\Table.
If the class for the requested alias cannot be found, then a generic instance of \Cake\ORM\Table will be used, which will then of course cause a failure as it won't have any of your custom code.
See also
Cookbook > CakePHP at a Glance > CakePHP Conventions > Model Conventions
Cookbook > Database Access & ORM > Table Objects
Cookbook > Configuration > Disabling Generic Tables
To answer your question, yes. The call() magic function is going to require every function within the body of a Model to be either a get* or set* function. But the code you quoted points you directly to the answer you're looking for: create a Behavior and call the function whatever you'd like.

CakePHP 3: Setting a variable in a Listener

Is it possible to set a variable from within a Listener. This is what I am trying accomplish:
I created a Blog plugin and because the Homepage will be complex I wanted to attach an event to beforeRender for the Pages controllers and then return a list of 200 items that can be 'consumed' in different views and elements(ie. /src/Template/Pages/display.ctp and /src/Template/Element/latest_blog_items.ctp)
So far I have created this
// Blog.config/bootstrap.php
<?php
$homepageListener = new HomepageListener();
EventManager::instance()->attach($homepageListener);
And in the same plugin
// Blog.src/Event/HomepageListener.php
<?php
namespace Blog\Event;
use Cake\Event\Event;
use Cake\Event\EventListenerInterface;
use Cake\Core\Configure;
use Cake\ORM\TableRegistry;
class HomepageListener implements EventListenerInterface {
public function implementedEvents() {
return [
'Controller.beforeRender' => 'getBlogItems',
];
}
public function getBlogItems(Event $event) {
if ($event->subject()->name == 'Pages') {
$fBlogItems = TableRegistry::get('Blog.BlogPosts')->find('all')->order(['BlogPosts.created' => 'desc'])->limit(200)->toArray();
// This works, but I didn't want to do it this way
Configure::write('fBlogItems', $fBlogItems);
// My desired solution would be creating a variable similar to what is done in Controllers
// ie. $this->set('fBlogItems', $fBlogItems);
}
}
}
I have not figure out how, if possible, I can set a variable (ie. $this->set('fBlogItems, $fBlogItems) and ensure it is available in my Template files.
Is this even possible or advisable?
Does it break MVC?
Is there a better way?
$event->subject() is your controller instance so just use $event->subject()->set().

Invoking cells directly from the controller

I am working with cakephp 3.1.7 and figuring out how to invoke view cells or retrieve cell data from the controller. I implemented basic cells with the help of cakephp docs and also http://josediazgonzalez.com/2014/03/20/view-cells/ document which is working fine. However, when I try to return cells directly from the controller I get the following error.
Error: Call to undefined method App\Controller\ProductsController::decorate()
This is what I have:
use Cake\View\Cell;
use Cake\ORM\TableRegistry;
class ProductupdateCell extends Cell
{
public function display($options = []){
if (!empty($options['displaylist'])) {
$this->set('productlist', $options['displaylist']);
return $this;
}else{
$category = $this->request->query['category'];
$this->loadModel('Products');
$query = $this->Products-> find()
-> where(['Products.category' => $category])
-> hydrate(false);
$productlist = $query->toArray();
$this->set('productlist',$productlist);
return $this;
}
}
}
In my controller,
<?php
class ProductsController extends Controller
{
use CellTrait;
public function view($id)
{
$products = $this->Products->findById($id);
$this->set('displaylist', $this->decorate('ProductupdateCell', $products));
}
}
Please correct me where I am going wrong. Is it efficient to use this to update my product list based on user input with ajax request? Can I selectively update the particular cell rendered in my view page? Is there any other method to update the cell directly. Please forgive me if this is a dumb question.
I am working with cakephp 3.1.7 and figuring out how to invoke view cells or retrieve cell data from the controller.
This is an architecturally wrong. They're supposed to be used from the view level.
If you want to have modular and abstracted controller logic either use the CRUD plugin. Or simply go for components. Components are packages of logic that are shared between controllers.
Error: Call to undefined method App\Controller\ProductsController::decorate()
There is no such method in the Controller, CellTrait nor the View class. I don't know from where you got that code, it's also not in the documentation of the cells.

CakePHP override plugin method

I'm using the CakeDC Tags plugin in my CakePHP project. I am using the TagCloudHelper to output a list of links but this helper isn't formatting the links the way I would like. Specifically the method _tagUrl($tag, $options) is generating links with named parameters instead of using the query string.
Instead of
$options['url'][$options['named']] = $tag[$options['tagModel']]['keyname'];
I get the desired behavior with the following change
$options['url']['?'][$options['named']] = $tag[$options['tagModel']]['keyname'];
what is the best practice way of overriding this method? Do I make another class that extends TagCloudHelper? How then would I tell CakePHP to use my class instead of the plugin's?
I was able to override the helper with my own
// app/View/Helper/MyTagCloudHelper.php
App::uses('TagCloudHelper', 'Tags.View/Helper');
class MyTagCloudHelper extends TagCloudHelper {
protected function _tagUrl($tag, $options) {
$options['url']['?'][$options['named']] = $tag[$options['tagModel']]['keyname'];
return $options['url'];
}
}
Then in the controller
public $helpers = array('TagCloud' => array('className'=>'MyTagCloud'));
the className option let's you alias the name of the helper

How can I get started with PHPUnit, where my class construct requires a preconfigured db connection?

I have a class that uses a lot of database internally, so I built the constructor with a $db handle that I am supposed to pass to it.
I am just getting started with PHPUnit, and I am not sure how I should go ahead and pass the database handle through setup.
// Test code
public function setUp(/*do I pass a database handle through here, using a reference? aka &$db*/){
$this->_acl = new acl;
}
// Construct from acl class
public function __construct(Zend_Db_Adapter_Abstract $db, $config = array()){
You would do it like this:
public class TestMyACL extends PHPUnit_Framework_TestCase {
protected $adapter;
protected $config;
protected $myACL;
protected function setUp() {
$this->adapter = // however you create a new ZendDbADapter
$this->config = // however you create a new config array
$this->myACL = new ACL($this->adapter, $this->config); // This is the System Under Test (SUT)
}
}
IMHO, you need to work on your naming conventions. See Zend Framework Naming Conventions, for a start. An example would be the underscore, look up variables in the link. Also class naming.
You can do normally without reference same as constructor because this method is simplest.

Resources