i'm new in CakePHP and i'm having problems in an example i'm building to learn.
I'm building a plugin with 3 models (Categoria,Plato,Imagen)
The relationships between them are the following:
Categoria - Plato (n-n)
Plato - Imagen (1-n)
If I go to Plato view, I get all Imagen by the relationship, but when I access through a category, I can't just reach the Imagen associated with each Plato. Why? What's the problem?
Models code:
Plato:
App::uses('AppModel', 'Model');
class Plato extends ErestaurantAppModel {
public $name = 'Plato';
//public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Categoria' => array(
'className' => 'Categoria',
'joinTable' => 'categorias_platos',
'foreignKey' => 'plato_id',
'associationForeignKey' => 'categoria_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
public $hasMany = array('Imagen' =>
array('foreingkey' => array('plato_id')));
}
Categoria:
App::uses('AppModel', 'Model');
class Categoria extends ErestaurantAppModel {
public $name = 'Categoria';
//public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Plato' => array(
'className' => 'Plato',
'joinTable' => 'categorias_platos',
'foreignKey' => 'categoria_id',
'associationForeignKey' => 'plato_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
}
Imagen:
App::uses('AppModel', 'Model');
class Imagen extends ErestaurantAppModel {
public $name = 'Imagen';
//public $actsAs = array('Containable');
public $belongsTo = array('Plato');
}
Finally, the code I'm launching when i go to a Categoria view.
App::uses('AppController', 'Controller');
class CategoriasController extends ErestaurantAppController {
public $uses = array('Erestaurant.Categoria');
public function index() {
$this->Categoria->recursive = 0;
$this->set('data', $this->Categoria->find('all'));
}
public function view($id = null) {
if (!$this->Categoria->exists($id)) {
throw new NotFoundException(__('Registro inválido.'));
}
/*
$this->Categoria->recursive = -1;
$options = array('conditions' =>
array('Categoria.'.$this->Categoria->primaryKey => $id),
'contain' => array(
'Plato' => array(
'Imagen'
)
)
);
*/
$this->Categoria->recursive = 2;
$options = array('conditions' =>
array('Categoria.'.$this->Categoria->primaryKey => $id));
$this->set('item', $this->Categoria->find('first', $options));
}
}
The commented code you see it's another way I tried, using Containable, but at the end I get error "Plato is not associated with model Imagen"
Database seems all ok, with each table created as needed (categorias, platos, imagens, categorias_platos) and with all foering keys created and trying to keep CakePHP default names.
Thank you!
To access deep relations you must use containable behavior. You have a definition of containable behavior in your model, but for some reason it is commented.
public $actsAs = array('Containable');
Uppon uncommenting this line in your Categoria, you can access deep relations in this way:
$this->Categoria->find('all', array(
'contain'=>array(
'Plato.Imagen'
)
));
...or something like this. For more information plase visit this link Containable Behavior
Related
I have a blog post model:
App::uses('AppModel', 'Model');
class BlogPost extends AppModel {
public $primaryKey = "ID";
public $useDbConfig = 'dev_blog';
public $useTable = 'posts';
public $hasMany = array(
'BlogComment' => array(
'foreignKey' => 'comment_post_ID',
'className' => 'BlogComment',
'order' => 'BlogComment.comment_date DESC',
'conditions' => array(
'BlogComment.comment_approved' => '1',
'BlogComment.comment_parent' => 0
)
)
);
}
And a blog comment model:
App::uses('AppModel', 'Model');
class BlogComment extends AppModel {
public $primaryKey = "comment_ID";
public $useDbConfig = 'dev_blog';
public $useTable = 'comments';
public $hasMany = array(
'Children' => array(
'className' => 'BlogComment',
'foreignKey' => 'comment_parent',
'order' => 'Children.comment_date DESC',
'conditions' => array(
'Children.comment_approved' => 1
)
)
);
}
In the controller, I set recursion on BlogPost equal to 2 and did a find:
$options = array(
'conditions' => array(
'BlogPost.ID' => $postID,
'BlogPost.post_status' => 'publish'
),
);
$post = $this->BlogPost->find('first', $options);
What this does is get the content of a particular blog post, all root comments and one level of replies to the root comments. It doesn't get a reply to a reply, though. How can I retrieve an arbitrary depth of replies?
Just don't use recursive at all. Ever.
Set it to -1 in the AppModel:
public $recursive = -1;
Then forget you even heard of it, and use CakePHP's awesome Containable Behavior to get the data you need.
Note: See the MANY other answers related to using CakePHP's Containable.
Using CakePHP 2.2.3
I'm nearly finished with my project and now going back through to setup authorization.
I'm implementing ACL, truncated both the users and groups tables for a fresh start, ran the command to recreate the aco/aro/aros_acos tables and have followed the tutorial.
When I create a group, it creates a corresponding ARO entry but the lft, and rght fields are NULL. I commented out all of my other code in the users/groups models and controllers to try to narrow it down, but it doesn't seem to help.
I will post my code below, with comments and validations removed for the sake of space.
group model:
App::uses('AppModel', 'Model');
class Group extends AppModel {
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
return null;
}
public $hasMany = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'group_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
User model:
App::uses('AppModel', 'Model');
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
//setup ACL settings and function
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
if (isset($this->data['User']['group_id'])) {
$groupId = $this->data['User']['group_id'];
} else {
$groupId = $this->field('group_id');
}
if (!$groupId) {
return null;
} else {
return array('Group' => array('id' => $groupId));
}
} // end parentNode()
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
}
return true;
}
AppController:
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
//'Security',
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
)/*,
'authenticate' => array(
'Form' => array(
'scope' => array('User.activated' => 1 )
)
) */
),
'Session'
);
public $helpers = array(
'Html',
'Text',
'Session',
'Form'
);
/* public function isAuthorized($user = null) {
return true;
} */
public function beforeFilter(){
$this->Auth->loginRedirect = array('controller' => 'products', 'action' => 'index' );
$this->Auth->logoutRedirect = array('controller' => 'products', 'action' => 'index');
$this->Auth->authError = 'You are not allowed to see that.';
}
I even did an ACL implementation on a fresh install of cakephp 2.4.6, and everything works great. I have the projects side by side for comparison but can't find a difference in my ACL setup
Why aren't my lft and rght fields being set in my ARO table?
Short Answer: Remove MVC files associated with ACL tables.
Less Short Answer:
I setup ACL on a fresh install of cake 2.2.3, and everything worked great. Overwrote my code from my user and group models and controllers as well as AppController, and still no go.
I've seen a similar situation when I forget to add $actsAs = array('Tree'); to a model.
I realized I baked controllers/models/views for all ACL tables. DOH! (look for aroscontroller, acoscontroller, etc.)
I removed all the MVC files for these tables and it works great now.
This isn't a typical issue since normally one would add ACL schema after baking, but I started with a database I used on another project and forgot to remove the tables.
I really hope my stupidity helps someone else in this situation.
I am trying to make multiple relation on model as describes in cake kbook
I have two model Account and Tax like this
Account(id, name, code)
Tax(id.name, sales_tax_gl, purchase_tax_gl)
both sales_tax_gl and purchase_tax_gl related to Account.id
these are the model I have created
class Tax extends AppModel {
var $name = 'Tax';
var $displayField = 'name';
var $belongsTo = array(
'SalesTax' => array(
'className' => 'Account',
'foreignKey' => 'sales_tax_gl',
'conditions' => '',
'fields' => '',
'order' => ''
),
'PurchaseTax' => array(
'className' => 'Account',
'foreignKey' => 'purchase_tax_gl',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
Account Model
class Account extends AppModel {
var $name = 'Account';
var$primaryKey = 'id';
var $hasMany = array(
'TaxSalesTax' => array(
'className' => 'Tax',
'foreignKey' => 'sales_tax_gl' ),
'TaxPurchaseTax' => array(
'className' => 'Tax',
'foreignKey' => 'purchase_tax_gl' )
);
}
But it fails with this message "Warning (2): pg_query() [function.pg-query]: Query failed: ERROR: missing FROM-clause entry for table "Account"
What'swrong with the model? I am using postgreSql, thank for your help
In first model your model name is SalesTax and in the second one (Account Model) the model name is TaxSalesTax,please correct it into the correct one and try.
I am thinking that i found the problem. That's cause I use virtual fields in account model like below
var $name = 'Account';
var $primaryKey = 'id';
var $displayField = 'name';
var $order=array('Account.id');
var $virtualFields = array('dropdown_name' => 'Account.id || \' \' || Account.name');
when I uncomment $virtualFields it work as it should, but I still don't know why?
I keep getting a "Call to a member function on a non-object" error in the index function of one of my controllers. Here is the code:
class ModulesController extends AppController {
public $uses = array('Module', 'User');
public $scaffold;
function index() {
if ($this->request->is('get')) { //Technically unecessary but good practice
$email = AuthComponent::user('email');
$user = $this->Module->User->findByEmail($email);
//Code omitted
}
}
And this is my Module model:
class Module extends AppModel {
public $name = 'Module';
public $hasMany = array(
'Slide' => array(
'className' => 'Slide',
'foreignKey' => 'module_id',
'order' => 'Slide.position ASC' //Let's make sure that name is correct
));
public $belongsTo = array(
'Creator' => array(
'className' => 'User'));
public $hasAndBelongsToMany = array(
'OUser' => array(
'className' => 'User',
'joinTable' => 'modules_users',
'foreignKey' => 'module_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
));
} //Unnecessary code omitted
And this is the code for my user model:
class User extends AppModel {
public $name = 'User';
public $uses = 'users';
public $hasMany = array(
'OModule' => array( //Owner of Modules
'className' => 'Module',
'foreignKey' => 'user_id',
'order' => 'Module.created DESC'
));
public $hasAndBelongsToMany = array(
'Module' => array(
'className' => 'Module',
'joinTable' => 'modules_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'module_id',
'unique' => 'keepExisting',
));
} //Unnecessary code omitted
It is worth mentioning that User and Module have both a belongsTo and a HABTM relationship, so User has the aliases Creator and OUser respectively. In the code above, the findByEmail is trying to use the Creator relationship, but that gives me the same error.
My question is, how do I call the findByEmail() method without error?
Change:
$user = $this->Module->User->findByEmail($email);
To:
$user = $this->User->findByEmail($email);
Voila!
Reason:
Somehow, there is either 1) no relationship between Module and User, 2) a mistake in the relationship, or 3) your using an alias for either or both of them so that using Module->User wouldn't be correct.
You're loading the 'User' model anyway though, so there's no reason to go through the Module model to access it - just access it directly (like example above).
I got this models:
class CompanyRestaurantRequest extends AppModel
{
public $name = "CompanyRestaurantRequest";
//public $actsAs = array('Containable');
public $hasMany = array(
"UserRestaurantRequestFeed" => array(
'dependent' => true
)
);
}
class UserRestaurantRequestFeed extends AppModel{
public $name = "UserRestaurantRequestFeed";
public $belongsTo = array("CompanyRestaurantRequest");
public $hasMany = array("UserRestaurantRequestFeedResponse");
}
class UserRestaurantRequestFeedResponse extends AppModel{
public $name = "UserRestaurantRequestFeedResponse";
public $belongsTo = array("UserRestaurantRequestFeed");
}
and I am trying to paginate CompanyRestaurantRequest like this:
$this->CompanyRestaurantRequest->recursive = 5;
$this->CompanyRestaurantRequestFeed->recursive = 5;
$this->paginate = array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
);
$this->set('requests', $this->paginate("CompanyRestaurantRequest"));
The problem is that I get no CompanyRestaurantRequestFeedResponse.
I tried to attach ContainableBehavior to the CompanyRestaurantRequest model and I used contain key in paginate settings like this:
'contain' => array('CompanyRestaurantRequestFeedResponse');
Anything I try, I can not get those CompanyRestaurantRequestFeedResponses related to CompanyRestaurantRequestFeeds.
How can I make it work?
Thank you!
Intead of lines:
$this->paginate = array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
);
At the top of the Controller where all var are declared add:
public $paginate = array(
'CompanyRestaurantRequest' => array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
)
);
This should fix it...