How do I do a simple route in CakePHP?
I need that each and every URL will be routed by swapping the action and the controller.
I just couldn't understand the placeholders syntax.
Example:
/files/read/3
to
/read/files/3
-- supplemental --
In my application I use aliases for the controllers.
and I want to route every url that have a certain keyword, as an action, to a certain controller.
I also want to provide the original controller name as a parameter.
Here is a 1:1 example:
There are to alises: fruits and streets.
The keyword that I want to catch in the action is find.
The new controller name is finder.
The following calls match my condition:
/fruits/find/apple/red and /streets/find/longer
The router should catch these urls and convert them, to:
/finder/fruits/apple/red(or supply the parameters in other way, I don't mind) and /finder/streets/longer
How should it be done?
Here is the line of code that you need to put in /app/config/routes.php:
Router::connect('/:action/:controller/*', array('controller' => ':controller', 'action' => ':action'));
Know more: As you can see from the CakePHP book, there are some 'reserved' patterns for routing configuration. An example would be what I used in the line above: :action and :controller. These patterns allow you to tweak routes extensively.
Beware: changing the order of controller and actions in urls might have unintended consequences in the functionality of other CakePHP features. I haven't tested thoroughly, but this is just a general warning.
Beware: Also, I noticed that you put in your example: /files/read/3. Maybe this was just some dummy example, but if you indeed plan to have an MVC named as 'file', be advised that it will conflict will CakePHP core classes (e.g. File model will conflict with File class).
Anyway, hope this answer helps you well. And I really like how the change of controller and action names make the url more readable. :D
Related
I am new to Drupal(7) and hence need some help for following situations.
I have created one Webform(I have other webform too) and now instead of inserting in default webform_submitted_data table, I want for this webfrom to insert into myTable. From what I found, I need to write a hook for this. Actually I am getting confused for way to write this hook. I have below questions.
Where to write this hook (in which file).
How to write this hook only for one webform.
Please help and let me know if you need any more information for this.
First, be very sure before you start twisting Drupal's arm into making things work differently then they are supposed to. Rerouting the data for a Webform could potentially provide hiccups in how Webform works and this could bite you later. It may still expect the data to be saved in its own bookkeeping tables, but fail to find it there later if you overwrite its behavior.
That being said, if you wish to alter the behavior of other modules, such as Webform, you will have to write your own, tiny module. Some of these hooks can also be influenced via the templating layer (using your templates template.php file), but this is the wrong place to alter this kind of behavior in my opinion.
A Drupal 7 module is basically comprised out of a minimal of two files, a *.info file and a *.module file. The former contains some meta data necessary for Drupal to categorize your module and calculate possible dependencies. The latter contains the actual PHP code.
These files have to be saved in a directory with (preferably) the same name as you named your info and module file. For Drupal to find your module, you can place it under sites/all/modules.
If, for example, you name your module changemyform, these are the minimal required files:
changemyform.info
changemyform.module
And both should reside in: sites/all/modules/changemyform.
I suggest you check Drupal's developer's manual for a more detailed explanation about writing modules, including licensing, unit testing, ... . But for this example, the mentioned two files will do.
In your info file you have to at least write the name for the module, a small description, for which core version it is applicable and which dependencies it has. Something like this would suffice for our example:
name = Change my form
description = Changes the submission behavior of my form.
core = 7.x
dependencies[] = webform
Next we should write the logic for the module file itself. The general hook for intercepting any form submission (including a Webform) is:
function mymodule_form_alter( &$form, &$form_state,$form_id ){
...
}
With this hook you can, as the name suggests, alter all the forms rendered with Drupal. Not only the submission handler, but add/remove fields, add markup, ... . Replace mymodule with the actual name of your module, in our example case changemyform. Next you need to scope it down to only effect your desired form:
function changemyform_form_alter( &$form, &$form_state,$form_id ){
if ($form_id == 'my_desired_webform_form_id') {
$form['#submit'][] = 'changemyform_submit_handler';
}
}
Notice that I now replace mymodule with changemyform. As you can also see I have added a custom handler to the form's submit property. You will have to write this handler as a function which then will contain all the logic you desire. Thus the total module file now becomes (minus the <?php ?> tags):
function changemyform_form_alter( &$form, &$form_state,$form_id ){
if ($form_id == 'my_desired_webform_form_id') {
$form['#submit'][] = 'changemyform_submit_handler';
}
}
function changemyform_submit_handler($form, &$form_state) {
... your submission logic ...
}
Now you are ready to write all the logic you need to capture the data on submit and do as you please.
Since this is a module, you should, of course, enable it in your administration modules overview screen for it to function.
Also (as a nitpick) when writing your own modules, do decorate each function with documentation headers that describe what each function does and what each parameter could hold. Even for tiny, trivial functions.
You can use hook_webform_submission_insert().
function MYMODULE_webform_submission_insert($node, $submission) {
// Insert a record into a 3rd-party module table when a submission is added.
db_insert('mymodule_table')
->fields(array(
'nid' => $node->nid,
'sid' => $submission->sid,
'foo' => 'foo_data',
))
->execute();
}
In Drupal 8, the best way to refer to entity_insert hook -
Write this hook in MODULE_NAME.module file of your module folder
function MODULE_NAME_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
if($entity->getEntityTypeId() == 'webform_submission') {
$result = \Drupal::database()->insert('TABLE_NAME')
->fields([
'nid' => $node->nid,
'sid' => $submission->sid,
'foo' => 'foo_data'
])
->execute();
}
}
I defined a configuration parameters in bootstrap, but they are not translated after in use.
$duedates = array(
'0'=> __('none'),
'1'=> __('8 days'),
'2'=> __('10 days'),
'3'=> __('15 days'),
'4'=> __('30 days'),
'5'=> __('45 days'),
'6'=> __('60 days'),
'7'=> __('90 days'),
'8'=> __('120 days'),
) ;
Configure::write('DUEDATES', $duedates);
They aren't trasnlated after using array
Configure::read('DUEDATES');
Where is the problem?
You can not define translatable strings in your bootstrap, as the language/locale is not yet set at that point. The bootstrap is processed before anything else, including the Config/core.php, which is where your language/locale settings should be. You should either:
Define the array at a later point, like in the beforeRender method of your AppController.
Move the language configuration to your bootstrap prior to defining the translatable strings.
Bootstrapping CakePHP
If you have any additional configuration needs, use CakePHP’s
bootstrap file, found in app/Config/bootstrap.php. This file is
executed just after CakePHP’s core bootstrapping.
This file is ideal for a number of common bootstrapping tasks:
Defining convenience functions.
Registering global constants.
Defining additional model, view, and controller paths.
Creating cache configurations.
Configuring inflections.
Loading configuration files.
Be careful to maintain the MVC software design pattern when you add
things to the bootstrap file: it might be tempting to place formatting
functions there in order to use them in your controllers.
Resist the urge. You’ll be glad you did later on down the line.
http://book.cakephp.org/2.0/en/development/configuration.html
It seems wrong to put localized strings into configuration. Their place seems to be in Views part of MVC.
CakePHP’s Configure class can be used to store and retrieve
application or runtime specific values. Be careful, this class allows
you to store anything in it, then use it in any other part of your
code: a sure temptation to break the MVC pattern CakePHP was designed
for. The main goal of Configure class is to keep centralized variables
that can be shared between many objects. Remember to try to live by
“convention over configuration” and you won’t end up breaking the MVC
structure we’ve set in place.
I have a controller with name users_controller, within the login action I want to redirect to my affiliate_redirect_controller.php, now I the following code in the users controller to redirect
$this->redirect(array(
'controller'=>'affiliate_redirect',
'action'=>'logRedirect' ));
And then I get the following error which I can't seem to resolve
Error: The requested address '/affiliate_redirect/logRedirect' was not found on this server.
I honestly do not know what this could be, quite new to cakePHP and none of the solutions found work for me.
the contents of affiliate_redirect_controller.php looks like this
class AffiliateRedirectController extends AppController
{
var $name = 'AffiliateRedirect';
function logRedirect(){
}
}
I can see there is a mistake in your code its because of naming convention.
$this->redirect(array(
'controller'=>'affiliate_redirects',
'action'=>'logRedirect' ));
Please see the above changes when you are writing your controller name in lowercase like above it should be plural affiliate_redirects and should not be affiliate_redirect
Apart from this you can use directly redirect as like this also.
$this->redirect('affiliate_redirects/logRedirect');
Please try, it should work.
Do you have a table in your database that corresponds to affiliate redirect controller?
You might want to rethink your logic, and use CakePHP routes to set the URL to what you want. Having a controller named affiliate_redirect_controller doesn't follow CakePHP's naming conventions.
Since I don't know exactly what you're trying to do, I don't know if this will work for you, but maybe consider redirecting to a separate action in UsersController like /users/affiliate_redirect/
Or you can create an AffiliatesController and then redirect to /affiliates/redirect/
Also, if you don't have debug mode set to 2, you should do that. It may help reveal what the actual issue is.
What debug level do you have in app/config/core.php ? Most of the time, when you get the message
Error: The requested address '/controller/action' was not found on this server.
it means you have a debug level set to 0 and increasing it to 1 or 2 allows to get more details about the error.
I am rewriting our company website in cakephp, and need to find a way to do the following:
A user enters our site by using one
of the promotional alias URLS that
has been pregenerated for a specific
media advert ( magazine, web
promotion etc )
The URL is checked against a
database of alias URLs, and if an
alias exists, then a specific
tracking code is written into the
session.
I have considered several options, none of which seem suitable for this purpose. They are:
Putting the lookup script in the
beforeFilter() in appcontroller, so
that its included in every
controller. (Writes a session value
so it only perfoms once.)
This option only works for existing contollers, and gives the
Cake 'missing controller' error if a
URL doesn't exist.
Specific routes for each alias in
Routes.php - Works but there are
potentially hundreds of alias urls
added/removed regularly via admin
interface.
Route all site URLs to their own
actions, and having an 'everything
else' rule, for the alias URLs that
maps to my lookup script. - Messy
and I lose the built in Cake
routing.
Custom 404. - I don't want to
return 404's for these urls, as I
feel its bad practice unless they
really don't map to anything.
I really could do with a place in the application flow where I can put this lookup/tracking script, and I'm fairly new to cake so I'm stumped.
EDIT: Also, I know that a subfolder called say 'promo' would easily do this, but I have a lot of legacy URLS from our old site, that need handling too.
Note: I'm making an assumption that your promo URLs are in the form of "domain.com/advert-259" or something like that (i.e. no "domain.com/adverts/advert-259'). That would be just too simple :)
Hopefully, you can use the routing with some regex. Add this to your /config/routes.php and let me know if a different regex will help :)
$controllers = Configure::listObjects('controller');
foreach ($controllers as &$value)
{
$value = Inflector::underscore($value);
}
Router::connect('/:promo', array('controller' => 'promos', 'action' => 'process'), array('promo' => '(?!('.implode('|', $controllers).')\W+)[a-zA-Z\-_]+/?$'));
Now you can handle all your promo codes in PromosController::process().
Basically, it checks for a promo code in url, excluding those in the $controllers array (i.e. your regular routes won't be messed up).
Later on you might want to consider caching the value of Configure::listObjects() depending on the speed of your app and your requirements.
A very interesting question. I think I would use item #3. It's not really that messy -- after all, this typically is handled by the pages controller in my stuff. That's how I'd handle it - hardcode your routes to your controllers in routes.php, then have a matchall route that will work for your promo codes. This allows you to keep legacy URLs, as well as use a lot of the standard cake stuff (you probably will just have to explicitly state each of your controllers routes, not such a chore...) Additionally, it will let you do some cool stuff with 404 errors -- you can put some logic in there to try and figure out where they were trying to go, so you can superpower your 404's.
How does cakephp handle a get request? For instance, how would it handle a request like this...
http://us.mc01g.mail.yahoo.com/mc/welcome?.gx=1&.rand=9553121_pg=showFolder&fid=Inbox&order=down&tt=1732&pSize=20&.rand=425311406&.jsrand=3
Would "mc" be the controller and "welcome" be the action?
How is the rest of the information handled?
Also note that you could use named parameters as of Cake 1.2. Named parameters are in key:value order, so the url http://somesite.com/controller/action/key1:value1/key2:value2 would give a a $this->params['named'] array( 'key1' => 'value1', 'key2' => 'value2' ) from within any controller.
If you use a CNN.com style GET request (http://www.cnn.com/2009/SHOWBIZ/books/04/27/ayn.rand.atlas.shrugged/index.html), the parameters are in order of appearance (2009, SHOWBIZ, books, etc.) in the $this->params['pass'] array, indexed starting at 0.
I strongly recommend named paramters, as you can later add features by passing get params, without having to worry about the order. I believe you can also change the named parameter separation key (by default, it's ':').
So it's a slightly different paradigm than the "traditional" GET parameters (page.php?key1=value1&key2=value2). However, you could easily add some logic in the application to automatically parse traditional parameters into an array by tying into how the application parses requests.
CakePHP uses routes to determine this. By default, the routes work as you described. The remainder after the '?' is the querystring and it can be found in $this->params['url'] in the controller, parsed into an associative array.
Since I found this while searching for it, even though it's a little old.
$this->params['url']
holds GET information.
I have tested but it does work. The page in the Cakephp book for it is this link under the 'url' section. It even gives an example very similar to the one in the original question here. This also works in CakePHP 1.3 which is what I'm running.
It doesn't really use the get in the typical since.
if it was passed that long crazy string, nothing would happen. It expects data in this format: site.com/controller/action/var1/var2/var....
Can someone clarify the correct answer? It appears to me that spoulson's and SeanDowney's statements are contradicting each other?
Would someone be able to use the newest version of CakePHP and get the following url to work:
http://www.domain.com/index.php/oauth/authorize?oauth_version=1.0&oauth_nonce=c255c8fdd41bd3096e0c3bf0172b7b5a&oauth_timestamp=1249169700&oauth_consumer_key=8a001709e6552888230f88013f23d5d004a7445d0&oauth_signature_method=HMAC-SHA1&oauth_signature=0bj5O1M67vCuvpbkXsh7CqMOzD0%3D
oauth being the controller and authorize being a method AS WELL as it being able to accept the GET request at the end?