How to add helper or component on-the-fly with the controller action method - cakephp

i don't want to add it as below cause i needed them only once in certain action method
(so do not useless load the memory)
class UsersController extends AppController {
var $name = 'Users';
var $helpers = array('Html', 'Session');
var $components = array('Session', 'Email');

class UsersController extends AppController {
public function method_name() {
$this->helpers[] = 'MyHelper'
}
}
More on this in the documentation.
Hope that helps.

You can load helpers using
$this->helpers[] = 'MyHelper';
as Rob mentioned above, but this won't work for controllers because they have their initialize and startup methods that need to be called in order for them to work.
I've come across a bit of code on the web for loading components inside of a controller action: ComponentLoaderComponent
Yes, it is a component but it isn't very big so it shouldn't be a problem to include it in your controllers.
Either that or you can just study it to see how the component loading works and then write your own controller action to do the same.

I use a component for adding helpers and components on the fly:
$this->Common->addHelper('Tools.Datetime');
$this->Common->addHelper(array('Text', 'Number', ...));
$this->Common->addComponent('RequestHandler');
$this->Common->addLib(array('MarkupLib'=>array('type'=>'php'), ...));
etc
The complete code to this can be seen in the cakephp enhancement ticket I just opened:
http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/1277
Or with php markup:
http://www.dereuromark.de/2010/11/10/loading-classes-on-the-fly/
It also fixes some minor problems with the solution posted by mtnorthrop.
Plugins as well as passed options are now possible. Have fun.

Related

CakePHP 3 - How to load components

In CakePHP 2 you could specify which components to load in the controller by providing a $components property.
class AppController extends Controller
{
public $components = [
'RequestHandler',
'Security'
];
}
I notice this still works in CakePHP 3 but that most of the book uses a new method in which you load every component separately:
public function initialize()
{
$this->loadComponent('RequestHandler');
$this->loadComponent('Security');
}
Is the $components property provided only for backwards compatibility? I want to do it the correct Cake 3 way, especially if the former method will be deprecated at some point in the future.
Are there any differences in functionality between the two methods?
If I try to configure the SecurityComponent like this, it doesn't work and the configuration seems to be completely ignored, even though it's a valid use of the method:
public function initialize()
{
$this->loadComponent('Security', ['blackHoleCallback', 'blackhole']);
}
Instead, I have to make a separate method call in beforeFilter() to set the configuration and get it to actually work:
public function initialize()
{
$this->loadComponent('Security');
}
public function beforeFilter(Event $event)
{
$this->Security->config('blackHoleCallback', 'blackhole');
}
However, the old 'Cake 2' way still works fine:
class AppController extends Controller
{
public $components = [
'RequestHandler',
'Security' => ['blackHoleCallback' => 'blackhole']
];
}
Is the $components property provided only for backwards compatibility? I want to do it the correct Cake 3 way, especially if the former method will be deprecated at some point in the future.
It's not yet deprecated as you can see here. But loading it via the method call is the better way of doing it. I guess the property is going to be dropped in 4.x and maybe deprecated in in a future version of 3.x.
Read these as well:
Should I or should I not use getter and setter methods?
Calling the variable property directly vs getter/setters - OOP Design

CakePHP update public $uses = false; in action from same Controller

I'm writing an installation script for my CakePHP web application. I have a InstallController with 6 actions: step1, step2, step3, etc.
At step1 I'm handling Config/database.php creation. Because this file is empty and no datasource is available I have to set public $uses = false; in the InstallController.
At step2 the Config/database.php file is set so I should be able to make a connection to the datasource. This is also necessary because I want to update some database fields in the following steps.
Is it possible to update the public $uses = false; in every following steps after step1?
I'm using CakePHP version 2.3.5
Have you considered loading the model within the actions? So, something like:
<?php
App::uses('AppController', 'Controller');
class InstallController extends AppController {
public $uses = false;
public function step1() {
}
public function step2() {
$this->loadModel("Install");
$this->Install->callMethod();
}
}
In CakePHP 2.x models are lazy loaded, so as long as your step1 action doesn't try to make use of a model, you can safely declare the models in your controllers $uses property, they are not being constructed until your code actually makes use of them.
However, if for some reason you'd actually need to modify $uses, well then just do it, as mentioned models are lazy loaded, so you can modify $uses whenever you want and then access the models afterwards via magic properties on the controller.

Multiple JS Engine Helpers cakephp 2.x

I have two plugins that both need to extend the JqueryEngineHelper.
I know that you can only specify one engine in AppController Helpers.
How can I extend the JqueryEngineHelper in both plugins? I have them both working but I cannot get them to work at the same time.
$helpers = ['Js'=>['MyPlugin.MyPluginJquery', 'MyPlugin2.MyPlugin2Jquery']];
I would like both to work, but unfortunately they do not. Only the first one is used.
Code from one of the engines
App::uses('AppHelper', 'View/Helper');
App::uses('JqueryEngineHelper', 'View/Helper');
class MrgCustomSelectJqueryEngineHelper extends JqueryEngineHelper{
function __construct(View $view, $settings = array()){
parent::__construct($view, $settings = array());
$this->_init_callbacks();
}
protected function _init_callbacks(){
$callbacks = [
'selectBoxIt'=>[]
];
$this->_callbackArguments = array_merge($this->_callbackArguments, $callbacks);
}
public function selectBoxIt($options = []){
$template = '%s.selectBoxIt({%s});';
return $this->_methodTemplate('selectBoxIt', $template, $options);
}
}
I think you're going to have to alter the plugins so that they don't conflict. Depending on how the plugins work, there may be different ways you can go about this:
Only load the version Js helper you need at the moment. Only works if you don't need both for a single controller action.
Change the plugins to refer to the different versions of Js helper by different names. This could possibly take a lot of search and replace.
If there are no conflicts between how the plugins extended Js helper, you can merge the two helpers.

CakePHP pages_controller always uses default layout

I have a static page that I want to serve so I made a .ctp in the /views/pages/ directory. The problem is that it's using the default layout which I do not want to use. I tried making my own pages_controller and passing the $layout var but that does not work. There has to be a way to tell a /pages/ to use another layout.ctp. No?
I was having a similar issue, thought i'd report my solution in case others are facing the same thing.
I wasn't using pages, but had a controller "members":
<?php
class MembersController extends AppController {
var $name = 'Members';
var $helpers = array('Html','Javascript','Form','Time');
var $uses = array();
function index() {
// Works, will load the ajax.ctp layout
// http://localhost/members/index
$this->layout = 'ajax';
}
function signup() {
// Does not work, loads the default.ctp layout
//http://localhost/members/signup
$this->layout = 'ajax';
}
}
?>
function index() was properly loading the ajax layout, but signup() kept loading default. Turns out the mistake was I did not have a view/signup.ctp. Once I added that it loaded the proper layout. Was an absentminded mistake but left me barking up the wrong tree because signs were pointing towards a layout issue rather than a view issue.
few things to check
make a custom pages_controller.php
define variable $layout and set it to the layout you want.
make sure the layout exists in
views/layout/
goes to the following link "lib\Cake\Controller" open CakeErrorController.php add your layout .
public function __construct($request = null, $response = null) {
parent::__construct($request, $response);
$this->constructClasses();
$this->Components->trigger('initialize', array(&$this));
$this->_set(array('cacheAction' => false, 'viewPath' => 'Errors'));
$this->layout='student';
}
I had this same issue and all errors were misleading.
What my problem ended up being is that I was trying to use a controller that didn't have a backing table/model so I was trying to reuse some other name in the controller's $name member variable because otherwise it would say that model didn't exist.
Long story short make sure that your controller name has a backing model object with the same naming convention.

Can I use one model inside of a different model in CakePHP?

Can I use another Model inside one model?
Eg.
<?php
class Form extends AppModel
{
var $name='Form';
var $helpers=array('Html','Ajax','Javascript','Form');
var $components = array( 'RequestHandler','Email');
function saveFormName($data)
{
$this->data['Form']['formname']=$data['Form']['formname'];
$this->saveField('name',$this->data['Form']['formname']);
}
function saveFieldname($data)
{
$this->data['Attribute']['fieldname']=$data['Attribute']['fieldname'];
}
}
?>
Old thread but I'm going to chime in because I believe the answers to be incomplete and lacking in "why". CakePHP has three ways to load models. Though only two methods work outside of a Controller, I'll mention all three. I'm not sure about version availability but this is core stuff so I believe they'll work.
App::import() only finds and require()s the file and you'll need to instantiate the class to use it. You can tell import() the type of class, the name and file path details.
ClassRegistry::init() loads the file, adds the instance to the object map and returns the instance. This is the better way to load something because it sets up "Cake" things as would happen if you loaded the class through normal means. You can also set an alias for the class name which I've found useful.
Controller::loadModel() uses ClassRegistry::init() as well as adds the Model as a property of the controller. It also allows $persistModel for model caching on future requests. This only works in a Controller and, if that's your situation, I'd use this method before the others.
You can create instances of other models from within any model/controller using one of these two methods.
If you're using Cake 1.2:
App::import('model','Attribute');
$attr = new Attribute();
$attr->save($dataYouWantToSavetoAttribute);
If you're using Cake 1.1:
loadModel('Attribute');
$attr = new Attribute();
$attr->save($dataYouWantToSavetoAttribute);
An obvious solution everyone missed is to create an association between two models, if appropriate. You can use it to be able to reference one model from inside another.
class Creation extends AppModel {
public $belongsTo = array(
'Inventor' => array(
'className' => 'Inventor',
'foreignKey' => 'inventor_id',
)
);
public function whoIsMyMaker() {
$this->Inventor->id = $this->field('inventor_id');
return $this->Inventor->field('name');
}
}
In CakePHP 1.2, it's better to use:
ClassRegistry::init('Attribute')->save($data);
This will do simply
<?php
class Form extends AppModel
{
//...
$another_model = ClassRegistry::init('AnotherModel');
//...
}
?>
In CakePHP 3 we may use TableRegistry::get(modelName)
use Cake\ORM\TableRegistry;
$itemsOb = TableRegistry::get('Items');
$items = $itemsOb->find("all");
debug($items);
If you want to use Model_B inside Model_A, add this line at the beginning of Model_A file:
App::uses('Model_B_ClassName', 'Model');
and then you will be able to use it inside Model_A. For example:
$Model_B = new Model_B_ClassName();
$result = $Model_B->findById($some_id);
var $uses = array('ModeloneName','ModeltwoName');
By using $uses property, you can use multiple models in controller instead of using loadModel('Model Name').
App::import('model','Attribute');
is way to use one model into other model. Best way will be to used association.

Resources