Simple question for Cakephp 2.0.
I want to set a routing rule such that:
www.abc.com/z/abc123
will resolve to the full URL of (including the URL parameter)
www.abc.com/bookings/bookingref/?ref=abc123
Where bookings is the Controller, and bookingref is the action.
Can someone teach me what I need to write in the routes.php?
Kevin
In routes.php:
Router::connect('/bookingref/', array('controller' => 'bookings', 'action' => 'bookingref'));
In controller:
public function bookingref(){
}
So you should have a view name after your function. i.e. bookingref.ctp
This is how I would implement your solution:
In Config/routes.php add:
Router::connect('/z/:reference',
['controller' => 'bookings', 'action' => 'bookingref'],
[
'pass' => ['reference'],// Passed to corresponding function argument (order matters if 2 or more)
'reference' => '[a-z0-9]+'// RegExp validation if you need it
]
);
In your BookingsController use:
public function bookingref($reference = null)
{
...
}
Unfortunately, Router::redirect() cannot redirect to string based URLs that include variables. The controller based approach Progredi mentioned is your best bet.
Related
In my CakePHP 3 application, after a controller redirect I get this error:
Error: [LogicException] Controller action can only return an instance of Response
Request URL: /mycontroller/
Stack Trace:
#0 /var/www/vhosts/example.com/httpdocs/vendor/cakephp/cakephp/src/Routing/Dispatcher.php(87): Cake\Routing\Dispatcher->_invoke(Object(App\Controller\SigninsController))
#1 /var/www/vhosts/example.com/httpdocs/webroot/index.php(37): Cake\Routing\Dispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response))
#2 {main}
Regarding to CakePHP 2 controller documentation redirect was like this:
$this->redirect('/orders/thanks');
$this->redirect('http://www.example.com');
return $this->redirect(
array('controller' => 'orders', 'action' => 'confirm')
);
But in CakePHP 3 documentation it seems like this:
return $this->redirect('/orders/thanks');
return $this->redirect('http://www.example.com');
return $this->redirect(
['controller' => 'Orders', 'action' => 'thanks']
);
When I add return word before $this->redirect, error is solved. So does this makes problem ? Because I couldn't see a return redirect part in cakephp 3 migration guide. Migration guide only mentions that third parameter is dropped.
Return in CakePHP 3 application is used when you want to redirect to other pages or we can say actions/methods of other controllers or even if you want to redirect to 3rd Party Links like you have specified :-
return $this->redirect('/orders/thanks');
return $this->redirect('http://www.example.com');
return $this->redirect(['controller' => 'Orders', 'action' => 'thanks']);
And if you want to redirect to other method in the same controller then you can leave the return and use setAction as below but here URL will remain the same.
$this->setAction('thanks');
Return is better approach and URL will redirect if you use below code.
return $this->redirect(['action' => 'thanks']);
Take a look at this
Response provides an interface to wrap the common response-related tasks such as:
Sending headers for redirects.
and this
You should return the response instance from your action to prevent view rendering and let the dispatcher handle actual redirection.
if you are using route name then use this-
$this->redirect(['_name' => 'view-details']);
you are using route then use this-
$this->redirect('/page/view-details');
and last option is this
$this->redirect(['controller' => 'Pages', 'action' => 'view']);
----------------------------------------------------------------------
if you are use route name in view file then this use-
use Cake\Routing\Router;
echo Router::url(['_name' => 'view-details']);
echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);
In cakephp, 3.6 to go to specific view/page Use $this->render('filename');
like below
public function search()
{
$this->render();
$this->render('profile');
}
You need to turn off Autorendering
since cakephp methods by default want to end with a redirect to a CTP file
use $this->autoRender = false
inside you function
I have two controllers: ArtistsController and RecordsController
I want to order routes logically depending on what the user is doing.
In this case once the user is editing an Artist (/artists/edit/some-artist) he's able to add some records for that artist.
So, I'd like the route to be something like:
"/artists/edit/some/artist/records/add"
And the same thing with the editing function of a record:
"/artists/edit/some-artist/records/edit/some-record"
I've been fighting with it for a while but I've never worked with Routes before on CakePHP and can't find a solution for this. Is this possible? Thanks
In Config/routes.php
Router::connect('/artists/edit/:some_artist', array('controller' => 'artists', 'action' => 'edit'), array('pass' => array('some_artist')));
Router::connect('/artists/edit/:some_artist/:records', array('controller' => 'artists', 'action' => 'edit'), array('pass' => array('some_artist','records')));
and you go on depending how what parameters you want to pass.
rule is simple: is some variable needs to be passed you put colon ":" before it, and add its name in array 'pass'.
I suggest read Routing: Route elements if you want specify type of passing element.
Additionally Artists Controller function should like this
public function edit($some_artist=null,$records = null) {
/**
[...]
*/
}
have custom pagination in my cakephp view. before that i made some custom routing changes.
problem is that links leads to pages like
http://localhost/myapp/foos/view/news/page:2
instead of
http://localhost/myapp/news/page:2
so, part with foos/view/ not have to be part of the link.
tried to change url with several custom options, like
$this->Paginator->options(array('url' => $this->passedArgs));
but no luck, because i always have foos/view/ in url.
can you help me how can i get rid of that foos/view?
thank you very much in advance!
UPDATE: i manage to do "something", but not enough, by adding following lines:
$options = array('url'=> array('controller' => 'news' ) );
$paginator->options($options);
now, my link looks like:
http://localhost/myapp/news/index/page:2
how can i get rid of that "index" in url?
The following line is more about passing various pieces of URL information to the view:
$this->Paginator->options(array('url' => $this->passedArgs));
I think what you want to look into is the helper declaration in your Controller:
var $helpers = (
'SomeHelper',
'AnotherHelper',
'Paginator' => array(
'url' => array('controller'=>'news')
)
);
If you want finer control of a custom route like the one you have then try
'url' => '/news'
I haven't used PaginatorHelper in a while - so I could be egregiously on the wrong track - but I believe that's a good start.
Also, take a look at the Paginator Helper page for where it mentions $options and then take a look at Router::url() as the former page recommends.
I had a case where I am working on a project using CakePHP 2.1 (This thread is tagged as 1.3) with a dynamic admin route to display pages like this:
Router::connect('/admin/main/*', array('controller' => 'adminPages', 'action' => 'display'));
With a query string parameter, that produces a dynamic url like this: http://mydomain.com/adminPages/main/...?page=1
The link route, was incorrect for our needs and found I could alter the url directly by using this:
$this->Paginator->options(array(
'url' => array(
'controller' => 'admin/main/my-display',
)
));
For me it made a link: http://mydomain.com/admin/main/my-display?page=1 - which was the correct url we were looking for. If I used a string, as described above, it appends itself to the url, like: http://mydomain.com/adminPages/main/.../admin/main/my-display?page=1
In view :
<?php
$this->Paginator->options(array('url' => array('controller' => '','action' =>'your-custom-url')));
?>
In routes.php :
<?php
Router::connect('/your-custom-url/*', array('controller' => 'Controller', 'action' => 'function'));
?>
I need to create routes that include a colon to produce URLs like http://app.com/prjct:a9b5c. Obviously it's currently simple to use a slash instead with the default routing.
$SLUG = array('slug' => '[-_A-Za-z0-9]+');
Router::connect('/prjct/:slug', array('controller' => 'projects', 'action' => 'show'), $SLUG);
But routes specifications use the colon character as a special indicator, which interferes with my naive attempt to replace the second slash above with another colon.
How do I use colons in this case for a route?
You can use named parameter as explained in CakePHP Cookbook. Write code below in your app/config/routes.php:
// Parse only the 'prjct' parameter if the current action is 'show' and the controller is 'projects'.
Router::connectNamed(array('prjct' => array('action' => 'show', 'controller' => 'projects')));
// Then set default route to controller 'projects' and action 'show
Router::connect('/', array('controller' => 'projects', 'action' => 'show'));
In your projects_controller.php :
function show(prjct = null) {
// Check if prjct match the pattern
$pattern = '[-_A-Za-z0-9]+';
if(!preg_match($pattern, prjct)){
// Redirect somewhere else
}
// Rest of your code here
}
I think this is indeed out of scope for simple routes. I see two options:
Use a custom route parsing class, as described here. There isn't a whole lot of documentation on the topic, but you can extend the existing class and play around with it to get a hang of what it's doing. Then customize it to your needs.
class MyRoute extends CakeRoute {
public function parse($url) {
debug($url); // input
$route = parent::parse($url);
debug($route); // output
return $route;
}
}
Route these URLs with a catch-all route to a controller, where the parameter will be available as a named parameter in $this->params['named']. Do what you need to do there.
What's the cleanest way to add a prefix to every URL in CakePHP, like a language parameter?
http://example.com/en/controller/action
http://example.com/ru/admin/controller/action
It needs to work with "real" prefixes like admin, and ideally the bare URL /controller/action could be redirected to /DEFAULT-LANGUAGE/controller/action.
It's working in a retro-fitted application for me now, but it was kind of a hack, and I need to include the language parameter by hand in most links, which is not good.
So the question is twofold:
What's the best way to structure Routes, so the language parameter is implicitly included by default without having to be specified for each newly defined Route?
Router::connect('/:controller/:action/*', ...) should implicitly include the prefix.
The parameter should be available in $this->params['lang'] or somewhere similar to be evaluated in AppController::beforeFilter().
How to get Router::url() to automatically include the prefix in the URL, if not explicitly specified?
Router::url(array('controller' => 'foo', 'action' => 'bar')) should return /en/foo/bar
Since Controller::redirect(), Form::create() or even Router::url() directly need to have the same behavior, overriding every single function is not really an option. Html::image() for instance should produce a prefix-less URL though.
The following methods seem to call Router::url.
Controller::redirect
Controller::flash
Dispatcher::__extractParams via Object::requestAction
Helper::url
JsHelper::load_
JsHelper::redirect_
View::uuid, but only for a hash generation
Out of those it seems the Controller and Helper methods would need to be overridden, I could live without the JsHelper. My idea would be to write a general function in AppController or maybe just in bootstrap.php to handle the parameter insertion. The overridden Controller and Helper methods would use this function, as would I if I wanted to manually call Router::url. Would this be sufficient?
This is essentially all the code I implemented to solve this problem in the end (at least I think that's all ;-)):
/config/bootstrap.php
define('DEFAULT_LANGUAGE', 'jpn');
if (!function_exists('router_url_language')) {
function router_url_language($url) {
if ($lang = Configure::read('Config.language')) {
if (is_array($url)) {
if (!isset($url['language'])) {
$url['language'] = $lang;
}
if ($url['language'] == DEFAULT_LANGUAGE) {
unset($url['language']);
}
} else if ($url == '/' && $lang !== DEFAULT_LANGUAGE) {
$url.= $lang;
}
}
return $url;
}
}
/config/core.php
Configure::write('Config.language', 'jpn');
/app_helper.php
class AppHelper extends Helper {
public function url($url = null, $full = false) {
return parent::url(router_url_language($url), $full);
}
}
/app_controller.php
class AppController extends Controller {
public function beforeFilter() {
if (isset($this->params['language'])) {
Configure::write('Config.language', $this->params['language']);
}
}
public function redirect($url, $status = null, $exit = true) {
parent::redirect(router_url_language($url), $status, $exit);
}
public function flash($message, $url, $pause = 1) {
parent::flash($message, router_url_language($url), $pause);
}
}
/config/routes.php
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
Router::connect('/:language/', array('controller' => 'pages', 'action' => 'display', 'home'), array('language' => '[a-z]{3}'));
Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), array('language' => '[a-z]{3}'));
Router::connect('/:language/:controller/:action/*', array(), array('language' => '[a-z]{3}'));
This allows default URLs like /controller/action to use the default language (JPN in my case), and URLs like /eng/controller/action to use an alternative language. This logic can be changed pretty easily in the router_url_language() function.
For this to work I also need to define two routes for each route, one containing the /:language/ parameter and one without. At least I couldn't figure out how to do it another way.
rchavik from IRC suggested this link: CakePHP URL based language switching for i18n and l10n internationalization and localization
In general, it seems that overriding Helper::url might be the solution.
An easier way might be to store the chosen language in a cookie and then not have to rewrite all the URLs. You could also potentially detect the user's browser language automatically.
However, search engines would be unlikely to pickup the various languages and you'd also lose the language if someone tried to share the link.
But love the full solution you posted, very comprehensive, thanks. :-)