How to do friend ORM model in fuelphp - many-to-many

I need to do a self referencing many to many relationship in fuelphp orm model.
In the application a user can have other users as friends.
I have a users table, and friends table. Users table stores the main information about the user, the friends table a single row stores the relationship between two users.
Friends table has fields | id | user_id1 | user_id2 |.
Im totaly stuck on how to create a many to many relationship self referencing on the user.
Here are the fuelphp orm relation docs: http://fuelphp.com/docs/packages/orm/relations/many_many.html
Can anyone help me with this?

You simply specify two relations in the $_many_many property.
protected static $_many_many = array(
'children' => array(
'key_from' => 'id',
'key_through_from' => 'parent_id',
'table_through' => 'my_relation_table',
'key_through_to' => 'child_id',
'model_to' => 'Model_User',
'key_to' => 'id',
),
'parents' => array(
'key_from' => 'id',
'key_through_from' => 'child_id',
'table_through' => 'my_relation_table',
'key_through_to' => 'parent_id',
'model_to' => 'Model_User',
'key_to' => 'id',
),
);
Notice that key_through_from and key_through_to are flipped in each relation definition.

Related

I do not understand joining tables

I'm using Cake version 2.5.4
I have two tables.
A call arbols which consists of the following fields:
id (int 11)
nombre (varchar (255)
especie:id (int 11)
The second table called fotos consists of the following fields:
id (int 11)
foto (varchar 255)
foto_dir (varchar 255)
arbol_id (int 11)
Although the Arbol model is related to the Especie model,
I leave it aside to the latter because it is not a reason for consultation.
The Arbol Model has a hasMany relationship with the Foto model.
In the Arbol model I have the following:
public $hasMany = array(
'Foto'=> array(
'className' => 'Foto',
'foreignKey' => 'arbol_id',
'dependent' => true
)
);
In the Foto model I have the following:
public $belongsTo = array(
'Arbol'=> array(
'className'=>'Arbol',
'foreign_key'=>'arbol_id'
)
);
Now, inside ArbolsController in public function view ($ id = null)
I want to do the following SQL query:
SELECT * FROM arboles as a join fotos as f on a.id=f.arbol_id
So I return all the photos related to an id of a particular tree passed as parameter in view
If this query is done using MySQL
$registros=mysqli_query($conexion," select * from arboles as a join fotos as f on a.id=f.arbol_id")
it works.
But if I want to do it using the query method in such ways:
$registros = $this->Arbol->query("select * from arboles as a INNER JOIN fotos as f ON a.id=f.arbol_id");
$registros = $this->Arbol->query("select * from arboles as a INNER JOIN fotos as f ON a.id=f.arbol_id");
It does not work
Reading the Cookbook I see there is a way to make joins.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
I dont understand her
I would appreciate it if you can explain it to me.
From already thank you very much!
You shouldn't be using the query method directly if you can avoid it.
What you can do is using a standard find, joining your tables with containable (or linkable).
Something like this should work:
$registros = $this->Arbol->find('all', array(
'contain' => 'Foto'
));
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
There is another way by you can join the tables in cakephp i.e customized joins
Create an array of tables whom you want to join, such as
$joins = array(
array(
'table' => 'fotos',//Table name
'alias' => 'Foto', //Model name
'type' => 'INNER', // type of join
'conditions' => array(
'Arbol.id = Foto.arbol_id'
) //Condition for join
)
);
$this->Arbol->find('all', array(
'joins' => $joins,
'conditions'=> array(Arbol.id => $id),
'fields' => array()
))
This will return all the photos information related to an id

hasMany relation without table having id column

I am using CakePHP 2.5. I am having following table
CompanyMaster:
company_master_id [PK]
Name and other columns
CompanySignatoryDetails: (has many owners for single company)
company_signatory_details_id [PK]
company_master_id [FK]
Name and other columns
Now, I want to get company details with all owners of that company. Here is what I have tried.
$this->CompanyMaster->bindModel(
array(
'hasMany' => array(
'CompanySignatoryDetails' => array(
'className' => 'CompanySignatoryDetails',
'foreignKey' => false,
'conditions' => array(
'CompanySignatoryDetails.company_master_id = CompanyMaster.company_master_id'
),
),
)
)
);
$this->CompanyMaster->recursive = 2;
$company = $this->CompanyMaster->find('first', array(
'fields' => array('CompanyMaster.*'),
'conditions' => $conditions, //company id in condition
));
I am getting following error:
Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'CompanyMaster.id' in 'field list'
SQL Query:
SELECT `CompanyMaster`.*, `CompanyMaster`.`id` FROM `crawler_output`.`company_master` AS `CompanyMaster` WHERE `CompanyMaster`.`company_master_id` = 1 LIMIT 1
Please let me know how can I bind model without id as column name.
CakePHP will produce a separate query when dealing with hasMany relationships, and therefore you won't be able to reference a field from another table. Only belongsTo and hasOne relationships produce a JOIN.
However, you don't need to add conditions to the relationship. The following should just work fine:
$this->CompanyMaster->bindModel(array(
'hasMany' => array(
'CompanySignatoryDetails' => array(
'className' => 'CompanySignatoryDetails',
'foreignKey' => 'company_master_id',
),
)
));
Don't forget to define your primary keys for CompanyMaster:
class CompanyMaster extends AppModel
{
public $primaryKey = 'company_master_id';
}
and for CompanySignatoryDetails:
class CompanySignatoryDetails extends AppModel
{
public $primaryKey = 'company_signatory_details_id';
}
Well, for instance, let your query looks like this:
select CompanyMaster.*,CompanySignatoryDetails.* from
CompanyMaster as cm inner join CompanySignatoryDetails as cd on
cm.company_master_id=cd.company_master_id
order by cm.company_master_id;
You will get all fields from two tables, ordered by company_master_id field. You may reduce number of fields, displayed by this query, by explicitly designate them like this:
select cm.company_master_id, cd.name from....
HNY!(Happy New Year!!)

Database indexes cakePHP

I have two tables, namely 'Customer' and 'Event'. The relations between these two are as follows:
Event
var $belongsTo = array(
...
'Customer'=>array(
'className' => 'Customer',
'foreignKey' => 'customer_id'
)
);
Customer
var $hasMany = array(
'Event' => array(
'className' => 'Event',
'foreignKey' => 'customer_id',
'dependent' => false,
)
);
Each and every customer record holds a company id as well as currently logged in user. What I would like to achieve is to get all of the events for a day, related only to a particular company, but that is of course not working since the event table does not hold company id. Maybe the following find call will help to understand the issue better:
$conditions = array('company_id'=>CakeSession::read("Auth.User.company_id"), 'date'=>date("Y-m-d", $tomorrow));
$tomorrowsEvents = $this->find('all', array(
'conditions'=>$conditions, 'contain'=>array('User', 'Customer')));
Moreover, a customer belongs to a company and a company has many customers, just as follows:
Customer
var $belongsTo = array(
'Company' => array(
'className' => 'Company',
'foreignKey' => 'company_id',
'dependent' => false,
),
);
Company
var $hasMany = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'company_id',
'dependent' => false
),
'Customer'=>array(
'className' => 'Customer',
'foreignKey' => 'company_id',
'dependent' => false
)
);
Any help is much appreciated.
I would actually do this query "backwards" by doing it from Customer, and using the containable behavior to contain the related Events:
$this->Customer->find('all',
array(
'conditions' => array(
'company_id' => CakeSession::read("Auth.User.company_id")
),
'contain' => array(
'Event' => array(
'conditions' => array(
'Event.date' => date("Y-m-d", $tomorrow)
)
)
)
));
In your case it seems that Events have many companies and companies have many events. This is ideal situation for hasAndBelongsToMany relationship. However, you have to focus on the className and joinTable properties to handle the non convenient naming of the join table customers.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm
you need to rethink the problem, because a user can be (customer or company) then they have a group or they are in a type of user. then a user belongs to a group or user type, this group can be a client or company .
users belongsto a group
group has many user
users hasmany events
events has many users
You can tell if is customer or company is the type of group that owns
table___group
id ____ category ____ subcategory
1 ____ customer ____ example
2 ____ company ____ example

CakePHP model associations - Random order on retrieve of associated model for HABTM

I am retrieving data:
$mydata = $this->ProductList->find('all', array('order' => 'rand()', 'conditions' => array('name' => 'we love')));
I have set up a HABTM relationship to the Product model. As you can see, I am fetching all products in the 'we love'-list. Now, I want those Products I am retrieving to be randomised. But they are not, instead the MySQL is randomised on the ProductList model as you can see in the SQL. Why is that? How can I get the random fetch on the Products instead?
Resulting MySQL query:
SELECT `ProductList`.`id`, `ProductList`.`name` FROM `database`.`product_lists` AS `ProductList` WHERE `name` = 'we love' ORDER BY rand() ASC
SELECT `Product`.`id`, `Product`.`category_id`, `Product`.`name`, `Product`.`price`, `Product`.`description`, `ProductListsProduct`.`product_list_id`, `ProductListsProduct`.`product_id` FROM `database`.`products` AS `Product` JOIN `database`.`product_lists_products` AS `ProductListsProduct` ON (`ProductListsProduct`.`product_list_id` = 3 AND `ProductListsProduct`.`product_id` = `Product`.`id`)
EDIT:
There are so many different ways to approach this; to get a random product from a user's product list. You could do it with PHP - just find all of the products and then use rand() to pick on from the returned array. You could set a Model query condition. The list goes on...
I would probably create an alias to the Product model in ProductList called RandomProduct. You could set the query for the retrieved product when you set the relationship:
public $hasMany = array(
'RandomProduct' => array(
'className' => 'Product',
'foreignKey' => 'product_list_id',
'order' => 'Rand()',
'limit' => '1',
'dependent' => true
)
);
You can then use the containable behavior so that this model is only retrieved when you need it. (You wouldn't need to do this if recursive finds are greater than -1, but I usually do that as best practice so that my models only query for the data that they need.) The following would return any ProductList called 'we love' and a "random" product associated with that list.
$mydata = $this->ProductList->find(
'all',
array(
'conditions' => array(
'name' => 'we love'
)
),
'contain' => array(
'RandomProduct'
)
);

CakePHP: Table Joins

I am new to CAKEPHP and using joins for the first time. I read the documentation as well.
Now i have two models, One is for Users and other is for Status.
In Status table i have a foreign Key which is User Id in users table.
I want to use $hasMany with conditions such that if a logged in user Share a status it should update the status table having UID in the foreign key and UID is Users table primary key
I dont know what and how to do that.
What i believe is that it should be something like this
class User extends AppModel
{
var $name = 'User';
var $hasMany = array(
'Status' => array(
'conditions' => array('Status.FK' => 'User.id')
)
);
}
Hope i did it right?
for hasMany put this code in your User Model:
/**
* #see Model::$hasMany
*/
public $hasMany = array(
'Status' => array(
'className' => 'Status',
'foreignKey' => 'Status.FK',
'dependent' => true,
),
);
but The Best way is that using belongsTo in your Status Model,Because belongsTo has fewer queries than hasMany method. and in your controller you can use the Status model to retrieving users with their status. for example:
In Status Model:
/**
* #see Model::$belongsTo
*/
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'Status.FK',
),
);
then In your Controller for find specific rows from database you can use :
$this->recursive = 1;
$this->Status->find('all',array('conditions' => array('User.id' => $id)));