I want Cakephp code in my query - cakephp

I am Cakephp Beginner.
I want this query with cakephp..
Original Query..
SELECT `Advertisement`.*, `Gallery`.`image` FROM `moenatmi_moen`.`advertisements`
AS `Advertisement` LEFT JOIN `moenatmi_moen`.`galleries` AS `Gallery` ON
(`Gallery`.`advertise_id` = `Advertisement`.`id` AND `Gallery`.`main_ad_image`
= 1) WHERE `Advertisement`.`status` = 1 AND `Advertisement`.`category_id` = 14 AND
((`Advertisement`.`expiry_date` >= '2014-11-18') OR (`Advertisement`.`expiry_date`
IS NULL)) GROUP BY `Advertisement`.`id` ORDER BY `Advertisement`.`id` desc
LIMIT 10
I Want Like this query..
SELECT `Advertisement`.*, `Gallery`.`image` FROM `moenatmi_moen`.`advertisements`
AS `Advertisement` LEFT JOIN `moenatmi_moen`.`galleries` AS `Gallery` ON
(`Gallery`.`advertise_id` = `Advertisement`.`id` AND `Gallery`.`main_ad_image` = 1)
WHERE `Advertisement`.`status` = 1 AND `Advertisement`.`category_id` IN (select id from
categories where id=14 or parent_id=14) AND ((`Advertisement`.`expiry_date` >=
'2014-11-18') OR (`Advertisement`.`expiry_date` IS NULL)) GROUP BY
`Advertisement`.`id` ORDER BY `Advertisement`.`id` desc LIMIT 10
Original Cakephp Code..
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=>$cat_id,
'OR'=>array(
'Advertisement.expiry_date >='=>date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);
Help me..
Thanks You..

this should be a painless switch. This first query calls the category ids that you're wanting within your main query.
$cat_id is the same variable you're using in the original query.
$ids = $this->Category->find('all', array(
'conditions' => array(
'id' => $cat_id,
'parent_id' => $cat_id
)
)
);
The important thing to note here, this query will output your typical nested array..
array(
array(),
array(),
array()
);
The classicExtract function will sift through the mess for you and give you a single array with a list of 'id' which is exactly what you want for your query. EX:
array(14, 15, 16, 18, 19);
Finally, your main query.
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=> Set::classicExtract($ids, '{n}.Category.id'),
'OR'=>array(
'Advertisement.expiry_date >=' => date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);
Conclusion
All together your new conditions will look just like this:
$ids = $this->Category->find('all', array(
'conditions' => array(
'id' => $cat_id,
'parent_id' => $cat_id
)
)
);
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=> Set::classicExtract($ids, '{n}.Category.id'),
'OR'=>array(
'Advertisement.expiry_date >=' => date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);

Related

how to remove single quotes inside BETWEEN condition cakephp

I m trying to separated single quote from the values inside BETWEEN condition in cakephp 2 but it always gets values with single quotes like BETWEEN '2' and '34' .
here is my code:
$ref_no1 = $this->request->data['Lead']['ref_no1'];
$ref_no2 = $this->request->data['Lead']['ref_no2'];
$customerHo = $this-> Customer -> find('all',array(
'order' => array('Customer.customer_name' => 'asc'),
'joins'=>array(
array('table'=>'leads','alias'=>'Lead','type'=>'LEFT','foreignKey'=>false,'conditions'=>array('Customer.customer_id = Lead.customer_id')),
),
'fields'=>'Customer.*,Lead.*',
'conditions' => array(
'Customer.status' => 'active','Customer.customer_id Like'=>'S%',
'Customer.company_id'=>$company_id,
'AND' => array(
array('Lead.ref_no BETWEEN ? and ?' => array($ref_no1,$ref_no2) ),
),
)));
I am getting output like :
SELECT `Customer`.*, `Lead`.*
FROM `customers` AS `Customer`
LEFT JOIN `timezip_db_demo`.`leads` AS `Lead` ON (`Customer`.`customer_id` = `Lead`.`customer_id`)
WHERE `Customer`.`customer_id` Like 'S%' AND
`Lead`.`ref_no` BETWEEN '2' and '34'
ORDER BY `Customer`.`customer_name` asc
Expected output :
SELECT `Customer`.*, `Lead`.*
FROM `customers` AS `Customer`
LEFT JOIN `timezip_db_demo`.`leads` AS `Lead` ON (`Customer`.`customer_id` = `Lead`.`customer_id`)
WHERE `Customer`.`customer_id` Like 'S%' AND
`Lead`.`ref_no` BETWEEN 2 and 34
ORDER BY `Customer`.`customer_name` asc
can't you just do it like this? I didn't test this code yet.
$ref_no1 = $this->request->data['Lead']['ref_no1'];
$ref_no2 = $this->request->data['Lead']['ref_no2'];
$customerHo = $this-> Customer -> find('all',array(
'order' => array('Customer.customer_name' => 'asc'),
'joins'=>array(
array('table'=>'leads','alias'=>'Lead','type'=>'LEFT','foreignKey'=>false,'conditions'=>array('Customer.customer_id = Lead.customer_id')),
),
'fields'=>'Customer.*,Lead.*',
'conditions' => array(
'Customer.status' => 'active','Customer.customer_id Like'=>'S%',
'Customer.company_id'=>$company_id,
'AND' => array(
array('Lead.ref_no BETWEEN' . $ref_no1 . 'and' . $ref_no2 ),
),
)));
you can convert that string into integer, i hope it will work
array((int)$ref_no1,(int)$ref_no2)

Joins not used for complex HABTM search CakePhp 2

I have Contents, which can have Tags belonging to different TagGroups. I have a quite complex search condition which is as follows:
A Content matches if it is tagged with at least one tag from the search as long as it belongs to the same tag group.
Example:
TagGroup 1 are colours, TagGroup2 are shapes.
So if a Content is tagged with "blue", "turquoise" and "rectangular" it will be found, when I search for "blue" and "rectangular"
However this example is only to show that the logic behind this is quite complex.
Content -> ContentsTag <- Tag -> TagGroup
I want to develop a search with paging of the results I had it working, but between refactoring and framework updates it is broken.
At some point I loose the information for the joins and so my SQL is crashing because it is missing tables.
array(
'limit' => (int) 10,
'order' => array(
'Content.objnbr' => 'asc'
),
'joins' => array(
(int) 0 => array(
'table' => 'sang_contents_tags',
'alias' => 'CT1', //join for the first TagGroup
'type' => 'INNER',
'conditions' => array(
(int) 0 => 'CT1.content_id = Content.Id'
)
),
(int) 1 => array(
'table' => 'sang_contents_tags',
'alias' => 'CT2', //join for the second TagGroup
'type' => 'INNER',
'conditions' => array(
(int) 0 => 'CT2.content_id = Content.Id'
)
)
),
'conditions' => array(
'AND' => array(
(int) 0 => array(
'OR' => array(
(int) 0 => array(
'CT1.tag_id' => '189' // chosen Tag 1 from the first TagGroup
)
)
),
(int) 1 => array(
'OR' => array(
(int) 0 => array(
'CT2.tag_id' => '7' // chosen Tag 2 from the second TagGroup
)
)
)
)
),
'contain' => array(
(int) 0 => 'Description',
'ContentsTag' => array(
'Tag' => array(
(int) 0 => 'Taggroup'
)
)
)
)
results in the following SQL:
SELECT `Content`.`id`, `Content`.`objnbr`, `Content`.`name`, `Content`.`imagecounter`, `Content`.`videolength`, `Content`.`money_maker`, `Content`.`comment`
FROM `my_db`.`contents` AS `Content`
WHERE ((`CT1`.`tag_id` = '189') AND (`CT2`.`tag_id` = '7'))
ORDER BY `Content`.`id` DESC
LIMIT 20
So clearly the Tags CT1 and CT2 are not joined and my sql is crashing.
Could it be that the contain is blocking the joins? If I unset the contain I still get the same result / error.
Any ideas?
Edit: To clarify, what I want to achieve:
The result should be a SQL statement like this:
SELECT `Content`.`id`, `Content`.`objnbr`, `Content`.`name`, `Content`.`imagecounter`, `Content`.`videolength`, `Content`.`money_maker`, `Content`.`comment`
FROM
`my_db`.`contents` AS `Content`
INNER JOIN
contents_tags AS CT1 ON CT1.content_id = Content.Id
INNER JOIN
contents_tags AS CT2 ON CT2.content_id = Content.Id
WHERE
((`CT1`.`tag_id` = '189')
AND (`CT2`.`tag_id` = '7'))
ORDER BY `Content`.`id` DESC
LIMIT 10
It looks like the trouble is caused by the pagination. If I do a "simple" find I get Contents based on the Tags:
$result = $this->Content->find('all', $this->paginate['Content']);
generated query by find:
SELECT
`Content`.`id`,
`Content`.`objnbr`,
`Content`.`name`,
`Content`.`imagecounter`,
`Content`.`videolength`,
`Content`.`money_maker`,
`Content`.`comment`
FROM
`my_db`.`contents` AS `Content`
INNER JOIN
`my_db`.`contents_tags` AS `CT0` ON (`CT0`.`content_id` = `Content`.`Id`)
INNER JOIN
`my_db`.`contents_tags` AS `CT2` ON (`CT2`.`content_id` = `Content`.`Id`)
WHERE
((`CT0`.`tag_id` = '56')
AND (`CT2`.`tag_id` = '7'))
ORDER BY `Content`.`objnbr` ASC
I did a research in the bowels of the pagination class and my conclusion is, that it simply is not able to work with the current Paginator, because I cannot pass on my special joins I need for this complex query.
A custom find type also will not help, because my query is too dynamic for that.
Should anybody prove me wrong I will be a happy coder.

Paginate ignores conditions

when I try to run this code, it will not change my query, the condition is just not taken:
$this->paginate = array(
'conditions' => array(
'campaign_id' => $this->request->data['Campaign']['campaign_id']
)
);
$this->set('products', $this->Paginator->paginate());
the query looks like this
SELECT
`Product`.`id`, `Product`.`campaign_id`, `Campaign`.`id`, `Campaign`.`title`, `Campaign`.`text`
FROM
`db`.`products` AS `Product`
LEFT JOIN
`db`.`campaigns` AS `Campaign` ON (`Product`.`campaign_id` = `Campaign`.`id`)
WHERE
1 = 1
LIMIT
20
Is there anything wrong in my syntax?
(CakePHP 2.5.1)
What #ndm means is replace your existing code with this:
$this->Paginator->settings['conditions'] = array(
'Product.campaign_id' => $this->request->data['Campaign']['campaign_id']
)
$this->set('products', $this->Paginator->paginate());

CakePHP distinct picks extra column

i'm working on a project in CakePHP but stuck at a strange problem. I'm writing a query:
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=>$subcategory_id)
));
It is picking Product.id along with Product.brand which I do not want.
The query it generates is:
SELECT DISTINCT `Product`.`brand`, `Product`.`id` FROM `ecom`.`products` AS `Product` LEFT JOIN `ecom`.`subcategories` AS `SubCategory` ON (`Product`.`subcategory_id` = `SubCategory`.`id`) LEFT JOIN `ecom`.`categories` AS `Category` ON (`Product`.`category_id` = `Category`.`id`) WHERE `Product`.`subcategory_id` = 13 ORDER BY `Product`.`brand` ASC
How can I skip Product.id from select?
Thanks
Adding group solved my issue:
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=>$subcategory_id),
'group' => 'brand'
));
I think it's because cake needs the id to create the joins
try
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=> $subcategory_id),
'recursive' => -1
));

CakePHP runs unnecessary queries when retrieving related models

The Event model has following relations:
var $belongsTo = array(
'Project' => array(
'className' => 'Project',
'foreignKey' => 'project_id',
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
here is how I list the events depending on the user input:
$conditions = array('user_id'=>$id, 'date >=' => $from, 'date <=' => $to);
$events = $this->find('all', array(
'conditions'=>$conditions, 'order' => array('Event.date' => 'asc')));
And here are the 3 queries that are being run:
1 SELECT `User`.`id`, `User`.`name`, `User`.`surname` FROM `scheduling`.`users` AS `User` WHERE `company_id` = 1
2 SELECT `Project`.`id`, `Project`.`name` FROM `scheduling`.`projects` AS `Project` LEFT JOIN `scheduling`.`customers` AS `Customer` ON (`Project`.`customer_id` = `Customer`.`id`) WHERE `Project`.`company_id` = 1
3 SELECT `Event`.`id`, `Event`.`project_id`, `Event`.`user_id`, `Event`.`date`, `Event`.`hours`, `Event`.`minutes`, `Event`.`xhours`, `Event`.`xminutes`, `Event`.`xdetails`, `Event`.`assignment`, `Event`.`start_time`, `Event`.`material`, `Event`.`meter_drive`, `Event`.`time_drive`, `Event`.`start_location`, `Event`.`finish_time`, `Project`.`id`, `Project`.`name`, `Project`.`customer_id`, `Project`.`project_nr`, `Project`.`address`, `Project`.`post_nr`, `Project`.`city`, `Project`.`company_id`, `Project`.`color`, `Project`.`start_date`, `Project`.`finish_date`, `User`.`id`, `User`.`employee_nr`, `User`.`name`, `User`.`surname`, `User`.`email`, `User`.`password`, `User`.`role`, `User`.`phone`, `User`.`address`, `User`.`post_nr`, `User`.`city`, `User`.`token_hash`, `User`.`company_id`, `User`.`car_id`, `User`.`image` FROM `scheduling`.`events` AS `Event` LEFT JOIN `scheduling`.`projects` AS `Project` ON (`Event`.`project_id` = `Project`.`id`) LEFT JOIN `scheduling`.`users` AS `User` ON (`Event`.`user_id` = `User`.`id`) WHERE `user_id` = 1 AND `project_id` = 5 AND `date` >= '2013-07-01' AND `date` <= '2013-12-06' ORDER BY `Event`.`date` asc
In fact, I only need the third query and not the first two. What causes them and how to get rid of them?
By default, CakePHP will try attach associations.
In all 3 models add:
var $actsAs = array('Containable');
This will allow you to "contain" your queries to specific models.
Now you can do you query thus:
$events = $this->find('all', array(
'conditions'=>$conditions,
'order' => array('Event.date' => 'asc'),
'contain' => true));
Say you did want Users (but not Projects) back you can do:
$events = $this->find('all', array(
'conditions'=>$conditions,
'order' => array('Event.date' => 'asc'),
'contain' => array('User')));
Other code is responsible
This code:
$conditions = array('user_id'=>$id, 'date >=' => $from, 'date <=' => $to);
$events = $this->find('all', array(
'conditions'=>$conditions,
'order' => array('Event.date' => 'asc')
));
Is responsible for this query:
SELECT
`Event`.`id`,
...
FROM
`scheduling`.`events` AS `Event`
LEFT JOIN
`scheduling`.`projects` AS `Project` ON (`Event`.`project_id` = `Project`.`id`)
LEFT JOIN
`scheduling`.`users` AS `User` ON (`Event`.`user_id` = `User`.`id`)
WHERE
`user_id` = 1 AND
`project_id` = 5 AND
`date` >= '2013-07-01' AND
`date` <= '2013-12-06'
ORDER BY
`Event`.`date` asc
However there are only user_id and date conditions in the code in the question.
This condition:
`project_id` = 5
Is being added by un-shown code - probably a behavior. Check your code for where the project_id condition is defined, there is the answer.
query #1 is unrelated
The first query does not look to be related to the code in the question at all - there is nothing in the question that requires finding a user's data. To find where that's coming from - you can use a simple technique. Open up the user model and put this in it:
class User extends AppModel {
public function beforeFind() {
debug(Debugger::trace());
debug(func_get_args());
die;
}
}
This will give a stack trace of how the query is being triggered - edit the application code appropriately once you know where it comes from.
query #2 is required
Assuming the query you want is actually correct (find all events for a single project) - there needs to be a way to restrict on project id. If that's not specified explicitly, the second query is looking for a project id by client id - i.e. the query you want depends upon that data.
This will help you.
$events = $this->find('all', array(
'conditions'=>$conditions,
'order' => array('Event.date' => 'asc'),
'recursive' => -1
));
recursive based on the max containment depth
$conditions = array('user_id'=>$id, 'date >=' => $from, 'date <=' => $to);
$events = $this->find('all', array('recursive'=>0,
'conditions'=>$conditions, 'order' => array('Event.date' => 'asc')));
the change in here is the recursive
recursive=>-1 mean will fetch only event
recursive=>0 mean will fetch event + to whom it belongs to, in this case project and user

Resources