I am using the search plugin on https://github.com/cakedc/search. I am trying to search for records using the ID field only, that is if i type in 1 on my form input it must show a record with user ID 1. The challenge that i am having now is when i specify that the input should be the id field, the input field for the search functionality disappears on my index view, strange thing is when i specify a different field name the input field shows.
Below is my code for my Model
public $actsAs = array('Search.Searchable');
public $filterArgs = array(
'id' => array('type' => 'like', 'field' => 'ItSupportRequest.id'),
);
public function findByTags($data = array()) {
$this->Tagged->Behaviors->attach('Containable', array('autoFields' => false));
$this->Tagged->Behaviors->attach('Search.Searchable');
$query = $this->Tagged->getQuery('all', array(
'conditions' => array('Tag.name' => $data['tags']),
'fields' => array('foreign_key'),
'contain' => array('Tag')
));
return $query;
}
public function orConditions($data = array()) {
$filter = $data['filter'];
$cond = array(
'OR' => array(
$this->alias . '.id LIKE' => '%' . $filter . '%',
));
return $cond;
}
and here is my controller code.
public $components = array('Search.Prg');
public $presetVars = true; // using the model configuration
public function find() {
$this->Prg->commonProcess();
$this->paginate['conditions'] = $this->ItSupportRequest->parseCriteria($this->passedArgs);
$this->set('articles', $this->paginate());
}
and in my index.ctp file i have this code.
<?php
echo $this->Form->create('ItSupportRequest', array(
'url' => array_merge(array('action' => 'find'), $this->params['pass'])
));
echo $this->Form->label('Query ID:') . "<br/>";
echo $this->Form->input('name', array('div' => false, 'label' => false));
echo $this->Form->submit(__('Search'), array('div' => false));
echo $this->Form->end();
?>
Thanks in advance.
You should not call it id as id will be hidden (because cake assumes this is a primary key here).
Either name it something else or manually overwrite this behavior using
$this->Form->input('id', array('type' => 'text'));
But I would go with sth like "search" and
$this->Form->input('search', array('placeholder' => 'ID to look for'));
and
public $filterArgs = array(
'search' => array('type' => 'like', 'field' => 'ItSupportRequest.id'),
);
Related
I want a simple search feature that can search the current selected results on the model's index page. I have created a model Search which has no actual table:
class Search extends AppModel {
protected $_schema = array(
'search_term' => array('type' => 'string' , 'null' => true, 'default' => '', 'length' => '255'),
'model' => array('type' => 'string' , 'null' => true, 'default' => '', 'length' => '255'),
);
public $useTable = false;
public $validate = array(
'search_term' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'Please enter a search term'
),
'between' => array(
'rule' => array('between',3,30),
'message' => 'Please enter a search term greater than 3 characters.'
)
)
);
}
In any index.ctp view I have this with a hidden input field with the model's name:
echo $this->Form->create('Search, array('action' => 'search'));
echo $this->Form->input('search_term', array('label'=> 'Search'));
echo $this->Form->input('model', array('type'=> 'hidden', 'value'=>$this->params['controller']));
echo $this->Form->end(__('Submit'));
In the SearchesController:
public function search() {
$conditions = null;
if( $this->request->is('post') ) {
$searchModel = $this->request->data[$this->modelClass]['model'];
...
$this->{$this->modelClass}->useTable = Inflector::tableize($searchModel);
...
$this->paginate = array('conditions'=>array($groups,'OR' => $conditions));
$this->set($searchModel, $this->paginate());
$this->render("/$searchModel/index");
}
Problem is paginate is returning an array with the model labelled as 'Search' (understandably because of the useTable call) and not say Groups or Users, the model's being searched. Any way to relabel the array returned from paginate to the model being searched ? The alternative is to modify all the index.ctp files or create a results.ctp for each model.
I wouldn’t create another model merely for searching; it’s a hack and not extendable.
In the past, I’ve just used parameters (usually in the query string) to alter the conditions array (whether it’s a normal find operation of a paginate operation). An example:
<?php
class ItemsController extends AppController {
public function index() {
$conditions = array();
if (isset($this->request->query['search'])) {
$conditions['Item.title'] = $this->request->query['search'];
}
$items = $this->Item->find('all', array(
'conditions' => $conditions
));
$this->set(compact('items'));
}
}
Hopefully the above demonstrates this approach.
I've tried every simple cakedc search setup, and followed code samples from previous posts on this but it just won't seem to cooperate for me. I'm not sure, but there doesn't seem to be any search query generated with the search string, judging from a query log I have running on my database.
When I try to search, from /books/search, I get no results on a title I know is in the database and the URL changes to /books/index/title:sweet (I'm not sure if that is relevant).
Any help would be much appreciated.
Model
public $actsAs = array('Search.Searchable');
public $primaryKey = 'isbn13';
public $hasMany = array(
'Contributor' => array (
'className' => 'Contributor',
'foreignKey' => 'isbn13'
),
'Override' => array (
'className' => 'Override',
'foreignKey' => 'isbn13'
)
);
public $filterArgs = array(
'title' => array('type' => 'query', 'method' => 'filterTitle'),
'main_desc' => array('type' => 'value')
);
public function filterTitle($data, $field = null) {
if (empty($data['title'])) {
return array();
}
$titleField = '%' . $data['title'] . '%';
return array(
'OR' => array(
$this->alias . '.title LIKE' => $titleField,
));
}
Controller
class BooksController extends AppController {
public $helpers = array ('Html', 'Form');
public $paginate = array();
public $components = array('Search.Prg');
public $presetVars = true;
public function index() {
//get books
$this->set('books', $this->Book->find('all'));
//search
/* $this->Prg->commonProcess();
$this->paginate['conditions'] = $this->Book->parseCriteria($this->Prg->parsedParams());
$this->set('books');
*/
}
public function search($books = NULL) {
$this->Prg->commonProcess();
$this->paginate['conditions'] = $this->Book->parseCriteria($this->passedArgs);
$this->set('books', $this->paginate());
}
View
<h1>Search Results</h1>
<?php
echo $this->Form->create('Book' , array(
'url' => array_merge(array('action' => 'search'), $this->params['pass'])
));
echo $this->Form->input('title', array('div' => false, 'empty' => true)); // empty creates blank option.
echo $this->Form->submit(__('Search', true), array('div' => false));
echo $this->Form->end();
Routes
Router::connect('/', array('controller' => 'books', 'action' => 'index'));
Router::connect('/index/*', array('controller' => 'books', 'action' => 'search'
));
Router::connect('/view/:url', array('controller' => 'books', 'action' => 'view', array('url' => '[\w\W]*')
));
Router::connect('/edit/:url', array('controller' => 'books', 'action' => 'edit', array('url' => '[\w\W]*')
));
Router::connect('/whatsnew/*', array('controller' => 'books', 'action' => 'whatsnew'
));
Router::connect('/search/*', array('controller' => 'books', 'action' => 'search'
));
I've renamed the search-master folder to Search and put it in my plugins directory and In my bootstrap.php I've loaded the plugin
CakePlugin::load('Search');
Fixed! Needed
$this->set('books', $this->paginate($this->Book->parseCriteria($this->passedArgs)));'
instead of
$this->set('books', $this->paginate());'
in the controller. Not sure why though..
How can I keep the same checkboxes checked after submit? All the other input fields on the form automatically keeps the values. I thought this would also go for checkboxes, but nope.
echo $this->Form->input('type_id', array(
'multiple' => 'checkbox',
'options' => array(
'1' => 'Til salgs',
'2' => 'Ønskes kjøpt',
'3' => 'Gis bort'
),
'div' => false,
'label' => false
));
I believe this can be done in the controller, but how?
Edit:
Since I posted this question I've changed to CakeDcs Search plugin, because I've gotten this to work with that before. Still... I can't get it to work this time.
Adding model and controller code:
AppController
public $components = array('DebugKit.Toolbar',
'Session',
'Auth' => array(
'loginAction' => '/',
'loginRedirect' => '/login',
'logoutRedirect' => '/',
'authError' => 'Du må logge inn for å vise denne siden.',
'authorize' => array('Controller'),
),
'Search.Prg'
);
public $presetVars = true; //Same as in model filterArgs(). For Search-plugin.
AdsController
public function view() {
$this->set('title_for_layout', 'Localtrade Norway');
$this->set('show_searchbar', true); //Shows searchbar div in view
$this->log($this->request->data, 'debug');
//Setting users home commune as default filter when the form is not submitted.
$default_filter = array(
'Ad.commune_id' => $this->Auth->user('User.commune_id')
);
$this->Prg->commonProcess(); //Search-plugin
$this->paginate = array(
'conditions' => array_merge($default_filter, $this->Ad->parseCriteria($this->passedArgs)), //If Ad.commune_id is empty in second array, then the first will be used.
'fields' => $this->Ad->setFields(),
'limit' => 3
);
$this->set('res', $this->paginate());
}
Model
public $actsAs = array('Search.Searchable');
public $filterArgs = array(
'search_field' => array('type' => 'query', 'method' => 'filterSearchField'),
'commune_id' => array('type' => 'value'),
'type_id' => array('type' => 'int')
);
public function filterSearchField($data) {
if (empty($data['search_field'])) {
return array();
}
$str_filter = '%' . $data['search_field'] . '%';
return array(
'OR' => array(
$this->alias . '.title LIKE' => $str_filter,
$this->alias . '.description LIKE' => $str_filter,
)
);
}
/**
* Sets the fields which will be returned by the search.
*
* #access public
* #return array Database table fields
* #author Morten Flydahl
*
*/
public function setFields() {
return array(
'Ad.id',
'Ad.title',
'Ad.description',
'Ad.price',
'Ad.modified',
'User.id',
'User.first_name',
'User.middle_name',
'User.last_name',
'User.link',
'User.picture_url',
'Commune.name',
'Type.id',
'Type.name'
);
}
You have to set manually the selected option of the input, as an array with "keys = values = intval(checkbox id)"
I cannot explain why this format, but this is the only way I get it to work.
Here is my code:
echo $this->Form->create('User');
// Read the submitted value
$selected = $this->Form->value('User.Albums');
// Formats the value
if (empty($selected)) {
$selected = array(); // avoid mess
} else {
$selected = array_map('intval', $selected);
$selected = array_combine ($selected, $selected);
}
// Renders the checkboxes
echo $this->Form->input('Albums',array(
'type' => 'select',
'multiple' => 'checkbox',
'options' => $albums, // array ( (int)id => string(label), ... )
'selected' => $selected, // array ( (int)id => (int)id, ... )
));
Hope this helps.
++
I've set a simple search engine on my CakePHP project which looks like that :
<?php
echo $this->Form->create("Post", array(
"action" => "search",
"id" => "searchForm"
));
echo $this->Form->input("keyword", array(
"label" => "",
"type" => "search",
"placeholder" => "Recherche..."
));
echo $this->Form->end();
?>
Here is the controller :
function search() {
$keyword = $this->request->data;
$keyword = $keyword["Post"]["keyword"];
$cond = array("OR" => array(
"Post.title LIKE '%$keyword%'",
"Post.description LIKE '%$keyword%'"
));
$posts = $this->Post->find("all", array("conditions" => $cond));
$this->set(compact("posts", "keyword"));
}
And it works great. The only problem is when I want to paginate the results. I simply add :
$posts = $this->paginate();
And here is the problem. When I add this, CakePHP give me all the posts and not only the ones that match the keyword.
So, if you would have a solution, it would be nice :)
According to the CakePHP book you should be able to do
$this->paginate('Post', array(
'OR' => array(
'Post.title LIKE' => "%$keyword%",
'Post.description LIKE' => "%$keyword%"
)
));
Or you can do it like this ( from the cakephp site ).
public function list_recipes() {
$this->paginate = array(
'conditions' => array('Recipe.title LIKE' => 'a%'),
'limit' => 10
);
$data = $this->paginate('Recipe');
$this->set(compact('data'));
);
Source:
http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
Paginate does its own lookup on the data I believe. The find you are calling previously has no effect on the paginate.
Try this:
$this->paginate = array( 'conditions' => $cond, ));
you can use Session for storing conditions
the first, when you submit form you store conditions into Session
and then(paginate) you can read conditions from Session
example i want to search the products:
Products/search.ctp
<?php
echo $this->Form->create('Product');
echo $this->Form->input('keyword');
echo $this->Form->end(__('Search'));
?>
ProductsController.php
<?php
class ProductsController extends AppController{
public function search() {
if ($this->request->is('post')) {
$keyword = $this->request->data['Product']['keyword'];
$this->paginate = array(
'fields' => array('Product.name', 'Product.price', 'Product.created'),
'order' => array('Product.created' => 'DESC', 'Product.price' => 'DESC'),
'limit' => 30,
'conditions' => array('Product.name LIKE' => '%' . $keyword . '%')
);
// store array $this->paginate into Session
$this->Session->write('paginate', $this->paginate);
}
$this->paginate = $this->Session->read('paginate');
$this->set('products', $this->paginate('Product'));
}
}
Hi I'm currently using the CakeDC search plugin for my CakePHP (2.2 app).
The search facility itself works fine, however I cannot get the results or the data shown on page before the search to paginate.
Heres my code
Model:
// Configure Meio file uploader
var $actsAs = array(
'MeioUpload.MeioUpload' => array(
'filename' => array(
'allowedMime' => array('image/jpeg', 'image/pjpeg', 'image/png', 'application/pdf'),
'allowedExt' => array('.jpg', '.jpeg', '.png', '.pdf'),
'maxSize' => '8 Mb'
)
),
'Search.Searchable'
);
// Search plugin filters
public $filterArgs = array(
'title' => array('type' => 'like'),
'live' => array('type' => 'value'),
'search' => array('type' => 'like', 'field' => 'FaqArticle.description'),
'error' => array('type' => 'like'),
'description' => array('type' => 'like')
);
Controller:
// Search plugin
public $components = array('Search.Prg');
public $presetVars = true; // using the model configuration
public function admin_index() {
$this->Prg->commonProcess();
$this->paginate = array('conditions' => $this->FaqArticle->parseCriteria($this->passedArgs));
$this->set('faqArticles', $this->paginate());
// Count all live articles for intro text
$this->set('liveArticles', $this->FaqArticle->find('count', array('conditions' => array('FaqArticle.live' => '1')
)));
// Count all articles for intro text
$this->set('countedArticles', $this->FaqArticle->find('count'));
// Set searched for details
$this->set('searchedFor', $this->passedArgs);
// Set layout
$this->layout = 'admin';
}
View:
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
echo $this->Paginator->numbers(array('tag' => 'li', 'separator' => '', 'currentClass' => 'active', 'modulus' => '5'));
echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
?>
</ul>
this code:
public $components = array('Search.Prg');
public $presetVars = true; // using the model configuration
Should be in your controller, not your model. Models don't have 'components'. Controllers have 'components'. And check the doco for the Serach plugin - the $filterArgs goes in the model (which you've done correctly), but the $presetVars goes in the controller.
Don't set $presetVars as an empty array. Just move it from your model to your controller. It should be declared up the top as a public var, as you've done in your model, and shouldn't be declared inside the admin_index method.