Accessing 3rd association - php

I have following models:
- Agenda (id, user_id, event_id) -> belongsto Event, User
- Event (id, etc) -> hasmany Agenda
- User (id, city_id, etc) -> hasmany Agenda, belongsto City
- City (id, name) -> hasmany User
While in the Agendas controller, I want to display the City.name of an user that has a certain event_id in his Agendas. How can I add City data to the User array of the Agendas array?
N.B. I don't want to use recursive 2 because that loads way to much data into the array.

Your best option looks to be the CakePHP Containable Behaviour http://book.cakephp.org/view/474/Containable
It allows you to limit the associated model data that is returned - it basically has the power of recursive 2 in being able to find deep association data, but has much better performance and is cleaner because it gives you only the data you need.
Something like the following code should return the City data within the User data, including the condition of event_id.
$this->Agenda->find('all', array(
'contain' => array(
'User' => array(
'City'
),
),
'conditions' => array(
'Agenda.event_id' => $event_id
)
));
Just to complete that code snippet, ensure var $actsAs = array('Containable'); is at the top of the model (or in the app_model.php if you want the containable behaviour accessible to all models)

Related

How to store multiple value in a field which has relationship with other table

I am working on a 'contact databse' using mysql database and codeigniter. Some of my table structure is as below
Organization -> fld_id
fld_orgname
fld_orgaddress
Department -> fld_id
fld_org_id (has relationship with organization)
fld_deptname
fld_details
Designation -> fld_id
fld_dept_id (has relationship with organization)
fld_desgname
usertable -> fld_id
fld_desg (has relationship with Designation)
fld_dept (has relationship with Department)
fld_org (has relationship with organization)
Now the problem is, sometime a person may work in multiple organization. Then how could i insert this multiple value sequentially to usertable?
One answer is to create another cross reference table for storing the connection between a user and an organization. That way there can easily be a one to many relationship between a person and organizations
user_org => fld_id
user (usertable.fldid)
org (Organization.fld_id)
You should then remove fld_org (has relationship with organization) from usertable
(Sorry about my english if im not clear)
If i'm understanding this correctly a user can work in more than one organization and an organization can have multiple users, uno solution may be to create a junction table
JUNCTION_ORG_USER -> fld_id_user (usertable) REFERENCES usertable(fld_id)
-> fld_id_org (organization) REFERENCES organization(fld_id)
Or if u dont want (or can't) to normalize, u can repeat the row changing the organization id
Also as u are using codeigniter, and this applies if u create a junction table,
u can use
$this->db->insert_batch('table_name', $array);
Just build the array like the documentation indicated
$data = array(
array(
'fld_id' => 'TheUserId',
'fld_org' => 'OrganizationId_1'
),
array(
'fld_id' => 'TheUserId',
'fld_org' => 'OrganizationId_2'
)
);
$this->db->insert_batch('mytable', $data);
Hope my answer helps u.

cakephp find query conditions on associated model

I have a model User and a model Role in a CakePHP application. The association between the two models is the following:
User $belongsTo Role
Role $hasMany User
I want to make a query on the User model to find all users with a specific role (let's say the role Supervisor). I did my query like this:
$supervisors = $this->User->find('all', array(
'contain' => array(
'Role' => array(
'conditions' => array(
'Role.name' => 'Supervisor'
)
)
)
));
But the above query returns me all the users in my users table. It does not return only the users with role Supervisor. I know that if I do two queries, one on the Role model to find the id of the role type 'Supervisor' and then do another query on the User model and pass the id of the supervisor role record in the conditions on my User model like this:
$supervisor_role_id = $this->Role->field('id', array('Role.name' => 'Supervisor'));
$supervisors = $this->User->find('all', array(
'conditions' => array(
'User.role_id' => $supervisor_role_id
)
));
The above queries will give me the desired result. But I don't wanna do 2 queries to do this. Why doesn't the first approach work. Any idea please?
Thank you
The reason your attempt didn't work
CakePHP's Containble Behavior creates separate queries for each model. So - what you did was basically described like this: "Find all Users. Also find any Roles with the name of 'Supervisor". As you can see, there is no condition that crosses between the two.
So, you can do one of the following:
1) [easy way] Query the other way around
Query from the Role model and contain it's user(s). This pulls the role you want (based on your provided conditions) then contains any/all of it's users.
Note - if you've already loaded the 'User' model (or it's been loaded by default because you're in the UsersController), you can run your find like this: $this->User->Role->find(..... - so you don't have to load the Role model separately.
2) Use JOINs (see CakePHP Book on Joining Tables)
This allows you to limit the result of a parent model based on it's associated data.

Save a HABTM record to database CakePHP

I am working on a followers / following system with CakePHP 2.
I have setup my database with a users table, and a user_users table. The users table is the main table containing every user on the system, whilst the user_users table contains the records of followers.
I then have a UsersController, User model and Follower model.
I can successful output a button to either say Follow or Following dependent on whether the currently logged in user is following the user of which the profile they are viewing belongs to, however what I am unable to understand how to do, is create new following relationships in the table. In other words, I do not know how to create records in the user_users table.
I am not sure where the logic for this should go, and thus what my "Follow" button should point to.
This is probably a very simple question, but I am totally stumped. I have tried adding a "follow" action to the UsersController but I cannot get that to work.
Any help much appreciated,
Duncan
HATBM isn't a good fit in this situation. From the cookbook:
HABTM data is treated like a complete set, each time a new data
association is added the complete set of associated rows in database
is dropped and created again so you will always need to pass the whole
data set for saving. For an alternative to using HABTM see hasMany
through (The Join Model)
For this reason, HABTM is mainly good for pretty 'dumb' relationships. I've used it in cases such as where a User has to select many Interests - and they just get a list of checkboxes, where they can click multiple Interests, and save them all in one hit.
In your case, it'll be easier to have a separate table with it's own model. I'd call it Relationships or something similar. It would have an id, followed_by_id, following_id, and any other fields you may need.
I've dug up some code from an old cake 1.3 app, but it should help you out. Your Relationships model would look something like this:
<?php
class Relationship extends AppModel {
var $name = 'Relationship';
var $belongsTo = array(
'FollowedBy' => array(
'className' => 'User',
'foreignKey' => 'followed_by_id'
),
'Following' => array(
'className' => 'User',
'foreignKey' => 'following_id'
)
);
}
?>
Your User's model would have to have relationships like this:
var $hasMany = array(
'Followers' => array(
'className' => 'Relationship',
'foreignKey' => 'following_id',
'dependent'=> true
),
'FollowingUsers' => array(
'className' => 'Relationship',
'foreignKey' => 'followed_by_id',
'dependent'=> true
),
);
Then in your relationships controller, you'd have methods something like this:
function add($following_id = null) {
$this->Relationship->create();
$this->Relationship->set('followed_by_id',$this->Auth->User('id'));
$this->Relationship->set('following_id',$following_id);
$this->Relationship->save();
$this->redirect($this->referer());
}
function delete($id = null) {
$this->Relationship->delete($id);
$this->redirect($this->referer());
}
Note that in that code, I'm modifying the database with a GET request - which I really shouldn't be doing (it's old code, from years ago). You'll want to enforce a POST request for both the add and delete methods, since they're modifying the database.
But still, that code should set you on the right track.

Reflexive many-to-many relationship in CakePHP

I've been searching around for a definitive answer to this issue but have been unable to resolve it. I've recently been working with (and learning) CakePHP and have run across an obstacle. To simplify my database, let's say we simply have two tables:
persons
relationships (or persons_persons)
Persons has a many-to-many relationship with itself - and indeed, two people can have more than one relationship with each other:
persons
-------
*person_id*
name
relationships
-------------
*relationship_id*
person_1_id
person_2_id
start_date
end_date
Now, if I want to say Person1 (id=1) is married to Person2, I would have one entry in the relationships table. person_1_id would be 1, and person_2_id would be two.
I can create this relationship in CakePHP, and show the lists of relationships (and persons) per Person record. However, it's a unidirectional relationship: for Person 1, the query will only pull Relationship objects where person_1_id matches. If I want to query the relationships for Person 2, I'd have to have a second identical row, with the person_1_id and person_2_id swapped.
Here's the models:
class Member extends AppModel {
public $hasMany = array(
'Relationships' => array(
'className' => 'Relationship',
'foreignKey' => 'person_1_id'
)
);
}
class Relationship extends AppModel {
public $belongsTo = array(
'Person1' => array(
'className' => 'Person',
'foreignKey' => 'person_1_id'
),
'Person2' => array(
'className' => 'Person',
'foreignKey' => 'person_2_id'
)
);
}
Any suggestions? It doesn't make logical sense to duplicate Relationship entities when person_1_id is actually no separate than person_2_id.
I think you've got two options:
1. Duplicate the Relationship Record
Look at it from a different perspective; Consider the concept of directed vs. an un-directed graph. Your current schema supports a directed edge leaving one object (Person) and arriving at another. Agreed from your application's perspective, a person can't have a relationship with another, without them knowing.
The amount of space within the database would be negligible if you did choose to go down this route and would be less complex to implement than option 2. Bare in mind that you should put in place measures to ensure the relationship remains symmetrical at all times.
2. Handle the Relationship Asymmetry in Your Application
Create another relationship so your model looks like the following:
class Member extends AppModel {
public $hasMany = array(
'RelationshipsA' => array(
'className' => 'Relationship',
'foreignKey' => 'person_1_id'
),
'RelationshipsB' => array(
'className' => 'Relationship',
'foreignKey' => 'person_2_id'
)
);
}
You then have separate bins for your relationships depending on which side of the relationship your person exists. You then have to put extra logic everywhere so that you can handle the relationship bins as one homogeneous collection.
I'm sorry I couldn't be any more helpful but I can't think off the top my head, how to implement an un-directed graph without building it on top of a directed one.
Update 05/05/13
To summarize the comment thread, setting the finderQuery on the hasMany association can mask the need to duplicate the lookup for the association with person_2_id (Documentation):
'Relationship' => array(
'finderQuery' => 'SELECT Relationship.* FROM relationships AS Relationship WHERE Relationship.person_2_id = {$__cakeID__$} OR Relationship.person_1_id = {$__cakeID__$};'
)
This hides the complex retrieval mechanism but storing relationships may require further thought.

cakephp friendship between users Linking models together

What I need:
A facebook-like friendship system.
User (A) sends a requests for a friendship with User (B)
User (B) confirmes the request
User (A) and User (B) are friends now
My problem:
I'm confused how to work this out. I read a lot on the internet but it did not really helped me...
My Questions:
What kind of link is it in CakePHP? Is it hasAndBelongsToMany? Or hasMany? Or ...?
How do I realise it in the datebase correctly?
How do I link it in the model?
What I already did:
Table: users
Name: id, username, password, ...
users_users table: id, user_id, friend_id, approved
Model:
'User' => array(
'className' => 'User',
'joinTable' => 'users_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
);
"#tereško Thank you! But I get an error: Error: An Internal Error Has Occurred"
First to answer your comment about the "internal error" you getting:
Try setting debug to 2 in config.php you will realize that you will start getting much more understandable errors.
Regarding your first question:
1. Your relation basically looks to like hasMAny since every user has friends.
HABTM will also work here, but it is much more complicated. This decision (what relations to use) also depends on other parts of your system - i.e. for what and how you'd like to use this data in other parts of it.
2. Read here
3. Read there again
A bit more on HABTM and hasMany through the jon model (if you need to store any additional data in the join table while using the same idea as HABTM).
What to do when HABTM becomes complicated?
By default when saving a HasAndBelongsToMany relationship, Cake will delete all rows
on the join table before saving new ones. For example if you have a Club that has 10 Children associated. You then update the Club with 2 children. The Club will only have 2 Children, not 12.
Also note that if you want to add more fields to the join (when it was created or meta information) this is possible with HABTM join tables, but it is important to understand that you have an easy option.
HasAndBelongsToMany between two models is in reality shorthand for three models associated through both a hasMany and a belongsTo
association.
Your current DB structure is awful. I didn't get why you need a table called table - or maybe I got this wrong.If you intend to use HABTM you do not need to create the join model at all - cake will automatically create and populate it for you.
Some more info for HATBM:
Here
There
Here
There

Categories