Should the following join structure work for a CakePHP find? - mysql

Is the following join structure correctly formatted to work with a CakePHP find? This doesn't seem to be working when I use it along with conditions and my gut tells me that the structure is off. I'm new to joins, so any help is appreciated.
'joins' => array(
(int) 0 => array(
'table' => 'cheeses_milk_sources',
'alias' => 'CheesesMilkSource',
'type' => 'INNER',
'conditions' => array(
(int) 0 => 'Cheese.id = CheesesMilkSource.cheese_id'
)
),
(int) 1 => array(
'table' => 'milk_sources',
'alias' => 'MilkSource',
'type' => 'INNER',
'conditions' => array(
(int) 0 => 'CheesesMilkSource.milk_source_id = MilkSource.id',
'CheesesMilkSource.milk_source_id' => '1'
)
)
),
'conditions' => array(
'AND' => array(
(int) 0 => array(
'Cheese.cheese_producer_id' => (int) 35
),
(int) 1 => array(
'Cheese.active' => (int) 1
)
)
),

The confusing part is
'conditions' => array(
(int) 0 => 'CheesesMilkSource.milk_source_id = MilkSource.id',
'CheesesMilkSource.milk_source_id' => '1'
)
You are mixing an array element without a key with one with a key equal to CheesesMilkSource.milk_source_id.
if you need to specify two conditions on the join, do it like
'conditions' => array(
'CheesesMilkSource.milk_source_id = MilkSource.id AND CheesesMilkSource.milk_source_id = 1'
)
perhaps the next snippet will equally work, but I'm not sure and can't test it at the moment - let me know if it does with a comment.
'conditions' => array(
'CheesesMilkSource.milk_source_id = MilkSource.id',
'CheesesMilkSource.milk_source_id = 1'
)
But since you're joining the tables, maybe you should put CheesesMilkSource.milk_source_id = 1 in the general conditions of the find:
'conditions' => array(
'Cheese.cheese_producer_id' => 35,
'Cheese.active' => 1,
'CheesesMilkSource.milk_source_id' => 1,
)
Notice you don't need to specify AND as this is the default way of joining conditions.

Related

Cakephp Multiple Table search in container behaviour

hello I want to get results from multiple tables using the keyword which user has typed. The problem I am having is I don't know how can I do search on that table which is getting through contain
Here's my query
public function getGigPostBasedOnSearch($keyword){
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User','UserInfo', 'GigPostAndCategory.Category','Location','GigPostAndCalender'
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
)
)
//'OrderGigPost.request' => 0
),
'order' => 'GigPost.gig_post_id DESC',
'recursive' => 0
));
}
This query works fine. I want to search keyword in category table also.I want to do something like this
array('Category.cat_name LIKE' => '%'.$keyword.'%')
Please help me how can I search in Category table as well
Thank you
Model GigPost.php
<?php
class GigPost extends AppModel
{
public $useTable = 'gig_post';
public $primaryKey = 'gig_post_id';
public $hasAndBelongsToMany = array(
'Category' =>
array(
'className' => 'Category',
'joinTable' => 'gigpost_category',
'foreignKey' => 'gig_post_id',
'associationForeignKey' => 'cat_id',
'unique' => true,
)
);
public $hasOne = array(
'Location' => array(
'className' => 'Location',
'foreignKey' => 'gig_post_id',
'conditions' => array('GigPost.gig_post_id = Location.gig_post_id')
));
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'fields' => array('User.user_id','User.email','User.active')
),
'UserInfo' => array(
'className' => 'UserInfo',
'foreignKey' => 'user_id',
)
);
public function getGigPostBasedOnSearch($keyword){
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User','UserInfo', 'GigPostAndCategory.Category'=>array(
'conditions'=>array(
'OR' => array(
array('Category.cat_name' => '%'.$keyword.'%'),
),
)
),'Location','GigPostAndCalender'
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
// array('Category.cat_name LIKE' => '%'.$keyword.'%'),
)
)
//'OrderGigPost.request' => 0
),
'order' => 'GigPost.gig_post_id DESC',
'recursive' => 0
));
}
}
Your issue is that the relationship between GigPost and Category is HABTM, so when you use contain Cake has to do a separate query to retrieve the related categories as there is not a one-on-one association. To get round this you need to manually perform a join rather than contain the categories:-
$this->find('all', array(
'contain' => array(
'User', 'UserInfo', 'GigPostAndCategory.Category', 'Location', 'GigPostAndCalender'
),
'joins' => array(
array(
'table' => 'gigpost_category',
'alias' => 'GigPostCategory',
'type' => 'INNER',
'conditions' => 'GigPost.id = GigPostCategory.gig_post_id'
),
array(
'table' => 'categories',
'alias' => 'Category',
'type' => 'INNER',
'conditions' => 'Category.id = GigPostCategory.cat_id'
)
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
array('Category.cat_name LIKE' => '%'.$keyword.'%'),
)
)
),
'order' => 'GigPost.gig_post_id DESC',
'group' => 'GigPost.id',
'recursive' => 0
));
This ensures that the categories will be included with the data returned by the primary query.
You will probably need to modify the joins array a bit as you don't appear to be using Cake naming conventions for your table so I am not sure what you have named things. However, this should put you on the right track.

Finding all with a JOIN query giving a single result instead of multiple

I have the following CakePHP code; I want it to return all rows (two in this case)
public function orderdetails($orderId)
{
$Productsaleslist = $this->Productsales->find('all', array(
'joins' => array(
array(
'table' => 'product',
'alias' => 'prod',
'type' => 'INNER',
'conditions' => array(
'prod.id = Productsales.product_id'
)
),
array(
'table' => 'sales_order_address',
'alias' => 'sod',
'type' => 'INNER',
'conditions' => array(
'sod.id = Productsales.sales_order_address_id'
)
),
),
'fields' => array(
'Productsales.*',
'prod.name',
'prod.image_url',
'sod.*'
),
'conditions' => array(
'Productsales.product_sales_slno' => $orderId
)
)
);
$this->set('Productsaleslist', $Productsaleslist);
}
$orderId comes from a URL parameter, and it contains the value of product_sales_slno (RAJ201701211485025418). This should retrieve two integers, but I'm only getting one as shown below.
How can I fix this?

GROUP and COUNT() multiple fields in CakePHP

This is my database:
week, subbizname, devicetype
20141203, common, PC
20141203, unknown, PC
20141210, KRsinKD, SP
20141210, unknown, PC
20141217, Unknown, SP
20141217, Chintai, TAB
....
I am trying to get the number of records for each unique couple devicetype/week.
Ex:
array(
20141203 => array(
'PC'=>2,
'TAB'=>0,
'SP'=>0
),
20141210 => array(
'PC'=>1,
'TAB'=>0,
'SP'=>1
),
...
.....
)
UPDATE:
I have used query:
$data = $this->Test->find('all', array(
'conditions'=>array(
'OR'=>array(
array('devicetype'=>'PC'),
array('devicetype'=>'SP'),
array('devicetype'=>'TAB'),
)
),
'fields'=>"devicetype,week,COUNT(devicetype) AS countDevice",
'group'=>"week,devicetype"
));
Thing is, it returns something like this:
(int) 0 => array(
'Test' => array(
'devicetype' => 'PC',
'week' => '20141126'
),
(int) 0 => array(
'countDevice' => '34844'
)
),
(int) 1 => array(
'Test' => array(
'devicetype' => 'SP',
'week' => '20141126'
),
(int) 0 => array(
'countDevice' => '32401'
)
),
(int) 2 => array(
'Test' => array(
'devicetype' => 'TAB',
'week' => '20141126'
),
(int) 0 => array(
'countDevice' => '4256'
)
),
(int) 3 => array(
'Test' => array(
'devicetype' => 'PC',
'week' => '20141203'
),
(int) 0 => array(
'countDevice' => '96564'
)
),
(int) 4 => array(
'Test' => array(
'devicetype' => 'SP',
'week' => '20141203'
),
(int) 0 => array(
'countDevice' => '97450'
)
),
But I do not manage to get the expected result.
Surely there must be a better way.
How can I fix this?
Using your $data variable, you can do:
$d = array();
foreach ($data as $value) {
$week = $value['Test']['week'];
if (isset($d[$week])) {
$d[$week][$value['Test']['devicetype']] = $value[0]['countDevice'];
} else {
$d[$week] = array($value['Test']['devicetype'] => $value[0]['countDevice']);
}
}
print_r($d); // $d will contain the data in your required format

CakePHP 2.x: Join on belongsto

in my model 'mesn' i have belongsto relations:
public $belongsTo = array(
'Order' => array(
'className' => 'Order', 'foreignKey' => 'order_id', 'conditions' => '', 'fields' => '', 'order' => ''
), 'SaleOrder' => array(
'className' => 'SaleOrder', 'foreignKey' => 'sale_order_id', 'conditions' => '', 'fields' => '',
'order' => ''
), 'ShippedBox' => array(
'className' => 'Box', 'foreignKey' => 'shipped_box_id', 'conditions' => '', 'fields' => '',
'order' => ''
)
); /* * * hasMany associations** #var array
In one of my model-functions i want to join another table on the "belongsto" "ShippedBox" (table: boxes). But doesn't matter how i try to write the join i get an error message of unknown column:
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => 'shipments',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'MyShipments.id = ShippedBox.shipment_id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
I have tried:
'MyShipments.id = ShippedBox.shipment_id'
and
'MyShipments.id = box.shipment_id'
and even
'MyShipments.id = Boxes.shipment_id'
where the table "boxes" with the field "shipment_id" exists.
How can i get this join working?
'MyShipments.id = box.shipment_id'
to:
'MyShipments.id = Box.shipment_id'
Also what about this:
$arr_s_result = $this->find('all', array(
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
The belongsTo join is done automatically.
I think you'll need to do something like use subqueries to get what you want -
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => '(SELECT boxes.id, [enter other fields you need here] FROM shipments JOIN boxes ON boxes.shipment_id = shipments .id)',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'Mens.shipped_box_id = MyShipments.id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));

CakePHP: Using bindModel to trace backwards by 3 models?

I have the following models:
-> = 1:many, <-> = many:many
User<->Product->MessageList<->Message
My goal with this query is to find all messages corresponding to the logged in . I also filter out messages that have been read (I find the messages ids in the prior find and store them in $messageIdsReadByPerson).
Here is my attempt:
// only grab messages belonging to this user
$this->Message->unbindModel(array('hasAndBelongsToMany'=>array('MessageListsMessage')));
$this->Message->bindModel( array(
'hasOne' => array(
'MessageListsMessage' => array(
'className' => 'MessageListsMessage',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageListsMessage.message_id = Message.id'
)
),
'MessageList' => array(
'className' => 'MessageList',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageList.id = MessageListsMessage.message_list_id'
)
),
'Product' => array(
'className' => 'Product',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'Product.id = MessageList.product_id'
)
),
'ProductsUser' => array(
'className' => 'ProductsUser',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'ProductsUser.product_id = Product.id'
)
),
'User' => array(
'className' => 'User',
'foreignKey' => false,
'conditions' => array(
'User.id = ProductsUser.user_id',
'User.id' => $this->Auth->user('id')
)
)
)
));
$messages = $this->Message->find('all', array(
'recursive' => -1
));
$this->set('messages', $messages);
But that only gives this query:
SELECT `Message`.`id`, `Message`.`text`, `Message`.`url` FROM `messages` AS `Message` WHERE 1 = 1
How can this be done properly using bindModel (or some easier method that I'm unaware of, although joins is apparently not the way to go).
EDIT:
this doesnt work either:
function index() {
// only grab messages belonging to this user
$messages = $this->Message->find('all', array(
'contain' => array(
'MessageList' => array(
'Product' => array(
'User.id = ' . $this->Auth->user('id')
)
)
)
));
$this->set('messages', $messages);
}
I think the same answer applies as I just gave here:
How to get only products with images in CakePhp
containable or recursive higher