CakePHP 3 - How to load components - cakephp

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

Related

Extend Helper, use by original name

I have a helper we use in all our CakePHP apps that I am trying to extend to include an app-specific method. However, I'd like to refer to the helper by its original name.
e.g., instead of
$appSpecificHelperName->method()
I want to have my child class referred to by the base class name:
$helperName->method()
in the view.
Is there a way to do that? This is specifically in Cake 1.2, but the app will be upgraded to Cake 2 or possibly 3 next year, and I'd like to know the solution for any/all version(s).
Found the answer in the docs:
One common setting to use is the className option, which allows you to create aliased helpers in your views. This feature is useful when you want to replace $this->Html or another common Helper reference with a custom implementation:
// app/Controller/PostsController.php
class PostsController extends AppController {
public $helpers = array(
'Html' => array(
'className' => 'MyHtml'
)
);
}
// app/View/Helper/MyHtmlHelper.php
App::uses('HtmlHelper', 'View/Helper');
class MyHtmlHelper extends HtmlHelper {
// Add your code to override the core HtmlHelper
}

Cakephp 3 : How loadModel function defines globally?

I am new to cakephp3.I read http://book.cakephp.org/3.0/ and start developing small application using cakephp3.
I am using UserMastersController and I want to save and get data from person_masters table.For that each time I am using loadModel() or TabelRegistry::get(); methods in each function.
$this->loadModel('PersonMasters');
So, how can I define globally other models in cakephp3, so I should not define each time in each function ?
use the beforeFilter
I am using loadModel() or TabelRegistry::get(); methods in each function.
The simplest solution is to define the beforeFilter method in the relevant controller:
public function beforeFilter(Event $event)
{
$this->loadModel('PersonMasters');
parent::beforeFilter($event);
}
public function example()
{
$this->PersonMasters->find(); // no error
}
If you prefer, you could instead change the name of the default table class, which is set automatically to the name of the controller class - if it isn't already set. This is how the convention of "FoosController will use the Foos table class" is implemented. I.e. this would also work:
public function beforeFilter(Event $event)
{
$this->modelClass = 'PersonMasters';
parent::beforeFilter($event);
}
public function example()
{
$this->PersonMasters->find(); // no error
}
Though that's more indirect and probably more confusing for future readers of the code (e.g. you, next year, next week - or tomorrow =)).

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.

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

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.

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