Cakephp complex query - cakephp

I have the sql code and i want to do in cake php but i dont know how and i don't want to do it like that $obj->query($sql);
This is my query:
"SELECT dbfiles.amount, MONTHNAME(cases.enquiry_date) as Month FROM cases
INNER JOIN services ON cases.id = services.case_id
INNER JOIN dbfiles ON services.id = dbfiles.service_id
WHERE cases.status = 2 AND YEAR(cases.enquiry_date) = '2012' AND dbfiles.type = 'INV'
AND cases.currency = 'EUR' GROUP BY dbfiles.invoice_num ORDER BY Month DESC; "

Assuming $obj is of class Case
$obj->find('all', array(
'fields' => array('dbfiles.amount', 'MONTHNAME(cases.enquiry_date) as MONTH',
'joins' => array(
array(
'table' => 'services',
'type' => 'INNER',
'conditions' => array('cases.id = services.case_id'),
'foreignKey' => false
),
array(
'table' => 'dbfiles',
'type' => 'INNER',
'conditions' => array('services.id = dbfiles.service_id'),
'foreignKey' => false
)
),
'conditions' => array('cases.status' => 2, ... the rest of your WHERE clauses)
)

Related

cakephp code to pginate data using cakephp 1.3

i am using cakephp 1.3 version.
i try to display data with pagination.but my code getting wrong query.
plz help to correct them.
below is my code...
$this->paginate = array(
'fields' => array('u_data.lane_id AS LaneId'),
'joins' => array(array(
'table' => 'countries',
'alias' => 'origin_country',
'type' => 'INNER',
'conditions' => array('origin_country.id'=>'CustomerRoute.origin_country')
),
array(
'table' => 'countries',
'alias' => 'dest_country',
'type' => 'INNER',
'conditions' => array('dest_country.id'=>'CustomerRoute.dest_country')
),
array(
'table' => 'states',
'alias' => 'origin_state',
'type' => 'INNER',
'conditions' => array('origin_state.id'=>'CustomerRoute.origin_state')
),
array(
'table' => 'states',
'alias' => 'dest_state',
'type' => 'INNER',
'conditions' => array('dest_state.id'=>'CustomerRoute.dest_state')
),
array(
'table' => 'postalcodes',
'alias' => 'origin_city',
'type' => 'INNER',
'conditions' => array('origin_city.id'=>'CustomerRoute.origin_city')
),
array(
'table' => 'postalcodes',
'alias' => 'dest_city',
'type' => 'INNER',
'conditions' => array('dest_city.id'=>'CustomerRoute.dest_city')
),
array(
'table' => 'portfolios',
'alias' => 'p',
'type' => 'INNER',
'conditions' => array('p.id'=>'CustomerRoute.portfolio_id')
),
array(
'table' => 'supplier_uquotes_data',
'alias' => 'u_data',
'type' => 'LEFT',
'conditions' => array('CustomerRoute.id'=>'u_data.lane_id')
)),
'conditions' => array('CustomerRoute.portfolio_id' =>'"'.$_SESSION["portfolioid"].'"', 'u_data.supplier_id IN' => '"'.implode(',',$_SESSION['supplierid']).'"'),
'group' => array('CustomerRoute.id'),
'limit' => 10);
$content = $this->paginate('CustomerRoute');
print_r($content);
exit;
the above code getting below query.....
SELECT `u_data`.`lane_id` AS `LaneId` FROM `customers` AS `Customer` INNER JOIN countries AS `origin_country` ON (`origin_country`.`id` = 'CustomerRoute.origin_country') INNER JOIN countries AS `dest_country` ON (`dest_country`.`id` = 'CustomerRoute.dest_country') INNER JOIN states AS `origin_state` ON (`origin_state`.`id` = 'CustomerRoute.origin_state') INNER JOIN states AS `dest_state` ON (`dest_state`.`id` = 'CustomerRoute.dest_state') INNER JOIN postalcodes AS `origin_city` ON (`origin_city`.`id` = 'CustomerRoute.origin_city') INNER JOIN postalcodes AS `dest_city` ON (`dest_city`.`id` = 'CustomerRoute.dest_city') INNER JOIN portfolios AS `p` ON (`p`.`id` = 'CustomerRoute.portfolio_id') LEFT JOIN supplier_uquotes_data AS `u_data` ON (`CustomerRoute`.`id` = 'u_data.lane_id') LEFT JOIN `jobtitles` AS `Jobtitle` ON (`Customer`.`job_title` = `Jobtitle`.`id`) LEFT JOIN `countries` AS `Country` ON (`Customer`.`country` = `Country`.`id`) LEFT JOIN `states` AS `State` ON (`Customer`.`state` = `State`.`id`) LEFT JOIN `market_areas` AS `MarketArea` ON (`Customer`.`market_area` = `MarketArea`.`id`) WHERE `CustomerRoute`.`portfolio_id` = '\"69\"' AND `u_data`.`supplier_id` IN '\"37\"' GROUP BY `CustomerRoute`.`id` LIMIT 10
but i need the result like below mentioned query....the below mentioned query is my correct query.......
plz suggest whats the problem in my code..
SELECT u_data.lane_id AS LaneId,
origin_city.pcode AS origin_pcode,
dest_city.pcode AS dest_pcode
FROM customer_routes AS CustomerRoute
INNER JOIN countries AS origin_country ON ( origin_country.id = CustomerRoute.origin_country )
INNER JOIN countries AS dest_country ON ( dest_country.id = CustomerRoute.dest_country )
INNER JOIN states AS origin_state ON ( origin_state.id = CustomerRoute.origin_state )
INNER JOIN states AS dest_state ON ( dest_state.id = CustomerRoute.dest_state )
INNER JOIN postalcodes AS origin_city ON ( origin_city.id = CustomerRoute.origin_city )
INNER JOIN postalcodes AS dest_city ON ( dest_city.id = CustomerRoute.dest_city )
INNER JOIN portfolios AS p ON ( p.id = CustomerRoute.portfolio_id )
LEFT JOIN supplier_uquotes_data AS u_data ON ( CustomerRoute.id = u_data.lane_id AND u_data.mode = '".$mode."')
WHERE CustomerRoute.portfolio_id = '".$_SESSION["portfolioid"]."' AND u_data.supplier_id
IN (".implode(',',$_SESSION['supplierid']).") GROUP BY CustomerRoute.id
You should define remaining fields also and pass the Model name like this : $this->Prg->commonProcess('CustomerRoute');
This is your code
$this->Prg->commonProcess('CustomerRoute');
$this->paginate = array(
'fields' => array('u_data.lane_id AS LaneId','origin_city.pcode AS origin_pcode','dest_city.pcode AS dest_pcode'),
'joins' => array(array(
'table' => 'countries',
'alias' => 'origin_country',
'type' => 'INNER',
'conditions' => array('origin_country.id'=>'CustomerRoute.origin_country')
),
array(
'table' => 'countries',
'alias' => 'dest_country',
'type' => 'INNER',
'conditions' => array('dest_country.id'=>'CustomerRoute.dest_country')
),
array(
'table' => 'states',
'alias' => 'origin_state',
'type' => 'INNER',
'conditions' => array('origin_state.id'=>'CustomerRoute.origin_state')
),
array(
'table' => 'states',
'alias' => 'dest_state',
'type' => 'INNER',
'conditions' => array('dest_state.id'=>'CustomerRoute.dest_state')
),
array(
'table' => 'postalcodes',
'alias' => 'origin_city',
'type' => 'INNER',
'conditions' => array('origin_city.id'=>'CustomerRoute.origin_city')
),
array(
'table' => 'postalcodes',
'alias' => 'dest_city',
'type' => 'INNER',
'conditions' => array('dest_city.id'=>'CustomerRoute.dest_city')
),
array(
'table' => 'portfolios',
'alias' => 'p',
'type' => 'INNER',
'conditions' => array('p.id'=>'CustomerRoute.portfolio_id')
),
array(
'table' => 'supplier_uquotes_data',
'alias' => 'u_data',
'type' => 'LEFT',
'conditions' => array('CustomerRoute.id'=>'u_data.lane_id')
)),
'conditions' => array('CustomerRoute.portfolio_id' =>'"'.$_SESSION["portfolioid"].'"', 'u_data.supplier_id IN' => '"'.implode(',',$_SESSION['supplierid']).'"'),
'group' => array('CustomerRoute.id'),
'limit' => 10);
$content = $this->paginate('CustomerRoute');

cakephp paginate with associated model

User has many User_Questionaries. I want paginate users that have particular questionnaire. I used following pagination for it.
$paginate = array(
'conditions' => array(
'User.role' => IWOA,
'UserQuestionary.questionary_id' => $id
),
'recursive' => 1,
'limit' => 10,
'order' => array(
'name' => 'asc'
),
'contain' => array('UserQuestionary')
);
But it is not create join query. It is showing Unknown column UserQuestionary.questionary_id' in 'where clause'
What is the issue? How can i do it?
Finally I used join query for do this.
$paginate = array(
'conditions' => array(
'Iwoa.role' => IWOA,
),
'joins' => array(
array(
'alias' => 'UserQuestionary',
'table' => 'user_questionaries',
'type' => 'LEFT',
'conditions' => 'UserQuestionary.user_id = Iwoa.id AND UserQuestionary.questionary_id = ' . $id
)
),
'limit' => 10,
'order' => array(
'name' => 'asc'
),
);

CakePHP find all condition being ignored

I'm using CakePHP 1.3 and am having some trouble converting a SQL query to CakePHP. The concept behind the query is to retrieve all products associated with a specified account and belonging to a certain product category or the specified category's immediate child.
There are three tables involved here, products, product_categories and category_types. product_categories is a link table that joins products to category_types. The category_types table is a tree structure that can join to itself.
The SQL for the query should end up looking something like this if the category's id was 1 and the account's id was 1:
SELECT Product.id, Product.name, Product.account_id
FROM products AS Product
INNER JOIN product_categories AS pc ON (Product.id = pc.product_id)
INNER JOIN category_types AS ct ON (ct.id = pc.category_type_id)
WHERE (
((Product.account_id IS NULL) OR (Product.account_id = '1'))
AND ((ct.id = '1') OR (ct.parent_id = '1'))
)
Here is the code I'm using to try and do this, which is located in a function in my model:
$this->find('all', array(
'joins' => array(
array(
'table' => 'product_categories',
'alias' => 'pc',
'type' => 'INNER',
'conditions' => array(
'Product.id = pc.product_id'
)
),
// get category type
array(
'table' => 'category_types',
'alias' => 'ct',
'type' => 'INNER',
'conditions' => array(
'pc.category_type_id = ct.id'
)
)
)
, 'conditions'=> array(
'OR' => array(
'Product.account_id IS NULL'
, 'Product.account_id' => $account_id
)
, 'OR' => array(
'ct.id' => $categoryTypeId
, 'ct.parent_id' => $categoryTypeId
)
)
));
The problem is that the query is ignoring the account_id OR conditions resulting in SQL like this:
SELECT Product.id, Product.name, Product.account_id
FROM products AS Product
INNER JOIN product_categories AS pc ON (Product.id = pc.product_id)
INNER JOIN category_types AS ct ON (ct.id = pc.category_type_id)
WHERE ((ct.id = '1') OR (ct.parent_id = '1'))
How can I alter my php code to get the desired results?
Thanks to user2076809 for pointing me in the right direction. The solution is to wrap the two OR conditions each in their own array.
$this->find('all', array(
'joins' => array(
array(
'table' => 'product_categories',
'alias' => 'pc',
'type' => 'INNER',
'conditions' => array(
'Product.id = pc.product_id'
)
),
// get category type
array(
'table' => 'category_types',
'alias' => 'ct',
'type' => 'INNER',
'conditions' => array(
'pc.category_type_id = ct.id'
)
)
),
'conditions'=> array(
array(
'OR' => array(
'Product.account_id IS NULL'
, 'Product.account_id' => $account_id
)
),
array(
'OR' => array(
'ct.id' => $categoryTypeId
, 'ct.parent_id' => $categoryTypeId
)
)
)
));
I think, you should wrap the both of the array in only one OR condition like:-
$this->find('all', array(
'joins' => array(
array(
'table' => 'product_categories',
'alias' => 'pc',
'type' => 'INNER',
'conditions' => array(
'Product.id = pc.product_id'
)
),
// get category type
array(
'table' => 'category_types',
'alias' => 'ct',
'type' => 'INNER',
'conditions' => array(
'pc.category_type_id = ct.id'
)
)
),
'conditions'=> array(
'OR' => array(
array(
'Product.account_id IS NULL'
, 'Product.account_id' => $account_id
),
array(
'ct.id' => $categoryTypeId
, 'ct.parent_id' => $categoryTypeId
)
)
)
));

How to get all Users with a "order by" latest Posts in a HABTM relation with CakePHP

I have a HABTM relation between Post and User model.
Now I want to receive all Users ordered by Post.published.
Something like this:
...
var $paginate = array(
'limit' => 8,
'recursive' => 1,
'fields' => array('id', 'username', 'image')
);
function index() {
$this->paginate['conditions'] = array('User.state'=>true);
$this->paginate['order'] = 'Post.published DESC';
$this->set('authors', $this->paginate());
}
...
How can I do this? Is it possible?
In MySQL:
SELECT users.id, users.username, users.image, posts.published FROM users INNER JOIN posts_users ON users.id = posts_users.user_id
INNER JOIN posts ON posts.id = posts_users.post_id
ORDER BY posts.published DESC;
The solution:
function index() {
$this->paginate['joins'] = array(
array('table' => 'posts_users', 'alias' => 'PostsUser', 'type' => 'inner', 'conditions'=>array('User.id = PostsUser.user_id')),
array('table' => 'posts', 'alias' => 'Post', 'type' => 'inner', 'conditions'=>array('Post.id = PostsUser.post_id'))
);
$this->paginate['fields'] = array('id', 'username', 'image');
$this->paginate['conditions'] = array('User.state'=>true);
$this->paginate['order'] = 'Post.published DESC';
$this->paginate['group'] = 'User.id';
$this->set('authors', $this->paginate());
}
You can specify The joins in your paginate options array, just like in the find options:
class PostsController extends AppController {
public function by_tag ( $tag ) {
/**
* This will fetch Posts tagged $tag (say, 'PHP')
*/
$this->paginate['Post'] = array(
'limit' => 10,
'contain' => '',
'conditions' => array(
'Post.published' => 1
),
'fields' => array('Post.*', 'Tag.*'),
'joins' => array(
array(
'table' => 'posts_tags',
'type' => 'INNER',
'alias' => 'PostTag',
'conditions' => array(
'Post.id = PostTag.post_id'
)
),
array(
'table' => 'tags',
'alias' => 'Tag',
'type' => 'INNER',
'conditions' => array(
"PostTag.tag_id = Tag.id AND Tag.name = '$tag'"
)
)
)
);
$data = $this->paginate('Post');
$this->set(compact('data'));
}
}
http://planetcakephp.org/aggregator/items/3544-using-mysql-inner-join-in-cakephp-pagination

CakePHP 3 level join find method

I have these tables in my database: 'products' belongs to a 'company', and 'company' has many 'company_addresses'. And I am building a search action in my controller which will return the products based on user's inputted company address. How can I get something like the followin?
SELECT *
FROM products
LEFT JOIN companies ON products.company_id = companies.id
LEFT JOIN company_addresses ON companies.id = company_addresses.company_id
WHERE company_addresses.address1 LIKE '%'.$this->data['Product']['keyword'].'%'
OR company_addresses.address2 LIKE '%'.$this->data['Product']['keyword'].'%'
This doesn't seem to work:
$results = $this->Product->find('all', array(
'conditions' => array(
'OR' => array(
array('CompanyAddress.address1 LIKE' => '%'.$this->data['Product']['keyword'].'%'),
array('CompanyAddress.address2 LIKE' => '%'.$this->data['Product']['keyword'].'%')
)
),
'order' => array(
'Product.id' => 'ASC'
),
'contain' => array(
'Company' => array(
'CompanyAddress' => array(
'State',
'City'
)
)
)
));
Nor this:
$results = $this->Product->find('all', array(
'order' => array(
'Product.id' => 'ASC'
),
'contain' => array(
'Company' => array(
'CompanyAddress' => array(
'conditions' => array(
'OR' => array(
array('CompanyAddress.address1 LIKE' => '%'.$this->data['Product']['keyword'].'%'),
array('CompanyAddress.address2 LIKE' => '%'.$this->data['Product']['keyword'].'%')
)
),
'State',
'City'
)
)
)
));
I think the best for you is to use the join of CakePHP.
Something like this:
$this->Product->find('all', array(
'joins' => array(
array(
'table' => 'companies',
'alias' => 'Company',
'type' => 'left',
'conditions' => array(
'Company.id = Product.company_id'
),
),
array(
'table' => 'companies_addresses',
'alias' => 'CompaniesAddress',
'type' => 'left',
'conditions' => array(
'CompaniesAdress.company_id = Company.id',
'OR' => array(
'CompanyAdress.address1 LIKE' => '%' . $this->data['Product']['keyword'] . '%',
'CompanyAdress.address2 LIKE' => '%' . $this->data['Product']['keyword'] . '%',
),
),
),
),
));

Resources