Cakephp Avoid wrong condition betweeen models - cakephp

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).

Related

cakephp how to avoid the repeating columns in query result

I have a query like
$p = $this->Products->findById( $id )
->select(['name', 'description', 'category_id', 's.name', 'pp.price'])
->join([
'table' => 'sizes',
'alias' => 's',
'type' => 'INNER',
'conditions' => 's.category_id = Products.category_id',
])
->join([
'table' => 'products_prices',
'alias' => 'pp',
'type' => 'LEFT',
'conditions' => 'pp.size_id = s.id AND pp.product_id = Products.id',
]);
The problem is if the product has 10 different sizes, 10 rows will be produced with repeating name, description, category_id elements
Is there a way to rewrite it so the size's name and prices are delivered as array as a sub-array?
Maybe just use Containable instead of Join? You can run a find() on your Products and contain Sizes and ProductPrices. This would get you the array/sub-array you're looking for.
The only down-side is that it would still pull products even if they don't have a matching size.
It's tough to tell what you're really going for, since you're joining on category_id, which isn't really referenced. Maybe if you explain in more detail what the goal of this query is, we could provide a better answer on how to achieve.

cakephp - issue for joining multiple tables

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?

Retrieving values from multiple tables using CakePHP model associations

I have a ProductsController in which I am retrieving Products data and need to also retrieve the Category Name. (Note: My Products table has only Category_ID in it), how can I do that using CakePHP model associations?
I have seen examples in which the ID of the main data table (in my case, Products table) is a Foreign Key in the Associated Table. However, my case slightly different in that the Category_ID (from the secondary table) is part of the Main table (Products table).
I am not able to retrieve the Category Name using CakePHP model config. Can you help?
My ProductsController is on Products table which has
ID
Prod_Name
Category_ID
....
My Categories table is like
ID
Cat_Name
In my ProductsController I want to retrieve Cat_Name for Products being retrieved.
In your Product Model, use the association:
var $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
When retrieving your Products data use find method:
$this->set('variable', $this->Product->find('all'));
Once its in your View, it is an array containing all the products and its category.
Like this:
<?php
foreach($variable as $itemInTable):
echo 'Product:' . $itemInTable['Product']['Prod_Name'];
echo 'Its Category:' . $itemInTable['Category']['Cat_Name'];
endforeach;
?>
fzmaster's answer is correct. When you have a foreign key in Table A that corresponds to an id in Table B, it is said that the Model A "belongs to" Model B. At the same time, there could be an inverse relationship where Model B "has many" Model As.
The associations are fairly straightforward within that context and if you use the Cake naming conventions, you can associate the models with minimal additional code:
class Product extends AppModel{
var $belongsTo = array( 'Category' );
}
class Category extends AppModel{
var $hasMany = array( 'Product' );
}
At that point, CakePHP's Model::Find() method will automatically retrieve associated models unless you limit it with $recursive or by using the Containable behavior.

Doctrine Relationship on a namespaced table

I have several doctrine models that have relationships to other models. Let's call those ItemsOne, ItemsTwo, ItemsThree. Each has a relationship defined to the Products doctrine class (products table) and the relationship is defined as:
$this->hasMany(
'Models_Products as Products',
array(
'local' => 'id',
'foreign' => 'product_id',
)
);
Nothing out of the ordinary there.
I also have another table (prices) which stores namespaced data. By that I mean that the particular table stores data based on a predefined key (i.e. Vinyl, CD, DVD) so the rows would show something like this:
media_namespace entity_id quantity unit_price
CD 4 1000 0.99
DVD 4 2500 1.25
CD 7 3750 0.25
Vinyl 15 75 4.25
The entity_id is the id of each of the models accessing this table. So for instance CD/entity_id = 4 refers to ItemsOne model, DVD/entity_id = 4 refers to the ItemsTwo model, etc.
I want to create a relationship - and I don't know if this can be done - whereas it will be namespaced in the model. So in the above snipped for the products relationship I need something like (for the ItemsOne model):
$this->hasMany(
'Models_Prices as Prices',
array(
'local' => 'id',
'foreign' => 'entity_id',
)
);
However the above will return all the prices with the entity_id matching the ItemsOne table which is partly correct. In the above example if entity_id = 4, it will return the CD record but also the DVD one which is not what I need. I want it to be filtering the data based on the media_namespace table. So in short what I need is:
prices.media_namespace = 'CD' AND prices.entity_id = itemsone.id
Can the above be reflected in a hasMany relationship in Doctrine? I have searched and cannot something that would help.
Any pointers are more than appreciated!
You need to use Doctrine subclasses. Create a subclass for each namespace. This will let you reference a specific set of data by class name.
class Models_Price
subclass Models_Price_CD
subclass Models_Price_DVD
subclass Models_Price_Vinyl
In the Price class, you'll need to specify the following:
public function setUp()
{
parent::setUp();
$this->setSubclasses(
array(
'Price_CD' => array(
'media_namespace' => 'CD',
),
'Price_DVD' => array(
'media_namespace' => 'DVD',
),
'Price_Vinyl' => array(
'media_namespace' => 'Vinyl',
),
)
);
}
Let's make the assumption that ItemsOne uses namespace CD, ItemsTwo uses namespace DVD, and ItemsThree uses namespace Vinyl.
For this situation, you would add the following relationship to each class:
ItemsOne:
$this->hasMany(
'Models_Price_CD as Prices',
array(
'local' => 'id',
'foreign' => 'entity_id',
)
);
ItemsTwo:
$this->hasMany(
'Models_Price_DVD as Prices',
array(
'local' => 'id',
'foreign' => 'entity_id',
)
);
ItemsThree:
$this->hasMany(
'Models_Price_Vinyl as Prices',
array(
'local' => 'id',
'foreign' => 'entity_id',
)
);
Now, each of the Prices relations will return only what you expect. Doctrine, seeing the subclass, will automatically namespace all the queries you perform on that table.

Search record in HABTM relationship - CakePHP

I have a stores and store_details table and now a store_details_stores table.
The Store model has the following:
public $hasAndBelongsToMany = array('StoreDetail');
The StoreDetail model has the following:
public $hasAndBelongsToMany = array('Store');
When I attempt the below query in the stores_controller, I receive an sql error. For some reason the store_details table is not being joined naturally. Is this expected behaviour? Do I need to join this table manually?
$this->Store->find('all', array('conditions' => array('StoreDetail.name' => 'Parking')));
This is expected behavior. You need to set up a bindModel call with your conditions, or you can create a model for your join table and query that directly.
See:
CakePHP Book - HABTM
Modelizing HABTM Join Tables
$this->Store->bindModel(array(
'hasAndBelongsToMany' => array(
'StoreDetail' => array('conditions'=>array('StoreDetail.name' => 'Parking')
))));
$this->Store->find('all');
I would recommend applying the condition to the association before you do your find, using the bindModel method.
/**
* Apply a condition to the association
*/
$this->Store->bindModel(array(
'hasAndBelongsToMany' => array(
'StoreDetail' => array('conditions' => array('StoreDetail.name'=>'Parking'))
)));
/**
* Find all Stores that have an associated StoreDetail.name of 'Parking'
*/
$this->Store->find('all');

Resources