I am few months old with CakePHP. This is first time I am trying CakePhp Association. I assume I am following almost all instruction but still my model doesn't seem to work.
This is simple 'User' and 'Profile' Model. Table Structure: User:
- id (Primary Key)
- name
Profile:
- id (primary key)
- role
- user_id (Reference Key)
Models: User:
class UserModel extends AppModel{
var $name = 'User';
public $hasOne = array(
'Profile'
);
}
Profile:
class ProfileModel extends AppModel{
var $name = 'Profile';
public $belongsTo = array('User'); }
Controller: Users:
lass UsersController extends AppController{
var $name = 'Users';
public $scaffold;
function index(){
$user = $this->User->find('all'); //HERE I expect to get User and Profiles data
pr($user);
}
}
Profiles:
class ProfilesController extends AppController{
var $name = 'Profiles';
public $scaffold;
function index(){
$profile = $this->Profile->find('all');
pr($profile);
}
}
If I run users: /localhost/test_php_apps/users/ I get:
Array (
[0] => Array
(
[User] => Array
(
[id] => 1
[name] => rohini
)
)
)
I am wondering why 'Profile' data is not shown. I have manually added records in tables.
Further if I try in UsersController: $user = $this->User->Profile->find('all'); I get the following error:
Call to a member function find() on a non-object
My guess is something is wrong with setting up Associations. But not sure what is messing things up.
I know this is very basic question, but even after reading 10 to 15 related cases I don't seem to find the answer.
Any help will be much appreciated.
Do me a favor, change
class UserModel extends AppModel
to
class User extends AppModel
and
class ProfileModel extends AppModel
to
class Profile extends AppModel
and see if that helps when doing $user = $this->User->Profile->find('all'); in the UsersController.
Also, is
public $actsAs = array('Containable');
not
public $actAs = 'Containable';
not actAs. See if that helps any. If not, it would be helpful to know your cake version.
See here for containable and this for naming model conventions.
If you bake this things is made your life easier.
Models: User:
class User extends AppModel{
var $name = 'User';
public $hasMany = array(
'Profile'=>array(
'className' => 'Profile',
'foreignKey' => 'user_id',)
);
}
Profile:
class Profile extends AppModel{
var $name = 'Profile';
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
)
);
}
Controller: Users:
class UsersController extends AppController{
var $name = 'User';
public function index(){
$users = $this->User->find('all');
var_dump($users);
}
}
Controller Profile:
class ProfilesController extends AppController{
var $name = 'Profile';
public function index(){
$user_id = 2;
$users = $this->Profile->find('all', array('conditions'=>array('Profile.user_id'=>$user_id)));
var_dump($users);
}
}
add the following lines in your usermodel
public $useTable = 'YOUR USERTABLENAME';
and change
public $hasOne = array(
'Profile'
);
to public $hasOne = 'Profile';
in your profilmodel add the same.
public $useTable = 'YOUR PROFILETABLENAME';
and change
public $belongsTo = array('User');
to
public $belongsTo = array('User' => array('className' => 'User',
'foreignKey' => 'user_id'));
in your userscontontroller add this
public $uses = array('User','Profile');
normally it should work now when you try the query
$u = $this->User->find('all',array('contain' => array('Profile'));
or
$u = $this->User->find('all',array('recursive' => 2));
but it also should work if you write only:
$u $this->User->find('all');
regards
Related
I'm just learning cakePHP. I have a CATEGORIES table and a POSTS table. A post have one category. So there is a category_id foreign key in POSTS table.
In my Model, I have Category.php with this code.
<?php
App::uses('AppModel', 'Model');
class Category extends AppModel {
// A hasMany association will allow us to fetch a category’s posts when we fetch a Category record.
public $primaryKey = 'category_id';
public $hasOne = 'Post';
}
?>
In my Post.php I have something like this.
class Post extends AppModel {
public $hasMany = array('Photo');
public $primaryKey = 'post_id';
public $belongsTo = array('User'); // 'Category',
public $relatedImages;
public $belongsTo = 'Category';
Now in my PostController.php I have
$allCategories = $this->Category->find('list');
$this->set('allCategories', $allCategories);
The objective is to retrieve all the category from the categories table and show it in my form.
However I encountered the error of Call to a member function find() on a non-object
I'm not sure what is happening here. How can I retrieve this?
many thanks!
Use
$this->Post->Category->find('list');
As you have to goto Category table Thru posts as u r in posts controller Now currently.
In your post model try to declare the Category as below
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id'
)
);
In Cakephp,
I have used belongsTo in AppModel
class AppModel extends Model {
public $actsAs = array('Containable');
public $belongsTo = array(
'ModifiedBy' => array(
'className' => 'User',
'foreignKey' => 'common_modified_by_user_id'
)
);
}
Now I also want to apply belongs to in UserModel
class User extends AppModel {
public $belongsTo = array(
'School' => array(
'className' => 'User',
'foreignKey' => 'school_id'
)
);
}
But when i do so...it over rides the belongsTo of App model and on School data comes in the fetched array....
Please Help...
No automatic merging of associations
Other than the $actsAs and $findMethods variables, association configurations are not being merged automatically, you'll have to do that on your own.
It should be rather simple to solve, using Object::_mergeVars() in your User models constructor should do the trick:
public function __construct($id = false, $table = null, $ds = null) {
$parent = get_parent_class($this);
$this->_mergeVars(array('belongsTo'), $parent);
parent::__construct($id, $table, $ds);
}
ps. you might want to have a look at behaviors, they might be the better option for your needs.
I just created 2 models UsersModel and UserpicsModel and try to get both records but it is returning Error: Call to a member function find() on a non-object.
//UsersModel.php
class Users extends AppModel
{
public $hasMany = array(
'Userpics' => array(
'className' => 'Userpics'
)
);
}
//UserpicsMdoel.php
class Userpics extends AppModel
{
public $belongsTo = array(
'Users' => array(
'className' => 'Users',
'foreignKey' => 'uid'
)
);
}
//RecipesController.php
class RecipesController extends AppController {
public $uses =array('Users','Userpics');
public function view() {
$users = $this->Users->Userpics->find('all');
print('<pre>');
print_r($users);
print('<pre>');
exit;
}
}
first: you are not following cake conventions: models should be singular and not plural.
But the actual problem here is that the model files names are wrong: if you still want to use your conventions then the name for the Users model should be Users.php and not UsersModel.php
the same for Userpics
read this useful answer about how to debug this kind of error.
But if you decide to use the cake naming conventions (and I strongly suggest you to do so) consider doing the following:
//User.php (table users)
class User extends AppModel
{
....
}
//UserPic.php (table user_pics)
class UserPic extends AppModel
{
....
}
//RecipesController.php
class RecipesController extends AppController {
public $uses =array('User','UserPic');
public function view() {
$users = $this->User->UserPic->find('all');
print('<pre>');
print_r($users);
print('<pre>');
exit;
}
}
//UsersModel.php
class Users extends AppModel
{
public $hasMany = array(
'Userpics' => array(
'className' => 'Userpics',
'foreignKey' => 'uid'
)
);
}
I've set up two models: city, and country. Below is how I've defined them:
class City extends AppModel { // for "cities" table
public $hasOne = 'Country';
}
class Country extends AppModel { // for "countries" table
public $hasMany = array(
'City' => array(
'className' => 'City'
)
);
}
and in my controller:
public function getCities() {
$this->loadModel('City');
$cities = $this->City->find('all');
}
but it's giving me this error:
Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Country.city_id' in 'on clause'
SQL Query: SELECT `City`.`id`, `City`.`country_id`, `City`.`name`, `City`.`latitude`, `City`.`longitude`, `City`.`time_zone`, `City`.`dma_id`, `City`.`code`, `City`.`created`, `City`.`modified`, `Country`.`id`, `Country`.`country_id`, `Country`.`name`, `Country`.`code`, `Country`.`created`, `Country`.`modified` FROM `rtynbiz_ls`.`cities` AS `City` LEFT JOIN `rtynbiz_ls`.`countries` AS `Country` ON (`Country`.`city_id` = `City`.`id`) WHERE 1 = 1
Notice: If you want to customize this error message, create app/View/Errors/pdo_error.ctp
I can't understand why it's trying to do a join with Country table. I only want to fetch cities. How do I stop this from happening? And, why is it trying to make an association using Country.city_id (which doesn't exists) Also, have I named my classes and tables correctly? Thanks
Following lines of code are making relationship so JOIN is present there. To remove the JOIN from the query just replace :
class City extends AppModel { // for "cities" table
public $hasOne = 'Country';
}
class Country extends AppModel { // for "countries" table
public $hasMany = array(
'City' => array(
'className' => 'City'
)
);
}
With:
class City extends AppModel { }// for "cities" table
class Country extends AppModel {} // for "countries" table
You can make relationships in the tables easily by following this
By default, CakePHP will automatically try to pull additional model's data. To stop that from being the default, in your AppModel, set this variable:
public $recursive = -1;
I would also suggest adding Containable behavior, so your app model looks like this:
<?php
class AppModel extends Model {
public $actsAs = array('Containable');
public $recursive = -1;
}
Read more about "recursive" and "Containable Behavior" at the CakePHP book.
If you don't want to do join when you want to retrieve your data make it recursive -1
public function get_cities() {
$this->loadModel('City');
$this->City->recursive=-1;
$cities = $this->City->find('all');
//or
$cities = $this->City->find('all', array('recursive'=>-1));
}
any way this would be your model:
class Country extends AppModel {
public $hasMany = array(
'City' => array(
'className' => 'City',
'foreignKey' => 'country_id',
'dependent' => false,
),
);
}
class City extends AppModel {
public $belongsTo = array(
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id',
)
);
}
make sure you don't have messy code on these 2 models
I'm trying to build an invitation system with CakePHP. I have Invitation model which hasMany People, and Person hasOne and belongsTo Invitation. I believe the relationships are working, since my Invitation index view can properly access and display its associated People through the Invitation model. But heres what the relationship rules look like:
class Invitation extends AppModel {
var $name = 'Invitation';
var $hasMany = array(
'People' => array(
'className' => 'Person',
'foreignKey' => 'invitation_id',
'dependent'=> true
)
);
...
}
class Person extends AppModel {
var $name = 'Person';
var $hasOne = 'Invitation';
var $belongsTo = 'Invitation';
...
}
UPDATED MODEL RELATIONSHIPS:
class Invitation extends AppModel {
var $name = 'Invitation';
var $hasMany = array('Person');
...
}
class Person extends AppModel {
var $name = 'Person';
var $belongsTo = array('Invitation');
...
}
In my Invitation add function, however, I am having trouble saving the data for new People. I want to simultaneously add one invitation and two people.
Heres my add function:
function add() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
$this->layout = 'ajax';
if(!empty($this->data)) {
$this->Invitation->create();
if($this->Invitation->saveAll($this->data)) {
//debug($this->data);
$this->Session->setFlash('Saved');
$this->redirect('invitations/add_invitations');
} else {
echo('Didnt save<br />');
}
}
}
}
Here is the output of my debug($this->data):
Array
(
[Invitation] => Array
(
[code] => 001
[password] => 85c8a3735499bf91d25e5960ab4ed9deeb0b457e
[type] => 1
[num_people] => 2
)
[Person] => Array
(
[0] => Array
(
[fname] => Jane
[lname] => Doe
)
[1] => Array
(
[fname] => John
[lname] => Doe
)
)
)
I don't get any errors. the Invitation data is saved properly, but the people are not.
UPDATE: I finally got this working with the above updated model relationships. Obviously the hasOne & belongsTo rules in the Person model were conflicting. After that I made a mistake (an embarrassing one) that was preventing saving to related the related Person model:
In the Invitation model, I hade $hasMany = array('People'); when it should have been $hasMany = array('Person').
I also had to change the configuration of my database to use InnoDB as the default, so that was certainly a necessary fix.
var $hasOne = 'Invitation';
var $belongsTo = 'Invitation';
These relations to the same model should have different Aliases otherwise Cake will get confused, as I did trying to unpick it. See http://book.cakephp.org/view/1046/Multiple-relations-to-the-same-model