Containable Behaviour in Cakephp - cakephp

Since a long time as per my knowledge I was using recursive to control my model relationship. If I make any relation between my models it would surely be autoconnected with paginate. To control that I need to use recursive. By default its value is 1 and to contro; that I have to use it as -1 or 0. Yes I read about Containable behaviour that how it automatically control fetching result from other Models Though relationships are made.
I went through same as writing
public $actsAs = array('Containable');
In my controller I wrote
$this->Album->Behaviors->load('Containable', array('autoFields' => false, 'recursive'=>false));
But then also my default paginate called data from other Model as well as fetch queries with other Models.
$this->paginate['Album'] = array('conditions' => $condition, 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
$this->set('albums', $this->paginate('Album'));
My default pagination code as per my expectation data would be only from Album Model and to get from other Model I have to describe it in Pagination but when I checked it in Debug Kit it shows this.
As well as fetch data from all variables.
What should I do ?? Where I am wrong ??

You don’t want the data of related models, correct me if I’m wrong.
For this you need to set contain property to false. This will only bring the data of Album model
$this->paginate['Album'] = array('conditions' => $condition,'contain' => false 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
$this->set('albums', $this->paginate('Album'));
Contain will be helpful when you want to attach multiple model with your query like
$this->paginate['Album'] = array('conditions' => $condition,'contain' => array('model1','model2'), 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
I hope this will work for you. Thanks

Even if your model is set to be containable, you can still set the recursive to false to prevent the fetching of associated data.
Sample model:
<?php
class Article extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array('Category');
}
Sample controller:
<?php
class ArticlesController extends AppController {
public function index() {
$this->Article->recursive = 0;
$this->set('articles', $this->paginate('Article'));
}
public function view($id) {
$this->Article->recursive = 0;
$this->set('article', $this->Article->findById($id));
}
}

Related

In CakePHP 2, how do you tell the Paginator component which model to use?

Given the following working example,
// ProductsController.php
<?php
App::uses('AppController', 'Controller');
class ProductsController extends AppController {
public $helpers = array('Html', 'Form');
public $components = array('Session', 'Paginator');
public $paginate = array(
'limit' => 5
);
public function index() {
$this->Product->recursive = -1;
$this->set('products', $this->paginate());
}
}
?>
What tells Paginator which model to use when it sets the variable? Currently this seems to be automatically using the Products model, but I don't really understand why. Is it just part CakePHP's magic that it selects the model that has the same name as the current controller? And if so, how would I tell Paginator to use some other model? Like if I wanted to also paginate the User model on the same page, how would I implement that?
According to Cakephp2,
$this->paginate() by default works on the current model.
if you want to use other model on the same page you can do like this:
$this->paginate('User');
You can all pass other parameters like:
$this->Paginator->settings = array(
'fields' => array('User.*'),
'order' => array('User.username' => 'asc'),
'limit' => 10,
);
$this->set('users', $this->paginate('User'));
Reference: Pagination
So, after some trial and error, it seems like by default Paginator will just use whatever model is associated with the controller via the naming conventions (the 'User' model is associated with the 'UsersController' controller, and so on).
The first argument of $this->paginate() will accept a different model if you want to use one, for example $this->paginate('Dinglehopper'), but the specified model needs to be available to the controller/action in order for it to work. In order to do that you need $this->loadModel('Dinglehopper'); inside the action where $this->paginate('Dinglehopper') is called.
So in the hypothetical situation where you want to use and paginate the model 'Dinglehopper' inside your 'Products' controller you would do,
// ProductsController.php
<?php
App::uses('AppController', 'Controller');
class ProductsController extends AppController {
public $helpers = array('Html', 'Form');
public $components = array('Session', 'Paginator');
public $paginate = array(
'limit' => 5
);
public function index() {
$this->loadModel('Dinglehopper');
$this->Product->recursive = -1;
$this->set('dinglehoppers', $this->paginate('Dinglehopper'));
}
}
?>
$this->loadModel('Dinglehopper'); makes the model 'Dinglehopper' available to the action, and then $this->paginate('Dinglehopper') returns the paginated Dinglehopper model.

How should I declare my tree behavior in my model to preserve scope in CakePHP 2.5.x?

I'll be straightforward: I want to manage multiple (Link) trees according to their respective menu_id. As long as there is only one tree: no problem. Things get messed up when I start another tree in my link model with a different menu id.
I whish to be able to add, edit, remove, moveUp or moveDown while preserving the scope (menu_id).
This part of the documentation is unclear to me :
http://api.cakephp.org/2.5/source-class-TreeBehavior.html#41-49
Here my Link model.
<?php
App::uses('AppModel', 'Model');
class Link extends AppModel {
public $name = 'Link';
public $displayField = 'title';
public $actsAs = array('Tree' => array(
'parent' => 'parent_id',
'left' => 'lft',
'right' => 'rght',
'scope' => "WHAT-SHOULD-I-PLACE-HERE??",
));
public $belongsTo = array(
'Menu' => array(
'className' => 'Menu',
'foreignKey' => 'menu_id',
)
);
}
And my Menu model.
<?php
App::uses('AppModel', 'Model');
class Menu extends AppModel {
public $displayField = 'title';
public $hasMany = array(
'Link' => array(
'className' => 'Link',
'foreignKey' => 'menu_id',
'dependent' => false,
)
);
}
Thanks to BadHorsie I finally came up to understand that is it pointless to declare the scope in the model's behavior settings.
Instead you (currently I) need to attach the behavior on the fly, with the required scope before any action (add, edit, move up, move down etc) for this to work.
Now, what I need to make sure is that a link always has a menu_id.
And when someone edits a link, the parent_id dropdown must be repopulated according to the menu_id dropdown (javascript needed here and more validation rules in the model to ensure integrity).
The solution was to create a new function in the Link model. it's goal is to preserve the scope when any modification is made to the tree (move up, move down, remove from tree, delete, etc).
public function preserveScope($menuId) {
$this->Behaviors->attach('Tree', array(
'scope' => array(
'Link.menu_id' => $menuId
),
));
return true;
}
The scope is basically a SQL condition (in Cake format).
So you probably need to set the scope to the menu ID that you want.
'scope' => array(
'Link.menu_id' => 5
);
However, you probably don't know which ID yet when trying to set up the array on the class definition, so you might have to do it on the fly.
$this->Link->Behaviors->attach('Tree', array(
'scope' => array(
'Link.menu_id' => $id // You need to decide how to get this ID
),
));
I don't know when you would need to do this though. It's up to you to decide when to attach the behavior.
Edit: If the moveUp/moveDown methods are not working correctly, perhaps the scope field you are using is not correct?

How do I increase the pagination limit in cakephp scaffolding?

I am using scaffolding in cakePHP. The default view shows me maximum of 20 records.
How can I increase the limit of records to show?
thanks!
Scaffolding is nice to test your relation, I think you use this :
class CustomNameController extends AppController {
public $scaffold;
}
But If you find yourself really wanting to customize your logic and your views, it’s time to pull your scaffolding down in order to write some code. CakePHP’s bake console is a great because it generates all the code that would produce the same result as the most current scaffold.
Look at : http://book.cakephp.org/2.0/en/console-and-shells/code-generation-with-bake.html.
After that you have to put on your new "CustomNameController":
public $components = array('Paginator');
public $paginate = array(
'limit' => 25, // or more if you want !
);
Other solutions is to change:
public $settings = array(
'page' => 1,
'limit' => 20,
'maxLimit' => 100,
'paramType' => 'named'
);
on PaginatorComponent.php or extend Scaffold.php directly on the CakePHP Lib.

CakePHP, access model method from different model

how can i access method $this->someModel->find('all') when im in different model form example:
class DevicesController extends AppController {
public function add(){
$departments = $this->Department->find('all', array(
'fields' => array('id', 'mac')
));
$this->set(compact('departments'));
.....
.....
}
right now there is error because $this doesn't "see" Department
what i need to do to make it happen.
If the models are in fact related (and properly set up so in the models), it would be
$this->Device->Department->...
otherwise use loadModel() as documented.
If models are not related, try this way:
$this->loadModel('Department');
$departments = $this->Department->find('all', array(
'fields' => array('id', 'mac')
));
$this->set(compact('departments'));
u can't just use loadModel() because it is controller's method.
if your models aren't related u can do this like that
$this->ModelName = ClassRegistry::init('ModelName');
$this->ModelName->find...
if they are related just use
$this->ModelName->find...
Try this code for loading different models on a controller.
public $uses = array('ModelName1', 'ModelName2')
$this->ModelName1->find()........

CakePHP bindModel HABTM Save

I want to create a binding from one model to my User model on the fly so that the JOIN is not called every time that I perform a find on that model. I am using the binding to perform a HABTM save. However, when I use the bindModel function, the HABTM data is not saved in the database.
What makes this odd is that if I move my binding to the User model, then the save works perfectly. I don't see any indication in the documentation that the save behavior would be different when the association is made in the model versus the bindModel function (though, I may have missed it if there is any).
Here is my bindModel code in my controller:
$this->User->bindModel(
array(
'hasAndBelongsToMany' => array(
'Othermodel' => array(
'className' => 'Othermodel',
'joinTable' => 'othermodels_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'othermodel_id',
'unique' => true,
)
)
)
);
if($res = $this->User->save($data)){
return true;
}
And this is my user model.
class User extends AppModel {
public $name = 'User';
public $belongsTo = array();
public $hasOne = array();
public $hasMany = array();
public $hasAndBelongsToMany = array(
'Othermodel' => array(
'className' => 'Othermodel',
'joinTable' => 'othermodels_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'othermodel_id',
'unique' => true
)
);
Again, I only have the relationship active in one place at one time, so I know the problem is not with the binding itself. It seems the problem is solely related to the fact that I have tried to use bindModel. Is this the intended behavior?
Based on the responses in this article, it looks like the bindModel function only exists for finds.
CakePHP: Bind Model not working
Though there's no information in the CakePHP 1.3 documentation that states that the bind is only for finds, though that would explain the behavior...
http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Models.html
So, I am marking this as answered.
I'm not sure if this is relevant, but are you sure you are not doing any other find operations between the binding and the save. bindModel only binds the model for the next find operation so you may need to pass true through to bindModel to tell it to keep the binding around.
Relevant links: CakePHP: Bind Model not working and http://groups.google.com/group/cake-php/browse_thread/thread/316c9796603eac57?pli=1.
I hope this helps.
Try this,
$this->Message->bindModel(
array(
'belongsTo'=>array(
'User'=>array(
'foreignKey'=>false,
'conditions'=>array('Npl.to=User.id '),
'fields'=>array('recive')
),
'User_e'=>array(
'className'=>'User',
'foreignKey'=>false,
'alias'=>'User_e',
'conditions'=>array('Npl.from=User_e.id '),
'fields'=>array('recive')
)
)
)
);

Resources