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.
Related
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.
I'm using the following code in my bootstrap.php (as explained here) to load models also from another folder:
App::build(array('Model' => array('/my/path/to/models')));
This seems to work. I have a model MyModel inside that folder, which I include in the controller I want to use it like usually:
var $uses = array('MyModel');
If I print App::objects('Model'), the model MyModel is shown in the list, so I assume it's loaded correctly. However, when I try to use the model (i.e. $this->MyModel->find() it never finds anything, it always returns an empty array.
Note that if I put the same exact model (MyModel) in the typical models folder (app/Model/) then it all works fine.
What am I missing to make this work?
EDIT
Ok, so it seems that the problem is in the connection to the database when the model is placed in that folder outside app. With the code shown above, Cake finds the model. However, when I do a find(), I get a missing table error for the datasource (default in this case).
Is it possible that the model isn't loading the correct database configuration because that configuration is inside the app/Config folder? How can I make that model load that configuration? If I have to put that configuration somewehre else (maybe in the same outside folder?) I can do that, but how do I tell the model to find it?
EDIT 2
I can see better what the problem is now. If I put a model in a different folder (other than app/Model) and use App::build() to set the path of that new folder, Cake finds it, there's no doubt (I use App::objects('Model') and the model is listed with all the other models from app/Model).
However, it's like Cake is not actually reading what's inside that model class, or at least not everything. It seems to read the $useDbConfig variable, but it ignores $useTable and any function I have defined in that model. Example of my model:
class Usuario extends AppModel {
var $name = 'Usuario';
var $primaryKey = 'id_usuario';
var $useDbConfig = 'BD_ControlAcceso';
function createTempPassword($len) {
//some code
}
}
If I do a $this->Usuario->find('all'), it returns all the records correctly. However, if I call $this->Usuario->createTempPassword(7) I get a Database Error.
I have another model (MyModel) in that same folder with a $useTable = 'mytable'. If I don a find() on it, I get an error saying that mytable table could not be found. However, if I do $this->MyModel->useTable = 'mytable' then it works fine.
How is this possible? What's going on here?
EDIT 3
I just want to add that I've done extensive testing and the issue is clear: Cake "knows" that the model is in the external folder (confirmed by printing App::objects('Model'), the model is listed there, and if I remove it from that folder then it's not listed). But even though it knows it's there, it ignores whatever is inside the model file. I've tried all the methods below to load the model but none of them worked. Is this a bug in CakePHP? If not, what am I doing wrong?
You should use App::uses('MyModel', 'Model') and is should go before the class declaration like so:
<?php
App::uses('MyModel', 'Model');
App::uses('AppController','Controller');
class UsersController extends AppController {
// controller class
}
Another thing to try is loading the model where you need it:
$this->loadModel('MyModel');
The other thing you can try is the Model instantiation in the top of your model class. Try updating your model to:
App::uses('AppModel','Model');
class Usuario extends AppModel {
var $name = 'Usuario';
var $primaryKey = 'id_usuario';
var $useDbConfig = 'BD_ControlAcceso';
function createTempPassword($len) {
//some code
}
}
I'm still trying to migrate from CakePHP 1.3 to 2.0
I have a Controller UsersController and its Model User.
The class User has some constants which I could easily access from the UsersController using User::constant. But for CakePHP 2.0 it doesn't work: I get an error saying the User class is not found. It works if I App::Import('Model', 'User');.
It sure has to do with their built-in lazy loading in 2.0!
you simple need to tell this file that it has other dependencies
do that at the very top of your UserController file:
<?php
App::uses('User', 'Model');
then everything works fine
You can try setting the controller name (in UsersController):
var $name = 'Users';
Or using the "uses" var (in other controllers:
public $uses = array('User');
Does that not work?
Did you declare the name of the model like that ?
class User extends AppModel {
public $name = 'User';
}
Do you have others variables in your UsersController ?
I set variables in the model like this:
//Person model
public $genders = array('m' => 'male', 'f' => 'female');
Then get them from the controller like this:
//People controller
$genders = $this->Person->genders;
No special code needed. (Is this what you're talking about?)
Also, I don't believe you need to set the $name variable anywhere anymore - I think that was just for PHP 4. (not 100% on that part, but... I don't ever set that anymore, and my Cake2 apps run fine)
You have to load the model like this:
$this->loadModel('User');
I'm new to cakePhp development. I've stuck on following problem:
I've made few models, controllers and views - it works great. The problem is that after production, I have to made new table(Transactionaltemp table and corresponding model and controller ) in the db that logically is "connected" to other tables, but technically does not needs to - for ex. it holds temporary info on user_id, time, ip and similar. So, other tables doesn't need to be directly connected to that.
The problem is when I try (in some other controller than transactionaltemps_controller):
$this->loadModel('Transactionaltemp');
I get error - the model is not found (it is true because the model is missing in the cache). Interesting enough transactionaltempls_controller is in the cache (in the cake_controllers_list file).
I tried following stuff to resolve the problem:
clear cache
disable cache
tried using uses={..} code in the controller that I would like to use mymodels_controller
tried using init('Transactionaltemp')
with no success. Here is corresponding code:
The model:
<?php
class Transactionaltemp extends AppModel
{
var $name = 'Transactionaltemp';
function beforeSave() {
return true;
}
}
?>
The controller:
<?php
class TransactionaltempsController extends AppController
{
var $name = 'Transactionaltemps';
var $scaffold;
}
?>
I'll very grateful to any help!!!
App:Import('Model','Transactionaltemp');
$this->Transactionaltemp= new Transactionaltemp;
I hope this may work
If you are connecting to a table name with different name than your model, you must specify the table name in it:
<?php
class Transactionaltemp extends AppModel
{
var $uses = 'Transactional';
var $name = 'Transactionaltemp';
function beforeSave() {
return true;
}
}
Try
App::Import('Model', 'YourModelName');
in your controller (or where you want).
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.