Search with concat fields in cakephp 3 - cakephp

I need to make a search query using $this->Paginate in CakePHP 3. Following is the code I am using
$searchCondition = array(
'OR' => array(
'Quotes.quotenum LIKE' => "%" . $this->request->data['Quote']['keyword'] . "%",
'Branches.name LIKE' => '%' . $this->request->data['Quote']['keyword'] . '%',
'Contacts.fname LIKE' => '%' . $this->request->data['Quote']['keyword'] . '%',
'Contacts.lname LIKE' => '%' . $this->request->data['Quote']['keyword'] . '%',
'CONCAT(Contacts.fname, Contacts.lname) LIKE' => '%' . $this->request->data['Quote']['keyword'] . '%',
'Quotes.description LIKE' => '%' . $this->request->data['Quote']['keyword'] . '%'
)
);
$cond = array(
'conditions' => array_merge($searchConditions, $searchCondition, $limo),
'order'= > array('Quotes.quotenum desc'),
'contain' => array('Branches','Contacts')
);
$this->set('articleList', $this->paginate($this->Quotes));
As you can see I merge the condition arrays with each other and then send them to paginate. This worked fine in CakePHP 2.7. However now I get the error
Column not found: 1054 Unknown column 'contacts.lname' in 'where clause'.
The lname column definitely exits in the database table. Is there something I am doing wrong. If so, could someone tell me the right way to do concat search as I have been trying to do this for quite some time.

Yu have to use query expression but this can't be done in a pagination array.
So Following ndn suggestion here's how I would do
create a custom finder. In your QuotesTable file
public function findByKeyword(Query $query, array $options)
{
$keyword = $options['keyword'];
$query->where(
function ($exp, $q) use($keyword){
$conc = $q->func()->concat([
'Contacts.fname' => 'literal', รน
'Contacts.lname' => 'literal']);
return $exp
->or_([
'Quotes.quotenum LIKE' => "%$keyword%",
'Branches.name LIKE' => "%$keyword%",
'Contacts.fname LIKE' => "%$keyword%",
'Contacts.lname LIKE' => "%$keyword%",
'Quotes.description LIKE' => "%$keyword%"
])
->like($conc, "%$keyword%");
}
);
return $query;
}
Then in your controller
$this->paginate = [
'finder' => [
'byKeyword' => [
'keyword' => $this->request->data['Quote']['keyword']
]],
'conditions' => $limo, // this will merge your $limo conditions
// with the ones you set in the custom finder
'order'= > ['Quotes.quotenum desc'],
'contain' => ['Branches','Contacts']
];
$this->set('articleList', $this->paginate($this->Quotes));

Related

How to add multiple conditions for a single column?

I have many sentences that I need filter for a same column:
'conditions' => array('Zona.nombre LIKE' => $buscar,
'Zona.nombre LIKE' => 'CUPONATIC%',
'Zona.nombre LIKE' => 'GROUPON%'
),
your question is not very clear but I suppose the problem is that you use multiple time the same array key
You don't even mention the cakephp version but it seems cake2
If I remember well the workaround for cake2 is putting every condition in a different array
'conditions' => array(
array('Zona.nombre LIKE' => $buscar),
array('Zona.nombre LIKE' => 'CUPONATIC%'),
array('Zona.nombre LIKE' => 'GROUPON%')
),
edit: of course this way you'll have the 3 conditions joined in AND.
It seems more logical to put them in OR so
'conditions' => array(
'OR' => array(
array('Zona.nombre LIKE' => $buscar),
array('Zona.nombre LIKE' => 'CUPONATIC%'),
array('Zona.nombre LIKE' => 'GROUPON%')
)
),

get records with 2 not like conditions in cakephp3

This query doesnt work as expected. What happens it will select records with the word assessment in it. I have tried a few variations but as you can see the query should only get records with the word 'maths' and exclude records with 'scholarship' and 'assessment'.
I cant get this to work in cakephp3. What happens is that i get records with the words assessment or scholarship.
$subjectMaths = $this->Students->Subjects->find('list')
->select(['id', 'name'])
->where([
'Subjects.name not LIKE' => '%assessment%' ,
'Subjects.name LIKE' => '%maths%',
'Subjects.name not LIKE' => '%scholarship%'
])
->order(['Subjects.name' => 'asc']);
$subjectMaths = $this->Students->Subjects->find('list')
->select(['id', 'name'])
->where([
'Subjects.name LIKE' => '%maths%',
'OR'=> [
['Subjects.name not LIKE' => '%assessment%' ],
[ 'Subjects.name not LIKE' => '%scholarship%',]
]
])
->order(['Subjects.name' => 'asc']);
the proble here is that you have two identical array keys Subjects.name not LIKE. The second overwrites the first
So you havw to use AndWhere()
$subjectMaths = $this->Students->Subjects->find('list')
->select(['id', 'name'])
->where(['Subjects.name not LIKE' => '%assessment%'])
->andWhere(['Subjects.name LIKE' => '%maths%'])
->andWhere(['Subjects.name not LIKE' => '%scholarship%'])
->order(['Subjects.name' => 'asc']);

Paginating results from model function

For CakePhp 2.5
I have the following search function in my Controller.
public function search($query = null, $lim = null)
{
$tokens = explode(" ", $query);
$this->Paginator->settings = array(
'conditions' => array(
'Customer.site_id LIKE' => '%' . $this->viewVars['shopId'],
'CONCAT(Customer.first_name," ",Customer.last_name," ",Customer.organisation) LIKE' => '%' . implode(' ', $tokens) . '%'
),
'limit' => $lim
);
$this->set('customers', $this->Paginator->paginate());
}
This works fine, and gets the results i want.
However, its been suggested to me that I should put these search functions in my model. I can easily do this, and have done so similar as follows in my model:
public function getActiveTasks($id){
return $this->Task->find('all', array(
'conditions' => array(
'Task.customer_id' => $id,
'Task.status' => 0
),
'order' => array('Task.due_date ASC'),
'recursive' => -1,
));
}
The issue I'm having is that I cannot (or don't know how to) use Paginator with custom searches. Is there a way to paginate results from custom functions?
ie, can I do the following:
public function CustomModelSearch($query = null, $lim = null)
{
return $this->Task->find('all', array(
'conditions' => array(
'Customer.site_id LIKE' => '%' . $this->viewVars['shopId'],
'CONCAT(Customer.first_name," ",Customer.last_name," ",Customer.organisation) LIKE' => '%' . implode(' ', $tokens) . '%'
),
'limit' => $lim
));
}
and then in the controller call
$results = $this->Model->CustomModelSearch($query, $lim);
$this->set('results',$this->Paginate($results));
I cannot find a way to pass results into the paginator to render paged results to the view, unless I use it via the controller as per the first piece of code, which i've been told isn't good MVC principles.
To create custom pagination you have two options:
Create a Custom Query Pagination with a paginate and paginateCount funtions
// paginate and paginateCount implemented on a behavior.
public function paginate(Model $model, $conditions, $fields, $order, $limit,
$page = 1, $recursive = null, $extra = array()) {
// method content
}
public function paginateCount(Model $model, $conditions = null, $recursive = 0,
$extra = array()) {
// method body
}
or create a custom find and set Paginator to use that find.
good to understand but the truth should tell me that bug hits you in what you're doing.
The function in the model of "Task" you should not put $this->task->findjust$this->find that if you are in the model not need specify which model you are using, ou only need to do this in the controller.
model/Task.php:
public function CustomModelSearch($query = null, $lim = null)
{
return $this->find('all', array(
'conditions' => array(
'Customer.site_id LIKE' => '%' . $this->viewVars['shopId'],
'CONCAT(Customer.first_name," ",Customer.last_name," ",Customer.organisation) LIKE' => '%' . implode(' ', $tokens) . '%'
),
'limit' => $lim
));
}

How to apply && between 3 $conditions[] ? in cakephp

In Cakephp how can i add apply 'AND' between these lines , $conditions[]= codition1 && codition2 && condition3;
$conditions[]= array('Flight.from LIKE' => "%".$this->request->data['Flight']['from']."%");
$conditions[]= array('Flight.to LIKE' => "%".$this->request->data['Flight']['to']."%");
$conditions[]= array('Flight.date LIKE' => "%".$this->request->data['Flight']['date']."%");
You can simplify your query by using:
$conditions = array(
'Flight.from LIKE' => "%".$this->request->data['Flight']['from']."%",
'Flight.to LIKE' => "%".$this->request->data['Flight']['to']."%",
'Flight.date LIKE' => "%".$this->request->data['Flight']['date']."%"
);
You don't actually need the arrays around each field when the conditions are on different fields. Plus CakePHP will automatically use AND between your conditions.
$conditions = array(
'AND' => array(
'Flight.from LIKE' => "%".$this->request->data['Flight']['from']."%",
'Flight.to LIKE' => "%".$this->request->data['Flight']['to']."%",
'Flight.date LIKE' => "%".$this->request->data['Flight']['date']."%"
)
);
Official docs and examples here.

CakePHP adding array elements to an array

I think I have my dumber-than-usual head on today.
I am trying to parse text from a textbox in a form to generate an array that I can pass to the find method in cakePHP.
I have used php regular expressions to generate an array of the terms entered (including "phrases included in speech marks" as single item)
This may look like this:
array(
(int) 0 => 'test',
(int) 1 => 'this out',
(int) 2 => 'now')
In the cakePHP cookbook it says that I have to get an array that looks like this (using above example):
array(
array('ProjectDocumentSectionVariable.variable_description LIKE' => '%test%'),
array('ProjectDocumentSectionVariable.variable_description LIKE' => '%this out%'),
array('ProjectDocumentSectionVariable.variable_description LIKE' => '%now%'))
Try as I might, I end up with arrays that do NOT look like an array of arrays.
Typically I am ending up with this horrible looking thing:
array(
(int) 0 => array(
'ProjectDocumentSectionVariable.variable_description LIKE' => '%test%'
),
(int) 1 => array(
'ProjectDocumentSectionVariable.variable_description LIKE' => '%this out%'
),
(int) 2 => array(
'ProjectDocumentSectionVariable.variable_description LIKE' => '%now%'
))
The code for the above is:
$i = 0;
foreach($matches[1] as $match) :
$searcharray['ProjectDocumentSectionVariable.variable_description LIKE'] = "%" . $match . "%";
array_push($array_full,$searcharray);
$i++;
endforeach;
THis must be a common requirement, so I am hoping one of you guys could put me on the straight an narrow...
Thanks
If you're trying to build a search query (not clear what your goal is), your conditions should all be in the same array within an OR or AND - something like this:
$searchResults = $this->find('all', array(
'conditions' => array(
'OR' => array(
'ProjectDocumentSectionVariable.variable_description LIKE' => '%test%',
'ProjectDocumentSectionVariable.variable_description LIKE' => '%this out%',
'ProjectDocumentSectionVariable.variable_description LIKE' => '%now%'
)
)
));
If you want to build it out in a foreach() loop, you can do it something like this:
$conditions = array('OR' => array());
$matches = array('test', 'this out', 'now');
foreach($matches as $match) {
array_push($conditions['OR'], array('variable_description LIKE' => '%' . %match . '%'));
}
$searchResults = $this->find('all', array(
'conditions' => $conditions
));
its as simple as this:
$array= array();
foreach ( $colors as $c):
$uniques[] = $c;
endforeach;
not having the [] will treat it as a regular variable. This will append it to the array

Resources