I am using CakePHP framework to build a web application. The simplest form of my problem is this:
I have a users table and a messages table with corresponding models. Messages are sent from a user to another user. So messages table has columns from_id and to_id in it, both referencing to id of users. I am able to link Message model to User model by using $belongsTo but I am unable to link User model with Message model (in reverse direction) by using $hasMany in the same manner.
var $hasMany = array(
'From' => array(
'className' => 'Message',
'foreignKey' => 'from_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'To' => array(
'className' => 'Message',
'foreignKey' => 'to_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
What can do here? Any ideas? Thanks for any help.
You can link the two models with 'hasMany' or 'belongsTo' more than one time with diffirent foreign keys at the same time.Since I don't find any example from the cookbook I tested that with a tiny piece of code and it worked as expected .
Related
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)
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)
));
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.
I would like to use hasMany through relationship to connect two users through a model invitations
I currently have the following controller:
class User extends AppModel {
var $name = 'User';
var $displayField = 'username';
var $hasMany = array(
'Invitation' => array(
'className' => 'Invitation',
'foreignKey' => 'sender_user_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'Invitation' => array(
'className' => 'Invitation',
'foreignKey' => 'receiver_user_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
)
}
However, when i get error:
Error: Database table sender_users for model SenderUser was not found.
Which is a bit annoying, because I already thought I specified that I want to use Invitation.
What is the issue, what code do I change?
First: you can't create the same association twice. Even from a PHP syntax perspective that's not possible. You'll have to give each association a unique name:
public $hasMany = array(
'SentInvitation' => array(...),
'ReceivedInvitation' => array(...)
);
Second, the problem is probably that you don't have an Invitation model. Cake creates a model on-the-fly according to naming conventions. Since you have a column sender_user_id, according to naming conventions you should therefore also have a sender_users table. Create the Invitation model and set it up without that association, then Cake shouldn't be looking for it.
I am trying to query a hasAndBelongsToMany relationship in Cakephp 1.3, but it looks like the SQL query being run is not doing a Join on the many to many table.
I have a users table, projects table, and users_projects table. I want to get a list of all projects a user is associated with in a separate Allocations controller.
I have been reading the cakephp book on the topic: http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM
So I have been trying this:
var_dump($this->Allocation->User->Project->find('list',array('conditions'=>array('Project.user_id'=>'21'))));
However that does not work, It returns nothing and this error:
Warning (512): SQL Error: 1054: Unknown column 'Projects.user_id' in 'where clause' [CORE/cake/libs/model/datasources/dbo_source.php, line 681]
Query: SELECT `Project`.`id`, `Project`.`name` FROM `projects` AS `Project` WHERE `Projects`.`user_id` = '21'
It looks like cakephp is not doing the required join.
This is in my projects model:
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'users_projects',
'foreignKey' => 'project_id',
'associationForeignKey' => 'user_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
And this is in my users model:
var $hasAndBelongsToMany = array(
'Project' => array(
'className' => 'Project',
'joinTable' => 'users_projects',
'foreignKey' => 'user_id',
'associationForeignKey' => 'project_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
So, what is the correct syntax to get the list of projects for a given user on a many to many relationship in cakephp?
Perhaps that's because you didn't make the two table names connected in alphabetical order.users_projects should be projects_users.
You are getting this error because you are using the find type 'list'. Cake's default behaviour is to select the ID and NAME fields when using this find type.
Change your find type to 'all' to retrieve the results you are expecting:
var_dump($this->Allocation->User->Project->find('list',array('conditions'=>array('Project.user_id'=>'21'))));