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.
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']
]);
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!
I have a search form which, if someone fills it in and there are no results to report, I want to make them aware of that but then show them a result set of my choosing. The problem is that when I show them this result set of my choosing and I use the paginator helpers for prev/next they want to pass the search term which is in my URL along with the page number.
That obviously causes problems because there isn't a page:2 for the results search:termHasNoResults
How can I stop the paginator helper passing my search variable in the URL when I'm showing them my alternative result set?
Thanks
Use
$this->Paginator->options('url' => array(
'controller' => 'YOUR CONTROLLER', 'action' => 'YOUR ACTION', 'OTHER PARAMS');
You can pass 'url' option to pagination in your view like this:
$url = array_merge($this->request->pass, $this->request->named);
unset($url['page']);
$parts = explode('?', $_SERVER['REQUEST_URI'], 2);
if (count($parts) == 2) {
$url['?'] = $parts[1];
}
$this->Paginator->options(array(
'url' => $url,
));
More here: http://api.cakephp.org/2.2/class-PaginatorHelper.html
and here: http://book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#PaginatorHelper::options
If you widely use filters and additional url params - make an element which will handle it for you
In my layout-script I wish to create a link, appending [?|&]lang=en to the current url, using the url view helper. So, I want this to happen:
http://localhost/user/edit/1 => http://localhost/user/edit/1?lang=en
http://localhost/index?page=2 => http://localhost/index?page=2&lang=en
I have tried the solution suggested Zend Framework: Append query strings to current page url, accessing the router directly, but that does work.
My layout-script contains:
English
If the default route is used, it will append /lang/en, but when another route is used, nothing is appended at all.
So, is there any way to do this with in Zend without me having to parse the url?
Edit
Sorry for my faulty explanation. No, I haven't made a custom router. I have just added other routes. My bad. One route that doesn't work is:
$Routes = array(
'user' => array(
'route' => 'admin/user/:mode/:id',
'defaults' => array('controller' => 'admin', 'action' => 'user', 'mode'=>'', 'id' => 0)
)
);
foreach( $Routes as $k=>$v ) {
$route = new Zend_Controller_Router_Route($v['route'], $v['defaults']);
$router->addRoute($k, $route);
}
Upd:
You must add wildcard to your route or define 'lang' parameter explicitly.
'admin/user/:mode/:id/*'
Additionally, according to your comment, you can do something like this:
class controllerplugin extends Zend_Controller_Plugin_Abstract
{
function routeShutdown($request)
{
if($request->getParam('lang', false) {
//store lang
Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('lang', NULL); //check if this will remove lang from wildcard parameters, have no working zf installation here to check.
}
}
}
I'm new to cakephp...and I have a page with a url this:
http://localhost/books/filteredByAuthor/John-Doe
so the controller is ´books´, the action is ´filteredByAuthor´ and ´John-Doe´ is a parameter.. but the url looks ugly so i've added a Route like this:
Router::connect('/author/:name', array( 'controller' => 'books','action' => 'filteredByAuthor'), array('pass'=>array('name'),'name'=>".*"));
and now my link is:
http://localhost/author/John-Doe
the problem is that the view has a paginator and when i change the page (by clicking on the next or prev button).. the paginator won't consider my routing... and will change the url to this
http://localhost/books/filteredByAuthor/John-Doe/page:2
the code on my view is just:
<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
the documentation doesn't say anything about avoiding this and i've spent hours reading the paginators source code and api.. and in the end i just want my links to be something like this: (with the sort and direction included on the url)
http://localhost/author/John-Doe/1/name/asc
Is it possible to do that and how?
hate to answer my own question... but this might save some time to another developper =) (is all about getting good karma)
i found out that you can pass an "options" array to the paginator, and inside that array you can specify the url (an array of: controller, action and parameters) that the paginator will use to create the links.. so you have to write all the possible routes in the routes.php file. Basically there are 3 possibilities:
when the "page" is not defined
For example:
http://localhost/author/John-Doe
the paginator will assume that the it's the first page. The corresponding route would be:
Router::connect('/author/:name', array( 'controller' => 'books','action' => 'filteredByAuthor'),array('pass'=>array('name'),'name'=>'[a-zA-Z\-]+'));
when the "page" is defined
For example:
http://localhost/author/John-Doe/3 (page 3)
The route would be:
Router::connect('/author/:name/:page', array( 'controller' => 'books','action' => 'filteredByAuthor'),array('pass'=>array('name','page'),'name'=>'[a-zA-Z\-]+','page'=>'[0-9]+'));
finally when the page and the sort is defined on the url (by clicking on the sort links created by the paginator).
For example:
http://localhost/author/John-Doe/3/title/desc (John Doe's books ordered desc by title)
The route is:
Router::connect('/author/:name/:page/:sort/:direction', array( 'controller' => 'books','action' => 'filteredByAuthor'),
array('pass'=>array('name','page','sort','direction'),
'name'=>"[a-zA-Z\-]+",
'page'=>'[0-9]*',
'sort'=>'[a-zA-Z\.]+',
'direction'=>'[a-z]+',
));
on the view you have to unset the url created by the paginator, cause you'll specify your own url array on the controller:
Controller:
function filteredByAuthor($name = null,$page = null , $sort = null , $direction = null){
$option_url = array('controller'=>'books','action'=>'filteredByAuthor','name'=>$name);
if($sort){
$this->passedArgs['sort'] = $sort;
$options_url['sort'] = $sort;
}
if($direction){
$this->passedArgs['direction'] = $direction;
$options_url['direction'] = $direction;
}
Send the variable $options_url to the view using set()... so in the view you'll need to do this:
View:
unset($this->Paginator->options['url']);
echo $this->Paginator->prev(__('« Précédente', true), array('url'=>$options_url), null, array('class'=>'disabled'));
echo $this->Paginator->numbers(array('separator'=>'','url'=>$options_url));
echo $this->Paginator->next(__('Suivante »', true), array('url'=>$options_url), null, array('class' => 'disabled'));
Now, on the sort links you'll need to unset the variables 'sort' and 'direction'. We already used them to create the links on the paginator, but if we dont delete them, then the sort() function will use them... and we wont be able to sort =)
$options_sort = $options_url;
unset($options_sort['direction']);
unset($options_sort['sort']);
echo $this->Paginator->sort('Produit <span> </span>', 'title',array('escape'=>false,'url'=>$options_sort));
hope this helps =)