I have a search form using the get method. The form works fine until I use it after paginating through the results.
Users can enter the site from any number of urls that look like domain.com/serach/results/something/something_else/ the important part is the domain.com/serach/results/.
Here's what my code for the the form looks like:
echo $this->Form->create(null, array(
'type' => 'get',
'url' => $this->Html->url(null, true),
));
This will make the form look like this:
<form action="http://domain.com/serach/results/something/something_else/" method="get">
The problem is that when I paginate the results it adds the page:2 or page:3 to the action so it looks like:
<form action="http://domain.com/serach/results/something/something_else/page:3" method="get">
Is there a built in function in CakePHP that lets me remove the page:3from the url that's being passed to the form action or am I going to have to create a function that looks for and removes the page:#?
just set your url the verbose way:
'url' => array('controller' => 'x', 'action' => 'y') + $this->request->params['pass']
Done!
Related
I have a question about how I can search, for example, by name or surname in the INDEX view.
Is there any plugin or easy-to-use component that does not load the application too much?
Currently, I have a small form in index.ctp with one input field, where I enter what I want to search, and in controller have an if ($ this-> request-> is ('post')) after which to $this->Model->find adds condition WHERE. But I admit that this is not a nice way, it also reload the page.
This is the controller:
public function index()
{
if ($this->request->is('post')) {
$s = '%'.$this->request->getData('Search').'%';
$students = $this->Students->find('all')->where(['OR' => ['name LIKE' => $s, 'lastname LIKE' => $s]]);
$this->set('students', $this->paginate($students));
} else {
$students = $this->paginate($this->Students);
$this->set(compact('students'));
}
}
And this is the index.ctp:
<div class="input-group mb-3">
<?= $this->Form->button(__('<i class="fas fa-search"></i>'), ['escape' => false, 'class' => 'btn btn-primary']) ?>
<?= $this->Form->input('Search', ['type' => 'text', 'class' => 'form-control', 'label' => false]); ?>
<?= $this->Form->end() ?>
</div>
From what I can see you are either after a better solution to handle searching and/or a way of not reloading the page to display your search results.
If this isn't what you are after then please clarify your question to better outline what you would like you solution to look like.
You should be separating your searching out of your index function as that is only to display the content on that page. Adding conditions like you have will end up in you having a really long index function running your whole application based on the differences in the request, which isn't great.
Split out the searching into a separate function which will in turn create a new page for you to display your results.
public function index()
{
$students = $this->paginate($this->Students);
$this->set(compact('students'));
}
public function search()
{
$s = '%' . $this->request->getData('Search') . '%';
$students = $this->Students->find('all')->where(['OR' => ['name LIKE' => $s, 'lastname LIKE' => $s]]);
$this->set('students', $this->paginate($students));
}
This is well described in the tutorial on the CakePHP docs - CMS Tutorial - Creating the Articles Controller and can be related to your application as the index for you contains a form to pass search criteria to your application and the search function/page will then fetch the results and display them for you.
Don't forget to then alter your form to point it to the /search page. - Setting a URL for the Form
You will need to create a search.ctp file in your src/Template/ExampleController folder. Put your html code in there to display the results in a table or however you want to display the search results.
Finally you will need to add a route to your routes.php to allow the /search path in your application.
$routes->connect('/search', ['controller' => 'Example', 'action' => 'search']);
Now if you don't want the page to reload when you use your form then you have to use Ajax and JS/JQuery to make the request to your search method and display the results of the search function on the page dynamically. There are already a lot of good examples of this on stackoverflow and the web for using ajax and jquery for building tables from searches so I won't bother posting them here.
If you want a plugin/library solution then look at this tutorial on having search results displayed in a table using DataTables. - Search Using Datatables
install plugin https://github.com/FriendsOfCake/search
then in search configurations
$this->searchManager()
// Here we will alias the 'q' query param to search the `Students.name`
// field and the `Students.lastname` field, using a LIKE match, with `%`
// both before and after.
->add('q', 'Search.Like', [
'before' => true,
'after' => true,
'fieldMode' => 'OR',
'comparison' => 'LIKE',
'wildcardAny' => '*',
'wildcardOne' => '?',
'field' => ['name', 'lastname']
]);
Assume I'm in my items controller.
Ok say I am in my view action (the url would be something like /items/view/10012?date=2013-09-30) which lists a list of items that belongs to a client on a given date.
I want to link to add a new item. I would use the htmlhelper like so:
echo $this->Html('action'=>'add');
In my add action I have a form which has fields like client_id and item_date.
When I'm in my view action I know these values as I am viewing the items for a specific client on a specific date. I want to pass these variables to my add action so it will prefill those fields on the form.
If I add a query string in my link ('?' => array('client_id'=>$client_id)) it breaks the add action as it will give an error if the request is not POST. If I use a form->postLink I get another error as the add action's POST data must only be used for adding the record, not passing data to prefill the form.
I basically want to make my link on the view page pass those 2 variables to the add action in the controller so I can define some variables to prefill the form. Is there a way to do this?
Here is my add controller code. It may differ in content a bit from my question above as I have tried to simplify the question a bit but the concept should still apply.
public function add(){
if ($this->request->is('post')) {
$this->Holding->create();
if ($this->Holding->save($this->request->data)) {
$this->Session->setFlash(__('Holding has been saved.'), 'default', array('class' => 'alert alert-success'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to add your holding.'), 'default', array('class' => 'alert alert-danger'));
}
$this->set('accounts', $this->Holding->Account->find('list'));
$sedol_list = $this->Holding->Sedol->find('all', array(
'fields' => array(
'id', 'sedol_description'
),
'recursive' => 0,
'order' => 'description'
)
);
$this->set('sedols', Hash::combine($sedol_list, '{n}.Sedol.id', '{n}.Sedol.sedol_description') );
}
Why not use proper Cake URL parameters?
echo $this->Html->link('Add Item', array(
'action' => 'add',
$client_id,
$item_date
));
This will give you a much nicer URL like:
http://www.example.com/items/add/10012/2013-09-30
And then in your controller, you modify the function to receive those parameters:
public function add($client_id, $item_date) {
// Prefill the form on this page by manually setting the values
// in the request data array. This is what Cake uses to populate
// the form inputs on your page.
if (empty($this->request->data)) {
$this->request->data['Item']['client_id'] = $client_id;
$this->request->data['Item']['item_date'] = $item_date;
} else {
// In here process the form data normally from when the
// user has submitted it themselves...
}
}
I'm calling CHtml::ajaxlink like so:
<?php echo CHtml::ajaxLink('Add to a list',
$this->createUrl('itemList/ajaxadditem'),
array(
'onclick'=>'$("#addToListDialog").dialog("open"); return false;',
'type'=>'POST',
'update'=>'#addToListDialog',
'data' => 'js:{"product_id" : $("#productID").val()}'
),
array('id'=>'showAddToListDialog'));
?>
I don't know how to write the values of the AJAX options array dynamically. I'm using a workaround to get the value using JavaScript, $("#productID").val() and a hidden field.
I want to write something like:
'data' => 'js:{"product_id" : "$model->product_id"}'
But "$model->product_id" is entered as a literal string.
Can anyone give me a way to do this? My method won't actually solve the problem since I need to write this AJAX link multiple times on the fly.
Assuming your $model instance is available, you should be able to append it dynamically like below:
'data' => "js:{'product_id' : '{$model->product_id}'}"
I have the following route set at the end of the route list for my site which allows a final check on the uri value to provide my site users with a vanity URL (http://example.com/username)
Route::set('profile', '<path>/(<page>)',
array(
"path" => "[a-zA-Z0-9_-]+",
"page" => (blog|photos)))
->defaults(array(
'controller' => 'welcome',
'action' => 'profile'
));
This route directs properly to the welcome controller and the profile method, however I was wondering if there was a way to get the path and page values sent to the method like so:
action_profile($var1, $var2) {
echo $var1 . ' ' . $var2;
}
I don't want to rely on $this->request->uri() and exploding the result into an array unless there is absolutely no other way of doing this.
Read the manuals please: http://kohanaframework.org/3.0/guide/kohana/routing#request-parameters. $this->request->param('param-name') will helps.
I am trying to use a drop down input in my cakephp application, with this I want the drop down on submit to render the url like so:
www.example.com/cake/FILE/VALUE
However the only url i can get the select input to create is the following:
www.example.com/cake/FILE?form_value=VALUE
How do I go about making the URL SEO friendly like the first example without using httaccess because I want the URL to appear seo friendly in the search engines eyes.
Here is the code I am using.
In The VIEW
echo $form->input('form_value', array(
'label' => '',
'type' => 'select',
'options' => $listOfOptions,
'selected' => '0',));
Thank you.
In your controller, get the value of "form_value" through $file = $this->data['FILE']['form_value'] and do a redirect $this->redirect(array('action' => 'download', $file)).
You then create a function called download which should look like this:
<?php
function download($file = null) {
if ($file != null) {
/*make download*/
} else {
$this->Session->setFlash('no file specified')
}
?>
If you don't want the action "download" to appear in the URL you can use Cakes built-in routes in cakephp/app/config/routes.php.
With something like this you could map the index-action to the download-action:
Router::connect('/FILE/*', array('controller' => 'files', 'action' => 'download'));
See http://book.cakephp.org/view/46/Routes-Configuration for better explanation.