I have a form with a search input:
echo $this->Form->create('Job', array('url'=>array('controller'=>'jobs', 'action'=>'search'), 'action'=>'search', 'inputDefaults' => array( 'label' => false, 'div'=>false)));
echo '<br/>'.$this->Form->input('search', array( 'label' => false, 'div'=>false));
echo $this->Form->submit('Search', array('div' => false));
in my controller I have the paginate array like so:
public $paginate = array(
'Job' => array(
'fields' => array('Job.id', 'Job.name', 'Job.description', 'Job.tag_words'),
'limit' => 5,
'order' => array(
'Job.name' => 'asc'
)),
);
and then my search function is:
public function search () {
if ($this->request->is('post')) {
$conditions = array();
$search_terms = explode(' ', $this->request->data['Mix']['search']);
foreach($search_terms as $search_term){
$conditions[] = array('Mix.name Like' =>'%'.$search_term.'%');
$conditions[] = array('Mix.description Like' =>'%'.$search_term.'%');
$conditions[] = array('Mix.tag_words Like' =>'%'.$search_term.'%');
}
$searchResults = $this->paginate('Mix', array('Mix.published'=>1, 'OR' => $conditions));
$this->set('searchResults', $searchResults);
}
}
That works for the first page of results but in my view I have the previous/next helpers and clicking to go to page two just brings up an empty page. How am I meant to keep the search term and be able to go to page two?
The Paginator::sort method uses a get to pass the parameters, you should pass the search term as GET then in your view, before you call the pagination links try this:
$this->Paginator->options = array(
'url' => $this->passedArgs
);
That should have your search term persist with your pagination links.
Related
I'm working on a module where I need to save the records based on the scope of website and store. For that I need to have the select box as its in the system->configuration.
How can I get that select box in my form and save the website/store value in database so that it can be displayed in the specific store/website? Any suggestions on it?
Now I'm trying it breaking into two fields -> website and store. Now, how can I change the options in store based on the website selected?
Finally, I'd written my own code for this.
$scope = array('default' => 'default');
foreach (Mage::app()->getWebsites() as $website) {
$scope['website_' . $website->getCode()] = $website->getName();
foreach ($website->getGroups() as $group) {
$stores = array();
foreach ($group->getStores() as $store) {
$stores[] = array(
'label' => $store->getName(),
'value' => 'store_' . $store->getCode()
);
}
$scope[] = array(
'label' => $website->getName(),
'value' => $stores
);
}
}
$fieldset->addField('website', 'select', array(
'label' => Mage::helper('designer')->__('Website'),
'name' => 'website',
'values' => $scope
));
Thanks to this post by Marius
Within CakePHP 2 I am using pagination which works great until I see the URL which is page:2, how can I make this ?page=2 ?
The next question is that I use this code for my controller which powers /domain.com/offers/top, /domain.com/offers/newest, /domain.com/offers/popular and then the categories like /domain.com/offers/tv-and-video. The thing is when it is paginated for /domain.com/offers/top instead of being /offers/top/page:2 it goes to /offers/bycategory/top/page:2.
public function bycategory($slug = null)
{
$userId = $this->Session->read("UserAuth.User.id");
if ($slug == 'top') {
//Get the top rated offers
$this->paginate = array(
'limit' => 15,
'order' => array(
'Offer.vote' => 'desc'
)
);
} elseif ($slug == 'newest') {
//Get the latest offers
$this->paginate = array(
'limit' => 15,
'order' => array(
'Offer.created' => 'desc'
)
);
} elseif ($slug == 'popular') {
//Get the most talked about offers
} else {
//This is the categories, so just get the category slug.
$this->paginate = array(
'conditions' => array('Category.slug =' => $slug),
'limit' => 15,
'order' => array(
'Offer.created' => 'desc'
)
);
}
$offers = $this->paginate('Offer');
// pass the value to our view.ctp
$this->set('offers', $offers);
$this->set('userId', $userId);
$this->render('/Offers/index');
}
This is my custom route:
Router::connect(
'/offers/:catslug',
array('controller' => 'offers', 'action' => 'bycategory'),
array(
'pass' => array('catslug')
));
how can I make this ?page=2 ?
By setting the paramType option in paginator component options as mentioned in manual.
You second issue looks like reverse routing issue. Have you setup any custom routes?
I have the following method which takes a query to search my notes:
function search( $q = null )
{
if ( $q == null )
{
$this->redirect(array('action' => 'index'));
}
$this->paginate = array(
'limit'=>5,
'order'=>'Note.datetime DESC',
'conditions' => array(
'OR' => array(
'Note.title LIKE' => '%'. $q . '%',
'Note.content LIKE' => '%'. $q . '%'
)
),
'Note.status'=>1
);
$this->set('notes', $this->paginate());
$this->render('index');
}
As you can see it takes a single parameter called 'q' which is used to query the model data.
I have hooked up this to the router like so:
Router::connect('/notes',
array('controller'=>'notes','action'=>'index', 'page' => 1),
array(
'pass' => array('page')
)
);
Router::connect('/notes/page/:page',
array('controller' => 'notes', 'action' => 'index'),
array(
'pass' => array('page'),
'page' => '[1-9]+'
)
);
Router::connect('/notes/search/:page/:q',
array('controller'=>'notes','action'=>'search', 'page' => 1),
array(
'pass' => array('page','q')
)
);
Router::connect('/notes/search/:q/page/:page',
array('controller' => 'notes', 'action' => 'search'),
array(
'pass' => array('page','q'),
'page' => '[1-9]+'
)
);
This way I should be getting urls like:
domain.com/notes - loads page 1 of notes
domain.com/notes/page/2 - loads page 2 of notes
domain.com/notes/search/Hello - searches for Hello in notes
domain.com/notes/search/Hello/page/2 - shows page 2 of the above search
The pager in the view looks like:
<?php if(isset($this->request->params['named']['q'])) { ?>
<?php $this->Paginator->options(array('url'=>array('controller' => 'notes', 'action' => $action, 'q' => $this->request->params['named']['q']))); ?>
<?php } else { ?>
<?php $this->Paginator->options(array('url'=>array('controller' => 'notes', 'action' => $action))); ?>
<?php } ?>
It works fine for the index method, but for the search method it is getting confused as when I do a search it's not matching the pager with the route as expected. For example I'm getting urls like domain.com/notes/search/2/:q
Also I don't really like having to wrap the paginator options in an if statement so if I can get it to figure out the url automatically that would be awesome as it's messy having to do this and seems to be the cause of the above problems.
I have connected the named parameter at the top of the router like so:
Router::connectNamed(array('q'));
In the end I opted to make my search working using POST instead of GET so that everything is handled sever-side instead of doing it with messy url rewrites and trying to be clever.
Here's what I made the form look like:
<?php echo $this->Form->create('search', array('url'=>array('controller'=>'notes','action'=>'search'),'class'=>'search')); ?>
<label class="placeholder" for="q">Search</label>
<?php if( isset($q) ) { $term = $q; } else { $term = ''; } ?>
<?php echo $this->Form->input('q', array('label'=>false,'id'=>'q','value'=>$term)); ?>
<button type="submit" class="btn ss-icon ss-search"></button>
<?php echo $this->Form->end(); ?>
the search method:
function search()
{
if ($this->request->is('post')) {
$this->Session->write('q', $this->request->data['search']['q']);
$this->redirect(array('action' => 'search'));
} else {
$q = $this->Session->read('q');
$this->paginate = array(
'limit'=>5,
'order'=>'Note.datetime DESC',
'conditions' => array(
'OR' => array(
'Note.title LIKE' => '%'. $q . '%',
'Note.content LIKE' => '%'. $q . '%'
)
),
'Note.status'=>1
);
$this->set('q',$q);
$this->set('action','search');
$this->set('notes', $this->paginate());
$this->render('index');
}
}
and the routes:
Router::connect('/notes/search',
array('controller'=>'notes','action'=>'search', 'page' => 1),
array(
'pass' => array('page')
)
);
Router::connect('/notes/search/page/:page',
array('controller' => 'notes', 'action' => 'search'),
array(
'pass' => array('page'),
'page' => '[1-9]+'
)
);
and I clean up the session if any other page but the search method is being used in the AppController:
if(strpos($this->here, Router::url(array('controller'=>'notes','action'=>'search'))) === 0 ) {
//echo 'yes';
} else {
$this->Session->delete('q');
}
Which gives me urls like:
domain.com/notes - loads page 1 of notes
domain.com/notes/page/2 - loads page 2 of notes
domain.com/notes/search - searches for Hello in notes (stored in session)
domain.com/notes/search/page/2 - shows page 2 of the above search
In my model I have this
function pieChart($conditions = null) {
//Get Data for PieChart
$this->RecordDrug->virtualFields['sum'] ='COUNT(*)';
$records = array();
$records=$this->RecordDrug->find('list',
array(
'conditions' => $conditions,
'fields' => array( 'Drug.drug', 'sum'),
'order' => array('sum' => 'desc'),
'contain' => array( 'Drug', 'Record' ),
'group' => 'Drug.Drug'
));
return $records;
}
Which basically means that when this function is called by it's self, there are no conditions set. So inside my controller, I am able to define a condition, if i'd like. I want to do the exact same thing except with
'limit' => $limit,
and I assume I need to set
$limit = null
Inside the parenthesis of the function. I've tried & and , and $limit,$conditions = null
but neither of these options worked. I am not too experience with OOP but I assume there is a way to do this?
EDIT:
Updated code, Still not working. The first varialbe that comes inside the functions parenthesis is the one that works, the second one just act's like it's not there
Model:
function pieChart($limit = null, $conditions = null) {
//Get Data for PieChart
$this->RecordDrug->virtualFields['sum'] ='COUNT(*)';
$records = array();
$records=$this->RecordDrug->find('list',
array(
'conditions' => $conditions,
'fields' => array( 'Drug.drug', 'sum','Record.unit'),
'order' => array('sum' => 'desc'),
'limit' => $limit,
'contain' => array( 'Drug', 'Record' ),
'group' => 'Drug.Drug'
));
debug($records);
return $records;
}
Controller:
$conditions = array('Record.user_id' => $this->Session->read('Auth.User.id'));
$pieChart = $this->Record->pieChart($conditions);
$this->set('output',$pieChart);
Even after this conditions variable, it does not only load the users data. If I were to remove '$limit = null' it will work as intended.
This way:
function pieChartTwo($limit = null, $conditions = null) {
...
}
I'm using Cake 2.3.0. If I submit my form using POST, the selected form fields carry over however if I submit my form using GET, all of the form fields return to their default values.
Is there a way to make the GET submission to work like that of the POST?
Here's my contorller:
class ListingsController extends AppController {
public function results() {
$conditions = array(
'Listing.Beds >=' => $this->request->query['beds'],
'Listing.ListingStatus >=' => $this->request->query['status'],
);
$this->paginate = array(
'conditions' => $conditions,
);
$this->set('listings', $this->paginate());
}
}
Here's what my view looks like.
echo $this->Form->create(null, array(
'controller' => 'listings',
'action' => 'results',
'type' => 'get'
));
echo $this->Form->input('name');
$beds = array('1' => '1+', '2' => '2+', '3' => '3+', '4' => '4+', '5' => '5+');
echo $this->Form->input('beds', array('options' => $beds));
$status = array('Active' => 'Active', 'Pending' => 'Pending', 'ActivePending' => 'Active and Pending');
echo $this->Form->input('status', array('options' => $status));
echo $this->Form->end('Update');
So basically if I change 'type' => 'get' to 'type' => 'post' it works just fine. But I need to be able to do this via GET.
Thanks
I agree that this is annoying (IMO CakePHP should be smart enough to automatically determin 'where' to get its data from, based on the 'type').
You'll have to copy the 'query' of the request to the 'data' of the request;
$this->request->data = $this->request->query;
Not behind my computer to test it (as usual, lol), but should probably work.
Try adding this to your controller:
$this->request->data = $this->params['url'];
My solution:
$this->params->data = array('Tablefilter' => $this->params->query);
where "Tablefilter" depends on form definition (usually the model name)
$this->Form->create('Tablefilter', array('type' => 'get'))
Use PRG. Checkout this plugin.
What I ended up doing was looping through the $this->request->query array and pass those values to the matching $this->request->data.
So I added this:
foreach($this->request->query as $k => $v){
$this->request->data['Listing'][$k] = $this->request->query[$k];
}
Which ultimately gave me this:
class ListingsController extends AppController {
public function results() {
foreach($this->request->query as $k => $v){
$this->request->data['Listing'][$k] = $this->request->query[$k];
}
$conditions = array(
'Listing.Beds >=' => $this->request->query['beds'],
'Listing.ListingStatus >=' => $this->request->query['status'],
);
$this->paginate = array(
'conditions' => $conditions,
);
$this->set('listings', $this->paginate());
}
}
I'm not going to accept this as the answer though as I don't know if this is the optimal or suggested way to do it. But it works for me for now.
This works for me :
$this->request->data['Cluster'] = $this->params->query ; //controller side
Form definition:
$this->Form->create('Cluster',array('type'=>'get'));