Case Statement in CakePHP generates another array of the result - cakephp

I have a simple select query using Case Statement in CakePHP.
$this->M->find('all', array(
'fields'=>array(
'M.id',
'(CASE WHEN M.check> 0 THEN
TRUNCATE((M.col1 + M.col2),2)
ELSE
TRUNCATE(M.col2, 2)
END) AS TOTAL'
)));
I'm trying to have this result.
(int) 0 => array(
'M' => array(
'id' => '200',
'TOTAL' => '1073.00'
)
)
But Cake Outputs
(int) 0 => array(
'M' => array(
'id' => '200',
),
(int) 0 => array(
'TOTAL' => '1073.00'
)
)
Does cake renders the result like this for the Case Statement or I miss out something?

You should be using
http://book.cakephp.org/2.0/en/models/virtual-fields.html
as documented.
$this->virtualFields['total'] = ...;
Then it would work as expected.

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.

CakePHP - select from database with condition

I have this selector:
$this->Table->find('list',array('contain'=>false,'conditions'=>array('status'=>1,'unit_id'=>null,'country_id'=>$countryId,'eday'=>$eday),'fields'=>'id'));
And this works perfect. But now i need to have another one i cant find how to do this ;)
I need to select all records from Table but with condition:
'eday'>=$eday AND 'eday'<$eday+7
Its this posibble in easy way? Maybe this is stupid question but i dont have exp in PHP ;)
In cakephp the equivalent for and condition is
Example: column1 = 'value' AND column2 = 'value'
'AND' => array(
'column1' => 'value',
'column2' => 'value'
)
So your query builder would be like this
$this->Table->find('list',array(
'contain' => false,
'conditions' => array(
'status' => 1,
'unit_id' => null,
'country_id' => $country,
'AND' => array(
'eday >=' => $eday,
'eday <' => ($eday+7)
)
),
'fields'=>'id'
));
Just pass an AND array with in your current conditions array :
$this->Table->find('list',array('contain'=>false, 'conditions'=>array('status'=>1,'unit_id'=>null,'country_id'=>$countryId,'eday'=>$eday, AND => array( array('eday >=' => $eday) , array( 'eday <' => $eday+7) )), 'fields'=>'id' ));
Have you tried something like this :
$conditions['status'] = 1;
$conditions['unit_id'] = null;
$conditions['country_id'] = $countryId;
$conditions['eday >='] = $eday;
$conditions['eday <'] = $eday + 7;
$this->Table
->find('list') //either use this
->find('all') //or use this
->find() //or this
->where($conditions)
->select(['addFiledsToSelectHere'])
This looks more cleaner.

get data using not ids not working in cakephp

I want to select data for all rows where the below ids dont exist. I thought this would work but there is no error and the below ids still appear in the retrieved records. I am using cakephp 2.5 for this
$ids///
array(
(int) 0 => '14721',
(int) 1 => '14731',
(int) 2 => '14905',
(int) 3 => '15808',
(int) 4 => '15818',
$test=$this->Lessonbak->find('all', array(
'fields'=>array('id'),
'recursive' => -1 ) );
$ids=array();
foreach( $test as $item):
array_push($ids,$item['Lessonbak']['id']);
endforeach;
$lessonstudent2=$this->LessonsStudent2->find('all', array(
'conditions' => array( "NOT" => array( 'LessonsStudent2.lesson_id' => $ids )),
'recursive' => -1 ) );
Instead of selecting all of the Lessonbak ids, pushing them to an array, and using that in your LessonsStudent2 query, you should simply use a subquery:
$dbo = $this->getDataSource();
$subquery = $dbo->buildStatement(
array(
'table' => 'lessonbak',
'alias' => 'Lessonbak',
'recursive' => -1,
'fields' => array(
'Lessonbak.id'
)
),
$this
)
$this->LessonsStudent2->find('all', array(
'conditions' => array(
'NOT' => array(
'LessonsStudent2.lesson_id IN (' . $subquery . ')'
)
)
)

CakePHP find conditions with multiple 'OR'

I'm having a real headache getting this to work correctly. This is my desired outcome in raw MySQL:
WHERE `EmailTemplate`.`is_archived` = '0'
AND
((`EmailTemplate`.`project_id` IS NULL) OR (`EmailTemplate`.`project_id` = 101))
AND
((`EmailTemplate`.`user_id` IS NULL) OR (`EmailTemplate`.`user_id` = 44))
How does this translate into a CakePHP conditions array?
Solved this, eventually.
$templateConditions = array(
'EmailTemplate.is_archived' => 0,
'AND' => array(
'OR' => array(
array('EmailTemplate.project_id IS NULL'),
array('EmailTemplate.project_id' => $this->request->data['Project']['project_id'])
)
),
array(
'OR' => array(
array('EmailTemplate.user_id IS NULL'),
array('EmailTemplate.user_id' => $this->Auth->user('id'))
)
)
);

Resources