I have the following model in Cakephp:
class Post extends AppModel {
var $name = 'Post';
var $belongsTo = array(
"User" => array(
'className' => 'User',
'foreignKey' => 'user',
'fields'=>array('id', 'username', 'last_action', 'type', 'status', 'country')
),
);
var $hasOne = array(
"Follower" => array(
'className' => 'Follower',
'foreignKey' => false,
'fields'=>'target',
'conditions' => array('Follower.target = Post.user', 'Follower.user = 21')
),
);
}
This model gets the posts from the database and includes the basic user information. My goal is to include in the same query if the user who is retrieving the data is following or not whoever created that post.
For this reason I am trying to associate the table followers. But in order to get the appropriate result I should submit the user id, (in this case 21). The problem is that I don't know how to pass the logged user ID variable.
Does anybody know how to do it or how this model should be written?
Thanks
Remove the $hasOne code within the Post model. Immediately before executing your find, use the bindModel
For example, this would be called from a method within the Post model (changing the 21 to your logged in user's id) prior to the find:
$this->bindModel(
array('hasOne'=>array(
'Follower' => array(
'className' => 'Follower',
'foreignKey' => false,
'fields'=>'target',
'conditions' => array(
'Follower.target' => 'Post.user',
'Follower.user' => '21')
)
))
);
Related
I have 2 Models that are joined but not thrue the id's but with another field.
class Post extends AppModel{
public $useDbConfig = 'test';
public $actsAs = array('Containable');
public $belongsTo= array(
'User' => array(
'className' => 'User',
'foreignKey' => false,
'type' => 'inner',
'conditions' => array('User.field = Post.field')
));
}
But the cakephp is not connecting the 2 models correctly. To every Post it just gives the the first user (User with id 1). When I check the SQL-Statements the User statement is following:
SELECT `User`.`id`, `User`.`group_id`... FROM `users` AS `User` WHERE 1 = 1
Any ideas why this is not working?
I also tried joining the models manually:
$this->paginate = array(
'limit' => '15',
'joins' => array(
'INNER JOIN users User ON (User.field = Post.field)'
)
);
$posts= $this->paginate('Post');
Any ideas?
EDIT
I totally forgot to mention that these 2 tables are in different databases. Maybe there is the problem. But I had no problem joining tables over different databases so far.
EDIT
I was wrong about the join so I changed it from "belongsTo" to "hasOne" since a post can only be written by one user. But still no changes.
You can use the foreignKey parameter to any field, not necessarily the id:
Post model:
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'some_user_field'
)
);
User model:
public $hasMany = array (
'Post' => array (
'className' => 'Post',
'foreignKey' => 'some_user_field',
'dependent' => true
)
);
According to the book:
It is not mandatory to follow CakePHP conventions. You can easily
override the use of any foreignKey in your associations definitions.
Nevertheless, sticking to conventions will make your code less
repetitive and easier to read and maintain.
Otherwise, make joins manually:
$this->paginate = array(
'limit' => '15',
'joins' => array(
array(
'table' => 'users',
'alias' => 'User',
'type' => 'inner',
'conditions' => array('User.field = Post.field')
)
)
);
I found a solution although I don't understand why the others won't work. I put
$this->Post->primaryKey = 'field';
right before
$posts= $this->paginate('Post');
and now it works. Can anyone tell me why the other ways won't work?
I have a table
Medias:
ID,
PARENT_ID
PATH
TITLE
Items:
ID
medias
Title
description
Models
class ImageGallery extends AppModel {
public $name = 'ImageGallery';
public $useTable = "medias";
var $belongsTo = array(
'Parent' =>
array('className' => 'ImageGallery',
'foreignKey' => 'parent_id',
'dependent' => false,
),
);
var $hasMany = array(
'Children' =>
array('className' => 'ImageGallery',
'foreignKey' => 'parent_id',
'dependent' => false,
),
);
}
class Item extends AppModel {
public $useTable = "items";
public $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
);
public $belongsTo = array(
'Gallery' => array(
'className' => 'ImageGallery',
'foreignKey' => 'medias'),
);
public $hasMany = array(
'ItemMeta' => array( 'className' => 'ItemMeta'),
);
}
The media table contains gallery information. Images are stored in parent_id relation.
When I request Item->find('all'); I am getting only one entry from Media table, but I want to get all its children too. :(
I can get its children by using $this->ImageGallery->findById(10);, but I want to get them with the Item Model.
Use the containable behavior to specify which associated models you want the query to get. http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
$this->Item->find('all', array('contain' => array('ImageGallery' => array('Children'))));
If you're looking to go deeper than just the child level, like if you want to get the rest of the tree, then you'll need to either write something to recursively fetch the children, the children's children, etc., or perhaps you can alter your code and models to make use of CakePHP's Tree Behavior. See http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html and http://www.dereuromark.de/2013/02/17/cakephp-and-tree-structures/
I can't seem to figure out how the containable behavior works, or how to retrieve the data from (and based) on associated models.
I need to put the following MySQL query in the cakephp find('all') function, I know i can use the query builder for the sql syntax but I want to use find function and want to figure out how it works.
SELECT events.id, events.name FROM events, user_roles
WHERE user_roles.event_id = events.id
AND user_roles.user_id = 1
The idea is simple, in the user_roles the user_id, role_id and event_id are stored. Now I want to retrieve all events for a certain user (here user_id = 1). I tried some variations on the following:
$data = $this->Event->find('all',array(
'contain' => array(
'UserRole' => array(
'fields' => array('id'),
'conditions' => array(
'UserRole.user_id' => $this->Auth->user('id')
)
)
)
));
But this keeps returning all events. What I want is an array like (or any other result with the same associated data):
array(
[0] => array(
[Event] => array(
'id' => 1,
'name' => 'Event Name'
),
[UserRole] => array(
'role_id' => 2,
'event_id'=> 1
)
[1] => array(
.... etc ...
)
The following models and associations are defined
class Event extends AppModel {
public $hasMany = array(
'UserRole' => array(
'className' => 'UserRole',
'foreignKey' => 'event_id',
'dependent' => false,
)
)
)
class UserRole extends AppModel {
public $belongsTo = array(
'Event' => array(
'className' => 'Event',
'foreignKey' => 'event_id'
),
)
)
So how does it work ;).
Edit:
I forgot to mention that I've set in AppModel.php:
public $recursive = -1;
Containable finds the associated records for the original query. What you are doing is a find('all') on your Event model with absolutely no conditions, so it will return all Events.
Then Containable will retrieve all the UserRole records that are for the given user_id and are also associated to the Event by the event_id
If you want to only retrieve events for the given user, you could do it one of two ways
Via the Event->UserRole association and chained models:
$data = $this->Event->UserRole->find('first', array(
'conditions' => array('UserRole.user_id' => $this->Auth->user('id'),
'contain' => array('Event')
));
$events = $data['Event'];
or
Via your current code and then using the Hash::extract method to get the Events that match. (Hash is a CakePHP core class)
$events = Hash::extract('/UserRole[user_id='.$this->Auth->user('id').']/..', $data);
I've run through the Cakephp documentation on linking models together (creating associations), and I can get a single select dropdown in the scaffolded add and edit views by defining a $hasOne member one model and a corresponding $belongsTo in the other. Now, for a $hasMany relationship, I'm trying to get some kind of form input (either a multi-select dropdown, or checkboxes ... preferably checkboxes) in my scaffolded add and edit views that lets the user choose the associated advertisements for a given rental. But with the below code I get no mention of Advertisements in the Rental add and edit views :'( Am I missing something? Is this even possible? I've seen this done in RoR and Grails but can't get it working with CakePHP. Thanks for any help!
Rental model (app/Model/Rental.php)
<?php
class Rental extends AppModel {
var $name = 'Rental';
var $belongsTo = array(
'Agent' => array(
'className' => 'User',
'foreignKey' => 'agent_id'
),
'Bedroom',
'Landlord' => array(
'className' => 'Landlord',
'foreignKey' => 'landlord_id'
)
);
var $hasMany = array(
'Advertisement' => array(
'className' => 'Advertisement',
'foreignKey' => 'rental_id',
//'conditions' => array('Comment.status' => '1'),
'order' => 'Advertisement.created DESC',
'limit' => '5',
'dependent'=> false
)
);
public $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
'description' => array(
'rule' => 'notEmpty'
)
);
public function isOwnedBy($rental, $user) {
return $this->field('id', array('id' => $rental, 'user_id' => $user)) === $rental;
}
}
Rentals Controller (app/Controller/RentalsController.php)
<?php
class RentalsController extends AppController {
public $scaffold;
}
Advertisement model (app/Model/Advertisement.php)
<?php
class Advertisement extends AppModel {
var $name = 'Advertisement';
var $belongsTo = array(
'Rental' => array(
'className' => 'Rental',
'foreignKey' => 'rental_id'
),
'Author' => array(
'className' => 'User',
'foreignKey' => 'author_id'
)
);
}
Advertisements Controller (app/Controller/AdvertiesementsController.php)
<?php
class AdvertisementsController extends AppController {
public $scaffold;
}
Cake's scaffold views don't show anything from the hasMany side of the relationship. They assume you want to pick it from the model that has the belongsTo.
Frankly, doing it as a multi-select is a little odd for this relationship, IMHO. Multi-selects are normally used for hasAndBelongsToMany relationships. If you want to do it, you'll need to do the work yourself, and not use Cake's scaffolding.
I'm having this problem with relationships with Codeigniter's DataMapper.
I have an Interview model that has an author_id and an interviewee_id. They both relate to the user id in the user model.
I've been trying several approaches and none work; this is what I have right now:
class Interview extends DataMapper
{
var $has_one = array(
'interviewee' => array(
'class' => 'user',
'other_field' => 'done_interview'),
'author' => array(
'class' => 'user',
'other_field' => 'written_interview')
);
}
class User extends DataMapper
{
var $has_many = array(
'done_interview' => array(
'class' => 'interview',
'other_field' => 'interviewee'),
'written_interview' => array(
'class' => 'interview',
'other_field' => 'author')
);
}
How do I let DataMapper know that one relationship will go through author_id, and the other through interviewee_id?
Quoting Nelo who answered his question in a comment:
It seems there needs to be a user_id field necessarily and then for the other relationships I can name the fields however I want. So Changing interviewee_id to user_id seems to do the drill. Just in case someone has the same problem out there