How do I get the releated object names? - cakephp

I have a problem that I've been trying to resolve for hours. Let's say that I have a book model, an author model and a country model.
When viewing a book entry, at the bottom of the page, there are the related objects. In this case, authors.
The page shows me the related data for the author, the author's name and other details display fine. The country, however, is displayed as country_id.
Is there a way that I can change that to country name?
UPDATE:
I have these three tables:
Book HMBM Authors H Country
A book may be written by many authors (for anthologies)
An author may write many books
An author may reside in a country
A country may host may authors.
Book:
public $hasAndBelongsToMany = array(
'Author' => array(
'className' => 'Author',
'joinTable' => 'author_books',
'foreignKey' => 'book_id',
'associationForeignKey' => 'author_id',
'unique' => '',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Author:
public $hasMany = array(
'Book' => array(
'className' => 'Book',
'foreignKey' => 'book_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
public $belongsTo = array(
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
Country:
public $hasMany = array(
'Author' => array(
'className' => 'Author',
'foreignKey' => 'country_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)

If a book has an author, and an author has a country, the data you require is outside the ORM's mechanism to avoid recursive calls to the database. Call $this->Book->recursive = 2in your controller method to increase the recursion limit.

Related

CakePHP adding to multiple tables from one view

can someone provide an explanation for me?
I've got a database where I'm trying to update 4 tables from one page, Organizations, OrganizationsDetails, Account, AccountRoles. The add view itself would contain fields for the Account and the Organization. When I call the OrganizationsController add function, I want to then call add on AccountController, AccountRolesController (set Account as an administrator role), and OrganizationDetailsController (set that Account as the administrator for that specific Organization).
Should I be using components for this? When I call add() on the Organizations, I always intend to perform these steps - never solely create the Organizations entry below. Should I be doing this directly in that function or some other method?
Let me know if I need to explain more, thanks!
EDIT: Added the four models below:
Organization
class Organization extends AppModel {
public $hasMany = array(
'Account' => array(
'className' => 'Account',
'foreignKey' => 'organization_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
public $hasOne = array(
'OrganizationDetail' => array(
'className' => 'OrganizationDetail',
'foreignKey' => 'organization_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
OrganizationDetail
class OrganizationDetail extends AppModel {
public $belongsTo = array(
'Organization' => array(
'className' => 'Organization',
'foreignKey' => 'organization_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Account' => array(
'className' => 'Account',
'foreignKey' => 'account_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
AccountRole
class AccountRole extends AppModel {
public $belongsTo = array(
'Account' => array(
'className' => 'Account',
'foreignKey' => 'account_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Role' => array(
'className' => 'Role',
'foreignKey' => 'role_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Account
class Account extends AppModel {
public $belongsTo = array(
'Organization' => array(
'className' => 'Organization',
'foreignKey' => 'organization_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
public $hasOne = array(
'OrganizationDetail' => array(
'className' => 'OrganizationDetail',
'foreignKey' => 'account_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
public $hasMany = array(
'AccountRole' => array(
'className' => 'AccountRole',
'foreignKey' => 'account_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
You've got wrong the whole MVC idea. Controllers should not call methods in other controllers (or at least not in this scenario).
The right approach would be to set up OrganizationsController->add() so that it saves all the data by independent calls to each Model->save($data), or by using
Organization->saveAssociated($data,array('deep' => true))
Your form fields need to be named properly for this to work. For example:
echo $this->Form->create('Organization', array('action' => 'add'));
echo $this->Form->input('Organization.name'));
echo $this->Form->input('Account.0.name', array('label' => 'Account name'));
echo $this->Form->input('OrganizationDetail.details', array('label' => 'Org. Details'));
echo $this->Form->input('Account.0.AccountRole.id', array('label' => 'Account Role'));
echo $this->Form->end('Add');
However, you may get into trouble if you try to go too many levels deep. If you find yourself in this situation, it's probably because you data model is flawed.
This is what your data model currently looks like:
This is what I believe it should look like:
It is critical to have your data model right before you start coding. It can save you many headaches!

How deep is the cakephp delete cascade

I have three tables Book->pages->assets when I delete a book I delete the pages associated with it. I also want to delete the assets associated with page when I delete a book.
How deep does book delete cascade go? My book and pages delete but not assets. If I know cakephp should delete the assets also then I know it is just my setup.
Book Model
public $hasMany = array(
'Page' => array(
'className' => 'Page',
'foreignKey' => 'book_id',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => 'order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
Page model
public $hasMany = array(
'Asset' => array(
'className' => 'Asset',
'foreignKey' => 'page_id',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
Book Controller
$this->Book->delete($id, true)

HABTM associations with another table

I'm in trouble with a more complex situation of HABTM in Cakephp. Ina nutshel, the situation is: a have users and movies, the relationship between then is HABTM, but i also need a relationship types.
USERS - HABTM - MOVIES
|
RELATION_TYPES
The relationship between users and movies could be many different types: author type, public type, etc.
When i try to use the contain behavior, i get an error message that says:
Model "MoviesUser" is not associated with model "RelationType".
But all the models are associated.
These are the models:
User Model
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'movies_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => 'Movie.title',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Movie Model
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'movies_users',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
MoviesUser Model
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'RelationType' => array(
'className' => 'RelationType',
'foreignKey' => 'relation_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In the MoviesController, i'm trying to get some movies and the relation with users and the type of the relation. Here is where i call the Contain on Movies Controller:
$this->Movie->contain(array(
'Person' => array(
'order' => array(
'Person.name'=>'ASC'
),
'Activity'
),
'Country' => array(
'order'=>array(
'Country.name'=>'ASC'
)
),
'User'=>array(
'conditions'=>array(
'User.id'=>$this->Session->read('Auth.User.id')
),
'MoviesUser'=>array(
'RelationType'
)
)
));
When i try to run this i get the message Model "MoviesUser" is not associated with the model "RelationType".
The fields of movies_user are:
id, user_id, relation_type_id, rate, comment
The fields of relation_types are:
id, title
And here my $has_many property on RelationType Model:
public $hasMany = array(
'MoviesUser' => array(
'className' => 'MoviesUser',
'foreignKey' => 'relation_type_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);

Overriding CakePHP conventions. One table with 2 columns of the same model

Suppose I have a table/model Products.
Suppose I have a table/model Equivalencies which has among its columns this 2:
original_id
equivalent_id
Both original_id and equivalent_id have as foreign keys the primary key of Products. So, I can't follow the convention of naming original_id as product_id, because I also have to deal with equivalent_id (which would also be product_id).
What should I do?
Currently, I have the Product model configured as this:
public $hasMany = array(
'Original' => array(
'className' => 'Equivalency',
'foreignKey' => 'original_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => '',
'table' => 'products',
),
'Equivalent' => array(
'className' => 'Equivalency',
'foreignKey' => 'equivalent_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
Could anyone tell me if this is how it's supposed to be done?
What I Want
I want to be able to find all the equivalencies of a given product, but with conditions over the relation (the one with original_id, equivalent_id).
This doesn't work:
$original = $this->Product->find('all',
array(
'contain' => 'Product.Original.deleted_equivalent = false',
'conditions' => array('Product.id' => $id)
));
Your model is fine, that's the way you should do it.
Your call to find is not.
Try this
$original = $this->Product->find('all',
array(
'contain' => array('Equivalent'),
'conditions' => array('Product.id' => $id)
));

Getting data from a $hasAndBelongsToMany relation at CakePHP 2.2

I have 3 tables:
- users
- posts
- Subscriptions (which should be by default posts_users (n-n))
The subscriptions table is the n-n table needed for this relation. I didnt want to call it "posts_users" as it is very confusing for my system because i have more relations between users and posts.
The, to create the hasAndBelongsToMany relation, i did this:
Post (model):
public $hasAndBelongsToMany = array(
'Subscriptions' => array(
'className' => 'User',
'joinTable' => 'subscriptions',
'foreignKey' => 'post_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
User (model):
public $hasAndBelongsToMany = array(
'Post' => array(
'className' => 'Post',
'joinTable' => 'subscriptions',
'foreignKey' => 'user_id',
'associationForeignKey' => 'post_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Lets say i want to find the subscribed posts for the user with id 3.
Is there any way to do a find to retrieve data of subscribed Posts for a user?
In which model should i do the query? How??
Thanks.
Ok. Finally i got it.
You can do the query from any of the two related models. In this case Post or User.
$this->Post->User->find('all', array(
'conditions' => array('User.id' => $this->Session->read('Auth.User.id')),
'contain' => array('Subscriptions')
));
This would return the subscribed tickets (in the subscriptions array) for the current user.

Resources