Only change the extension of an url, keep query-string - cakephp

I have a search form, that uses get-parameters to determine what is searched and I want to have the search results as rss-feed.
So I'm using the route rss-extension to have those available and want to generate a link to the rss feed for that search/query.
$this->Html->link(__("Search results as rss"), ['ext' => 'rss']); leaves out all the params and I haven't found a way to extract the get-params in a sane way.
Is there some shortcut to just use the actual current url and change the extension?
The best way I found so far was:
$this->Html->link(__("Search results"), ['ext' => 'rss', '?' => $this->passedArgs]);
Is there a better way?

Yeah, you might want to use
'?' => $this->request->query
Then it only uses the query strings - which is what you want after all.

Below is the code I use, dont know if $this->link work the same way:
$url = $this->params['url'];
echo $this->Form->create(null, array(
'url' => array(
'action' => 'yourAction',
'?' => $url,
'ext' => 'rss'
)
));
echo $this->Form->end('Search Results');

Related

Filtering parameters in CakePHP

In Rails, we can specify the allowed parameters to be used in the controller when saving data. So, with params being the submitted data, I can do this:
params.require(:person).permit(:name, :age)
Which will ensure that the :person key is present and will filter out anything that is not a person's :name or :age.
Is there any way in CakePHP to accomplish this?
EDIT: I know I can write PHP, I want to know if there's a Cake component / plugin that already does this.
Something in this PHP way:
// submited data
$this->request->data['Person'] = array(
'name' => 'Salines',
'age' => '41',
'job' => 'Web Developer'
);
// check if isset and filter out anything that is not a person's name or age
if(isset($this->request->data['Person']))
{
$permit = array('name' => '','age' => '');
$this->request->data['Person'] = array_intersect_key($this->request->data['Person'],$permit);
}
//and return $this->request->data like
array(
'Person' => array(
'name' => 'Salines',
'age' => '41'
)
);
I'm looking for a Cake-provided solution (if there is one)
Well, define "cake-provided", you mean by the framework itself? No, the core doesn't have this functionality but there are two plugins.
For Cake3: Plum Search
For Cake2 & 3: CakeDC Search
For Cake3 I would go for Plum-Search, it is written by the same person as the initial code of the other plugin but a complete rewrite and makes a better use of Cake3.
Next time you ask name your exact Cake version.
Both plugins implement the PRG pattern but don't explicitly allow or deny query parameters. They'll only grab the parameters you specified in your filter declaration and turn them into the request. Validate and save to exclude unwanted fields.
Make a url link like this
echo $this->Html->url(array('controller'=>'users','action'=>'hello','par1'=>23,'par2'=>'sud'));
In hello function in users controller
pr($this->params->named['par1']);
pr($this->params->named['par2']);

CakePHP set redirect parameters using an array

I am writing some simple redirects in CakePHP 2.4.2 and came across one that stumped me a bit.
How can I redirect to another view with the same passedArgs? It seems like it should be simple, but I must be overlooking something. I tried this:
$this->redirect(array_merge(array('action' => 'index',$this->params['named'])));
The debug output seems correct:
array(
'action' => 'index',
(int) 0 => array(
'this' => 'url',
'and' => 'stuff'
)
)
My desired outcome is that
view/this:url/and:stuff
redirects to
index/this:url/and:stuff
but now it just sends me to
index/
Not sure what I am missing here, perhaps I have deeper configuration issues - although it's not a terribly complicated app.
For passed params (numeric keys) use array_merge.
But since you use named params, which have a string based key, you can leverage PHP basics:
$this->redirect(array('action' => 'index') + $this->request->params['named']));
This adds all array values from the named params except for action, which is already in use here (and hence should not be overwritten anyway). So the priority is clear, as well.
Cake expects a flat array of parameters, so you need to use array_merge to add in extra arrays to it on the sides. Try this:
$this->redirect(array_merge(array('action' => 'index'), $this->params['named']));
... or using your original variable $passedArgs:
$this->redirect(array_merge(array('action' => 'index'), $this->passedArgs));
Maybe better solution will be used persist attribute in Router::connect()?

Cakephp change the order of virtualFieldId in find/paginate

I have a model in which I have defined a virtualfield, virtualfield01. And when I call a find function like this.
$this->myModel->find('all', array(
'fields' => array(
'field01',
'virtualfield01',
'field02',
'field03')));
the result always gives me.
myModel=>array(
'field01' => 'value01'
'field02' => 'value02'
'field03' => 'value03'
'virtualfield01' => 'virtualvalue01')
the virtualfield is always output as the last field of the result.
How can I make the order exactly the same to that I make in the find function???
Why wouldn't you just do something like the following in your view, just as #mark mentioned?
$this->Html->tableCells(array(
$var['Model']['field01'],
$var['Model']['virtualfield01'],
$var['Model']['field02'],
$var['Model']['field03'],
));
There's no 're-arrangement action', you're just telling the data how to display, which is why it is a 'view'.
Simple is that as mark Mentioned. Order doesn't matter.

CakePHP Search Tutorial

I am trying to setup a search function that will allow me to search text on 2 fields in my MySQL db.
All the tutorials I have found have either been very old, or look to be too complex just to do a search on a couple of fields and output the results.
Can anyone point me in the direction of a good tutorial or give me any tips to accomplish this search?
With the find() command like Piotr said, you can also use LIKE to find results that are not exactly the text you entered.
$results = $this->Model->find('all', array('conditions' => array(
'Model.field1 LIKE' => '%entered value%',
'Model.field2 LIKE' => '%entered value%')));
This way when you search for "apple" you will also find "apple pie".
Use a find() command.
If you want to find a specific text in two fields, you just have to do something like this:
$results = $this->Model->find('all', array('conditions' => array(
'Model.field1' => 'expected value',
'Model.field2' => 'expected value')));
Function "Find" : http://book.cakephp.org/view/1018/find
Also videos in french : http://www.grafikart.fr/tutoriels/cakephp

CakePhp Router:connect, I don't get the syntax

I am trying to connect the next urls:
1) /food/tips
2) /happiness/tips/best_tips
To the following objects:
1) controller=tips / action=index / passed_parameters=food
2) controller=tips / action=index / passed_parameters=(happiness,best_tips)
--edit--
These routes are not fixed.
Meaning: what I try to do is to route every url that have tips as action, to the tips controller, to any fixed(index is good enough) action, and chaining the rest of the url as it was in the original call.
Something like /any_controller/tips/any_param to /tips/index/any_params
-- end edit --
Hope that now there is some sense.
How should it be done?
(please - also explain)
Thanks
the routing is all done through the call Router::connect('thing to catch', 'where to send it');
so it can be as simple as:
Router::connect('/food/tips', '/tips/index/food');
or the preferred method (using cakes built in url builder)
Router::connect('/food/tips/*', array('controller' => 'tips', 'action' => 'index', 'food');
The first method takes a string argument and passes it to another string which would be a url and you would then have to catch it in your controller, and expect a passed parameter through the url.
The second method uses cakes built in url former which takes an array with keys controller and action (there are other options: http://api.cakephp.org/class/router#method-Routerurl)
The second is preferred due to proper formatting and future flexibility (I believe).
any passed parameters in the second method are just passed as un-named items in the array. named parameters are just passed as keyed elements. So if I wanted to create a URL like this
/posts/index/find:all/page:2
I would write the url like this:
Router::connect('/url_to_catch', array('controller' => 'posts', 'action' => 'index', 'find' => 'all', 'page' => 2);
So just to finish up, I would actually pass your parameter through as named:
Router::connect('/happiness/tips/best_tips', array('controller' => 'tips', 'action' => 'index', 'items' => array('happiness', 'best_tips'));
which would need a function in your tips controller that looks like this:
function tips(){ $this->passedArgs['items']; }
I would recommend reading the chapter on Routing the the book, as it will explain things better than I can and it seems counter productive to paste it here.
http://book.cakephp.org/#!/view/948/Defining-Routes
For the sake of explanation I will try,
Router::connect('/food/tips', array('controller' => 'tips', 'action' => 'index', 'food'));
Router::connect('/happiness/tips/best_tips', array('controller' => 'tips', 'action' => 'index', 'happiness','best_tips'));
This should get things working for you. What you are essentially doing is telling the Cake Routing what url you want it to capture, as it will be doing this using Regex. Then you want to tell it which code you want it to run. So this takes a Controller and Action pair, as a set of things to do.
You also want to pass through your named paremeters afterwards. These will tack onto the function in your controller so that you can do stuff with them.
It's quite easy, just check the Router configuration in the manual. You have to use the connect method from the Router class. This accepts 2 parameters. First your desired routed (e.g. food/tips) and second an array with the actual path it should follow. So for your examples you'd do something like this:
Router::connect('/food/tips', array('controller' => 'tips', 'action' => 'index', 'food');
Router::connect('/happiness/tips/best_tips', array('controller' => 'tips', 'action' => 'index', 'happiness', 'best_tips');
This is equivalent to calling TipsController->index('food') and TipsController('happiness', 'best_tips) respectively.
However, your routes look a bit funny. The Cake convention for routes is /controller/action/param1/param2/etc where the parameters param1 etc. are optional and the index action is assumed when no other action is given.
You're taking a different approach and I would suggest (if you can) change it to the Cake conventional routes, as this will save you a lot of work later on because Cake will automatically connect these routes to the desired methods.
So my suggestion is going for tips/food and tips/happiness/best_tips instead of the routes you suggest. This way, you don't have to do any router configuration.
UPDATE
After you're edit, I think it's best to try something with defining custom routes. I can't test this for you at the moment, so you should do some testing yourself, but in that case it would be something like:
Router::connect('/:section/tips/:param',
array('action' => 'index'),
array(
'section' => '[a-z]*',
'param' => '[a-z]*'
)
);
UPDATE2
Sorry, I've tested the above and it doesn't seem to work.

Resources