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
Related
I'm having some problems using this old framework I had to manage.
I have these tables:
GROUP -> HAS MANY -> MONITOR
MONITOR -> HAS MANY -> [ EVENTS , ZONE ]
MONITOR -> HAS_AND_BELONGS_TO_MANY -> GROUP
For GROUP -> MONITOR Relationship, a join tables has been created by Cake called GROUP_MONITOR.
This is the HasMany Configuration on Group Model:
'Monitor' => array(
'className' => 'Monitor',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'GroupId',
'associationForeignKey' => 'MonitorId',
QUESTION 1:
I'm trying to retrieve all groups with all the related monitors. I found the recursive key that allow to go deeply in relations:
$all_groups = $this->Group->find('all', array('recursive' => 1));
I got this error:
Column not found: 1054 Unknown column 'Monitor.GroupId' in 'field list'"
It seems like Cake is not using the "Groups_Monitors" table but is searching groupId in the Monitor Table;
QUESTION 2:
Trying to get Groups querying Monitors, with recursive to 1 I got all groups correctly but also all other Monitor's HasMany relations.
$all_monitors = $this->Monitor->find('all',array("recursive" => 1));
Is it possible to exclude some HasMany relations in find to have a reduced amount of data?
You say you have
GROUP -> HAS MANY -> MONITOR
"Has many" doesn't use a join table. The way this relation works is "monitor" has to have a foreign key that references a group. If you want to use the join table you should use "has and belongs to many".
For Q2, use the containable behavior. You'll be able to specify in detail what data and which models you want fetched from the DB. https://book.cakephp.org/2/en/core-libraries/behaviors/containable.html
I have two different tables as Post and Post_Info.
I want to get all the details using post_id in cake php from both the tables. The Post_Info table having post_id as foreign key and other related details.
I am new to Cakephp and I don't know how to get data from multiple tables in Cakephp.
I can get data from Post table using following query in Cakephp.
Following code is getting data from Post table.
$userdata = $this->Post->find('first', array(
'conditions' => array('Post.post_id' => $post_id)
));
To achieve this you have to do two things.
Make a relation of belongsTo in PostInfoTable.php in your model folder. you can read more about it here.
Once you have made the relationship all you have to do is use "contain" in your query along with the Model name. Your query will be modified as below
$userdata = $this->Post->find('first', array(
'conditions' => array('Post.post_id' => $post_id),
'contain' => ['PostInfo']
));
And you are good to go.
Moreover, I will recommend you to go through the documentation at least once it will be a great help to you.
I am building a backend panel for a website with Laravel Backpack. It is really nice, but I have noticed that relationship queries are very expensive.
I have two models: Product and Center with a many to many relationship between them. In my CenterCrudController I have defined a field this way:
$this->crud->addColumns([
// More fields...
[
'label' => 'Products',
'type' => 'select2_multiple',
'name' => 'products', // the method that defines the relationship in your Model
'entity' => 'products', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'model' => 'App\Models\Product', // foreign key model
'pivot' => true, // on create&update, do you need to add/delete pivot table entries?
],
// More fields...
]);
It works fine, showing a select multiple field with related models. But the query used is SELECT * FROM products, which is highly expensive (table products have thousands of records with about 25 columns).
In this example I only need id and name fields. I am looking for something like Query Builder select() method.
Is there a way for optimizing this type of query?
Thanks in advance!
Not sure if this is actually an answer, but I'll post it anyway.
The best solution (as pointed by #tabacitu) was using select2_from_ajax field. It doesn't slow page load and make an ajax request for retrieving data only when user clicks on the select field.
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.
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.