I am joining multiple tables like the following.
$recommend_logs = $this->RecommendingProductLog->find('all', array(
'recursive' => 2,
'fields' => array('Product.ProductName', 'Product.Gender', 'Product.Price', 'RecommendingProductLog.preference', 'Brand.BrandName'),
'conditions' => array('RecommendingProductLog.user_id' => $user_id),
'contain' => array('Product', 'Product.Brand')
));
I am getting this query from log.
SQL Query: SELECT `Product`.`ProductName`, `Product`.`Gender`, `Product`.`Price`, `RecommendingProductLog`.`preference`, `Brand`.`BrandName`, `Product`.`id` FROM `database`.`recommending_Product_log` AS `RecommendingProductLog` LEFT JOIN `database`.`Products` AS `Product` ON (`RecommendingProductLog`.`Product_id` = `Product`.`id`) WHERE `RecommendingProductLog`.`user_id` = 32
Even though 'Product' table is a child table of 'Brand' table, somehow I don't see 'Brand' table in the query. That's why I am getting an error 'Unknown column 'Brand.BrandName' in 'field list'.
I specified 'Brand' in the Perfume model as 'belongsTo' and 'Perfume' in RecommendingPerfumeLog model and 'Perfume' as hasMany in Brand model.
can somebody point where the problem is?
thanks.
Have you correctly put the foreign keys on the respective tables of the relation? In this case Product have to have a a key with the name brand_id and it must be a foreign key to the brand id field.
Also check this and try to put your joins.
I don't remenber this 'contain' field from the docs. Are you using the latest version?
Related
I am trying to join the following two tables in a controller:
artifacts_publications
----------------------
id
artifact_id
publication_id
and
authors_publications
--------------------
id
author_id
publication_id
Other tables which have associations like belongsTo and HasMany set up easily join using contain(). For these tables, suppose no association is already defined. In the end, I want to join another table to the join of these tables but for now I cannot get these two joined.
The Controller uses
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager;
In the index() action of the controller, I have
$options['joins'] = [
[
'table' => 'authors_publications',
'alias' => 'j',
'type' => 'LEFT OUTER',
'conditions' => [
'authors_publications.publication_id = artifacts_publications.publication_id',
],
],
];
$query = TableRegistry::getTableLocator()->get('artifacts_publications')->find('all', $options);
$query->limit(2);
debug($query);
debug($query->toArray());
The resulting SQL query is somewhat like this, but I have shortened long identifiers:
SELECT id, artifact_id, publication_id
FROM artifacts_publications
LIMIT 2;
Executing that query also shows no join. I tried to follow cakePHP table joining two tables issue but I still cannot join. Hand-written SQL worked but it is not elegant. What am I missing here?
#Utsav
Try to use the Containable behaviour of CakePHP by switching the 'join' with 'contain'.
$options = [
'fields' => [
'ArtifactsPublication.fieldsYouWant'
],
'conditions' => [
'ArtifactsPublication.id' => $artifactId
],
'contain' => [
'AuthorsPublication'
]
];
You can also set the recursive to define if you want to get the contained model's linked models. Alternativly you can specify in the fields option what fields you want from the artifacts_publications Model and then just contain the authors_publications Model.
Hope this helps as I have had bad experiences with manual joins in CakePHP, also the CakePHP standard is to use contain. Just note a contain cannot retrieve distant joined data.
Cheers mate :)
I am using cakephp 2.5, and need to join Vehicle table with Address table where vei_id is the foreign key
I have one find operation that is generating a wrong condition for the two models: Vehicle and Address.
Address has the vei_id column wich is the foreign key to join the vehicle table.
The query is generating vehicle_id as the column to join the two tables, the probem is that this column does not even exists.
I have mapped the two models using the vei_id column.
How can i avoid this situation ? seems cakephp try to guess the join column even if i have already write the condition using the column i want.
//Vehicle Model
public $hasOne = array(
'Address' => array(
'className' => 'Address',
'conditions' => array('Vehicle.vei_id = Address.vei_id'),
'foreignkey' => false
)
//Address Model
public $belongsTo = array(
'Vehicle' => array(
'className' => 'Vehicle',
'conditions'=> array('Vehicle.vei_id=Address.vei_id'),
'foreignKey' => 'vei_id'
),
);
//At vehiclecontroller
$data = $this->Vehicle->find('first', array(
'conditions' => array('Vehicle.vei_id' => $vehicleId),
'contain' => array(
'Address' => array('conditions'=> array('Address.vei_id'=>'Vehicle.vei_id',
'Vehicle.vei_id' => $vehicleId
),
)),
));
it generates this line :
LEFT JOIN Address ON (
Address.vehicle_id = Vehicle.vei_id
AND Address.vei_id = 'Vehicle.vei_id'
AND Vehicle.vei_id = 123
)
Where this column does not exists :
Address.vehicle_id = Vehicle.vei_id
Your query looks little bit confusing:
Just look at following conditions within contain:
'contain' => array(
'Address' => array('conditions'=>
array(
'Address.vei_id'=>'Vehicle.vei_id', // why is this ?
'Vehicle.vei_id' => $vehicleId
),
));
Why are you using following conditions within contain ?
Address.vei_id'=>'Vehicle.vei_id
Did you do that to join two tables ?
When you use contain these things are done by cakephp's convention.
Address table is already joined with vehicle table.
See here:Cakephp contain.
Also why not to follow cakephp convention?
If you have vehicles table,
the foreign key would be vehicle_id according to cakephp convention.
And if you have users table foreign key would be user_id.
These things also reduces your work and make things easier.
See Here: (cakephp model and database conventions).
This is with CakePHP 2.4. I have a table (table1) which is connected to three others (tables 2 to 4) through a hasMany through connection. All four tables are in a non-default database. Although I'm using hasMany from tables 2-4 to table 1 and in the class for table1
public $belongsTo = array('table2', 'table3', 'table4');
When I try and display the view for table1 I get the error
Table table1 for model model1 was not found in datasource default
So it's looking in datasource default even though all four tables have are in the non-default database (specified using $useDbConfig).
Although the documentation doesn't say why you would want to specify the classname, even if it follows the naming convention, this appears to be the solution:
public $belongsTo = array('table2', => array(
'className' => 'table2'),
'table3'=> array(
'className' => 'table3'),
'table4'=> array(
'className' => 'table4'));
Sorry if this is obvious - I'm trying to do a find() on a join table and failing, whats the correct syntax to do this?
Basically I have expenseCode table with a HABTM releationship with the expense table.
In my expenseCode model I have:
public function beforeDelete($cascade = false) {
$count = $this->Expense->find("count", array(
'conditions' => array('expense_code_id' => $this->id)
));
if ($count == 0) {
return true;
} else {
//$this->Session->setFlash('Record cannot be deleted as it has ' . $count . 'number of expenses attached to it');
return false;
}
}
If I uncomment the setFlash() I get the error.
Where am I going wrong? Thanks in advance.
Unfortunately it's not possible to perform such a query on the HABTM join table from one of the parent models without some extra work. I'm assuming that Expense is the parent model and ExpensesCode the join model?
A common way is to modelise the HABTM join table. Say you have an expenses and codes table which are joined by expenses_codes:
$this->Expense->bindModel(array('hasOne' => array('ExpensesCode')));
$this->Expense->find('all', array(
'fields' => array('Expense.*'),
'conditions' => array('ExpensesCode.expense_code_id' => $this->id)
));
However, Cake also auto-iniatlises a model for the join table when a HABTM association is defined (see the manual, and the "with" key in the list of possible keys).
So this syntax would let you directly query the join table:
$this->Expense->ExpensesCode->find('all', array(
'conditions' => array('ExpensesCode.expense_code_id' => $this->id)
));
The query above will net you with an array containing only the results from the join table, as it doesn't perform a join like the first procedure. So you would have to perform a second find() on the Expense model to find the expenses related to the expense_code_id from ExpensesCode.
EDIT:
It's a framework convention that HABTM join tables should be underscored and alphabetically ordered. So if the HABTM join table is called codes_expenses, it's auto-modelised as CodesExpense.
You can also work in a simpler way if you create another model with two hasMany relations instead of one with HABTM.
HasAndBelongsToMany between two models is in reality shorthand for three models associated through both a hasMany and a belongsTo association.
I found it is one of the simplest ways to save and retrieve data.
For more information:
http://book.cakephp.org/2.0/en/models/saving-your-data.html#what-to-do-when-habtm-becomes-complicated
I have problem with updating (better updating not recreating) extra field in HABTM join table. I searched google and other sources, but struggled for 4 days now.
I have models:
class Tutorial extends AppModel {
var $hasAndBelongsToMany = array(
'TutorialCategory' => array(
'with' => 'TutorialCategoriesTutorial',
'order' => 'TutorialCategoriesTutorial.order_by ASC',
'unique' => true,
);
}
class TutorialCategory extends AppModel {
var $hasAndBelongsToMany = array(
'Tutorial' => array(
'with' => 'TutorialCategoriesTutorial',
'unique' => true,
);
}
join table tutorial_categories_tutorial have id, tutorial_id, tutorial_category_id, order_by fields.
I am trying to update order_by field like:
$order = 1;
foreach($tutorials as $i => $tutorial) {
$this->data[$i]['Tutorial']['id'] = $tutorial['Tutorial']['id];
$this->data[$i]['TutorialCategory']['id'] = $tutorial['TutorialCategory']['id];
$this->data[$i]['TutorialCategoriesTutorial']['order_by'] = $order;
++$order;
}
$this->Tutorial->bindModel(array('hasMany' => array('TutorialCategoriesTutorial')));
$saved = $this->Tutorial->saveAll($this->data);
This is deleting and crating new records in join table, but not setting order_by at all. I want to update record and set now order_by value. I tried hasMany through but no luck.
Please help and/or give advice and explanation.
Thank you!
As you have added extra data (order field) to the HABTM join model, you have actually exceeded the capabilities of a simple HABTM relationship with CakePHP. What you actually need to setup is a hasMany Through relationship.
In your case you'll basically make a "membership" model with Tutorial ID, catergory id and as much data as you want to assign to it. You will then define the relatioships as Membership belongsTo Tutorial & Category. The book probably has a better example than what I've just explained!
The main reason for this is that each "membership" record is treated as a normal record with no HABTM behaviour attached to it, so you can edit, delete and add records individually and easily.