Creating complex conditions with CakePHPs paginate and containable behavior - php

I'm using the containable behavior to look at several tables.
$this->paginate = array(
'contain' => array(
'Co' => array('fields' => array('ref')),
'CoItemType' => array('fields' => array('name')),
'Casing' => array(
'fields' => array('id','barcode','CONCAT(plant_dot,size_dot,product_line_dot,production_week) as dot'),
'Customer' => array('fields' => array('company_name')),
)
)
);
This works as expected. However I am integrating this with jQuery datatables and the way dataTables passes over conditions it does not specifiy a field. So I'd like to do conditions outside of the contains like so...
'conditions' = array(
'OR' => array(
array("Table.field_name LIKE " => '%'.$parameter.'%'),
array("Table.field_name LIKE " => '%'.$parameter.'%'),
array("Table.field_name LIKE " => '%'.$parameter.'%')
)
)
Of course this is not possible since the containable behavior wants you to include the conditions under the tables key in the contain array. This is frustrating, does anyone have a solution or workaround around to this problem?
I am using CakePHP 2.x

Use Linkable Behavior as noted in comments.

Related

Group By within contain cakephp

Hellow , I want to use group by within contain in cakephp. In the following case i want to take only distinct organization within organizationUser array..
$options = array(
'conditions' => array('User.' .$this->User->primaryKey => $userId),
'contain' => array(
'OrganizationUser'=>array(
'conditions'=>['status'=>3],
'group'=> array( 'OrganizationUser.organization_id')),
'OrganizationUser.Organization',
'OrganizationUser.Organization.Noticeboard',
'OrganizationUser.Organization.Newsboard',
'OrganizationUser.Organization.Noticeboard.Branch',
),
'page'=>$page,
'limit'=>$limit
);
$org = $this->User->find('all', $options);
But this is throwing error like 'Column not found', and 'conditions' is working fine within OrganizationUser but 'group' not working.I am using cakephp version 2.Thanks in advance.
I don't think cakephp 2+ offer something like you are doing to make field distinct within contain. So better to try following..
Replace :
'group'=> array( 'OrganizationUser.organization_id')
By
'fields'=> array( 'DISTINCT OrganizationUser.organization_id')
that might work for you.
In my case, I'm using cake version 4+.
In my table the relation I've made
$this->belongsTo('CreatedOperator')
->setClassName(USERS_PLUGIN . '.Users')
->setForeignKey('created_by')
->setJoinType('INNER')
;
and I'm calling the relation like
$query
->disableHydration()
->select([
'CreatedOperator.id',
'CreatedOperator.first_name',
'CreatedOperator.last_name',
'full_name' => $query->func()->concat(['CreatedOperator.first_name' => 'identifier',' ','CreatedOperator.last_name' => 'identifier']),
'total' => $query->func()->count('CreatedOperator.id')])
->contain(['CreatedOperator'])
->group(['CreatedOperator.id'])
;
return $query->toList();

CakePHP ignores condition

I have the following problem with CakePHP:
Two tables are joined (filters and accounts). Then I am building conditions and only the second condition Account.active =>1 gets executed. If I print the result, there are still showing filters that are having another mode_id than 3.
$joins= array(
array('table' => 'filters',
'alias' => 'Filter',
'type' => 'right',
'conditions' => array(
'Filter.account_id = Account.id',
)
),
);
Then I execute the request including joins and conditions
$activeAccounts = $this->Account->find('all',array(
'conditions'=>array('AND'=>array('Filter.mode_id'=>3,'Account.active'=>1)),
'joins'=>$joins));
The models were checked and no problems identified. Filter belongs to Account. Account has many Filter.
Below the query that is generated. The results are still showing filters with Filter.mode_id other than 3
Here is the query that is generated. The results are still containing rows with Filter.mode_id other than 3 despite the fact that one condition is 'Filter.mode_id'=>3
SELECT `Account`.`id`, `Account`.`user_id`, `Account`.`name`,
`Account`.`api_key`, `Account`.`account_number`, `Account`.`remaining_balance`,
`Account`.`investment_size`, `Account`.`active`
FROM `baseline_db`.`accounts` AS `Account`
right JOIN `baseline_db`.`filters` AS `Filter`
ON (`Filter`.`account_id` = `Account`.`id`)
WHERE ((`Filter`.`mode_id` = 3) AND
(`Account`.`active` = '1'))
Like say Oldskool, use the Model associations
and for your condition, The "AND" is not necessary,
you cant put :
$activeAccounts = $this->Account->find('all',array(
'conditions' => array(
'Filter.mode_id'=>3,
'Account.active'=>1
)
));
the request you want to make with the type of relation you have, seem to me weird.
If i understand, perhaps with something like that :
$this->loadModel('Filter');
$filters =$this->Filter->find("list", array(
'conditions' => array('Filter.mode_id' => 3),
'fields' => array('Filter.account_id')
));
$activeAccounts = $this->Account->find('all',array(
'conditions' => array(
'Account.account_id'=>$filters,
'Account.active'=>1
)
));

Containable not working correctly with deep association

I have a Produto(Product) model that belongsTo Titulo(Title).
Pedido(Order) hasMany Itens and the Itens belongsTo Produto(Product).
however, after I use find(all) using the model Pedido containing Itens with Produto, the next find of Produto, the contain nor the recursive function works, here is an example:
$proModel = ClassRegistry::Init('Produto');
pr($proModel->find('first', array('conditions' => array('pro_cod' => 650), 'contain' => 'Titulo')));
$cart = $pedModel->find('first', array(
'conditions' => array('ped_cod' => $cart['Pedido']['ped_cod']),
'contain' => array(
'Itens' => array(
'Produto' => array(
'Estadia' => array('Atributo', 'Numero'), 'Produtoplataformas'
),
'Troca', 'Locado', 'Tipo',
'Locacao' => array('Plano', 'Itens')
),
'Usuario'
),
'recursive' => -1
));
pr($proModel->find('first', array('conditions' => array('pro_cod' => 650), 'contain' => 'Titulo')));
exit;
The first pr of $proModel->find works ok and prints the 'Titulo' that is associated, however, after the $pedModel->find, the very same $proModel->find doesn't print the 'Titulo' association.
I have no afterFind method.
EDIT:
I pr($proModel->belongsTo) and it changes after $pedModel->find. All associations vanish except the ones used in the contain section of $pedModel->find.
If I use a new Produto instead of ClassRegistry::Init('Produto'), it worked fine, but I guess this is not a good thing, right?
This sucks.
It is a bug of CakePHP:
https://github.com/cakephp/cakephp/issues/5992
You can't have same aliases inside the contain block.
One of the staff said it was a limitation, for me, it is a bug, since it, at least, didn't throw an error.

Finding the Omega of a find() in cakephp

I have this on a HABTM statement:
$this->set('usergroups', $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')))));
This gets groups that are associated to the user id via a courses_users table.
This works perfectly find, except I also need to find all groups that a user doesn't belong to. How do I get the opposite of the statement above?
I used 'not' as a condition, and it still gave me the same result.
Thanks!
Something like this should work:
$user = $this->User->find('first', array(
'conditions' => array(
'User.id' => $this->Auth->user('id')
)
));
$otherGroups = $this->Group->find('all', array(
'conditions' => array(
'NOT' => array('id' => Hash::extract($user, '{n}.Group.id'))
)
));
Side Note: You should really be setting recursive to -1 in your AppModel and not relying on recursive to return additional data. Instead, use CakePHP's Containable Behavior.

Specifying record criteria on more than one model in one pagination call

I am stuck on pagination in CakePHP 1.3. I am trying to paginate feePayment records based on certain criteria.
feePayments belongs to Students which in turn belongs YearGroups.
I want to paginate 'unpaid' feePayments for each year group. The problem I am having is that the SQL query seems to only take into account the conditions I specified for the FeePayment model and ignores the YearGroup criteria so only overdue unpaid records are returned regardless of the year group specified.
Here is my code:
function unpaidClass($id) {
$this->paginate = array(
'FeePayment' => array ('recursive' => 1, 'conditions' => array('FeePayment.status' => 'Unpaid', 'FeePayment.due_date <= ' => date("Y-m-d"))),
'YearGroup' => array ('recursive' => 1, 'conditions' => array('YearGroup.school_year' => $id))
);
$this->set('feePayments', $this->paginate());
}
Hope this makes sense, appreciate any help.
Thanks,
Sid.
You should consider using the Containable behavior. This behavior allows you to group the necessary data you want without relaying on the "recursiveness" of your query. You can place conditions on your contained data similar to the way you would in your queries and is a more permanent way to structure data across your application instead of specifying conditions over and over again in each query.
Paginate should automatically pick up these associations when you Paginate your main model. Here's an example of what I mean here: http://cakephp.1045679.n5.nabble.com/Paginate-with-Containable-td1300971.html#a1300971
These should make your task easier.
After a lot of searching the net and reading CakePHP's documentation, here is the solution I came up with:
function unpaidClass($id) {
$this->FeePayment->unbindModel(array(
'belongsTo' => array('Student')
), $reset = 0);
$this->FeePayment->bindModel(array(
'belongsTo' => array(
'Student' => array(
'foreignKey' => false,
'conditions' => array('Student.id = FeePayment.student_id')
),
'YearGroup' => array(
'foreignKey' => false,
'conditions' => array('YearGroup.id = Student.year_group_id')
)
)
), $reset = 0);
$this->paginate = array(
'contain' => array('Student','YearGroup'),
'conditions' => array('YearGroup.school_year' => $id,
'FeePayment.status' => 'Unpaid',
'FeePayment.due_date <= ' => date("Y-m-d")));
$this->set('feePayments', $this->paginate());
}

Categories