Cakephp naming convention contradiction? - php

I don't understand the following. In the Book, they says:
Multiple word controllers can be any ‘inflected’ form which equals the controller name so:
/redApples
/RedApples
/Red_apples
/red_apples
will all resolve to the index of the RedApples controller. However, the convention is that your URLs are lowercase and underscored, therefore /red_apples/go_pick is the correct form to access the RedApplesController::go_pick action.
But if I write this on add.ctp view
echo $this->Html->link('Add Red Apples',
array('controller' => 'RedApples', 'action' => 'add'),
array('class' => 'button'));
it's create this html output:
www.site.com/RedApples/add
So, The correct way to access RedApplesController::add is /red_apples/add, but CakePHP html helper creates links like /RedApples/add? Which is the correct way to write my own links?
Thank you.

I'm confused as to what the issue is.
it says that you CAN use any form
you use a form other than the recommended
it displays the form you chose
What's the problem? The fact that it gives you a convention (but says it will accept non-conventional as well) and you've decided against using the convention doesn't equate to a problem IMO.
Maybe I'm misunderstanding the real question?
Which is the correct way to write my own links?
The "correct" way is the way you copy/pasted from the book where it almost literally says "the correct way is..."
However, the convention is that your URLs are lowercase and
underscored, therefore /red_apples/go_pick is the correct form to
access the RedApplesController::go_pick action.
If for some unknown reason you must use "RedApples" (a variable you can't change or something?) as your controller name in your link creation, you could wrap it in an inflector:
$myController = 'RedApples'; //unable to change to 'red_apples' for some reason
//...
'controller'=>Inflector::tableize($myController)
//...

Related

How to disable translation of Model validation messages only in cakePHP?

CakePHP will automatically assume that all model validation error messages in your $validate array are intended to be localized. But, I don't want to translate model validation messages. How to achieve this, any suggestion?
The simplest most easiest way would be just not translating those strings. So, if in your .po file
Mistake here -> Error aqui //don't do that
Mistake here -> Mistake here
And your validation errors are "translated" to the same language.
If you just don't want to filter yourself which strings are from validation and which are "normal" strings, change the validation domain of the models (do it in the AppModel so you'll only have to do it once).
class User extends AppModel {
public $validationDomain = 'validation_errors';
}
and now your validation messages will be in the new validation domain and not in default.pot, so you could just not translate the whole "validation_errors.pot" file and you'd be fine.
This part is only really valid for cake 2.5, I can't be sure if it applies to other versions
Now, if you want the really "difficult" way and just erase that functionality from the face of the earth, you'll have to overwrite some functionalities in Cake lib.
I'm not recommending changing the code directly in the the lib Folder, just extending the classes and replacing the in app/lib, otherwise upgrading versions will be a pain.
The class and functions you'll have to modify should be CakeValidationSet in lib/Cake/Model/Validator and the function is _processValidationResponse
All parts that have something like this
__d($this->_validationDomain, $result, $args);
should be replace with a vsprintf($result, $args) or similar (depending on the name of the parameters. This __d function is called 4 times inside that function, so replace all of them.
Personally, I'd just change the validation domain, wouldn't translate the file, and be done with it. Searching the code that translated this messages was really not worth the effort (except, you know, just to know how it's done).

Laravel 4.1 - Advice on where to put some custom config stuff

I am working on a small application with Laravel 4.1. I created an app/acme folder to contain most of my app specific code. I have a service provider named app/acme/AcmeServiceProvider.php where I am setting IoC bindings, Custom View templates and some Config variables.
My Custom Service Provider
...
View::addLocation(app('path').'/OneTimeNote/Views');
/* #TODO - Maybe a better place to put this would be in the app/config folder? */
Config::set('EXTERNAL_SITE_URL', 'http://www.example.com/#/');
/* #TODO - Probably could find a better spot for this, possibly in a lang folder? */
Config::set('EMAIL_SUBJECT', 'The note you created has been read and destroyed.');
...
I think having my custom View location in my service provider makes sense but what about the two entries below it?
The first Config is setting a value I can retrieve from my Controller so that I can build an external URL.
The second Config is setting a value I can use for an e-mail subject I'm sending the user. I thought about just hardcoding this value, but I wanted to put configurable text like this in one place for easy customization. I'd also like to utilize multiple languages in the future, so having some sort of 'lang' directory with different languages could be an answer I suppose?
My question: Is there a better place to put these two config statements rather than my Service Provider? Maybe they shouldn't be added to the Config at all but somewhere else? need advice.
Thanks!
Lets try by creating app/config/acme.php
and return array there e.g.
return array(
'EXTERNAL_SITE_URL' => 'SITE_URL',
'EMAIL_SUBJECT' => 'SUBJECt_VALUE'
);
try to access like that config::get('acme.EXTERNAL_SITE_URL'). I hope it should work for you. Please share you experience ....
#Edited: I have tested that is working for me, so should be for you as well :)
#Edited: Language Part
You can add file in app/lang/en/acme.php (e.g. for english)
if there is another language you can add app/lang/it/acme.php (e.g. for italian)
return array(
"abc" => "This is text",
"def" => array(
"sub1" => "this is fist sub message",
"sub2" => "this is on sencond number",
)
);
then you can get like App::setLocale('en');
echo Lang::get('acme.abc'); //output: This is text
echo Lang::get('acme.def.sub1'); //output: this is fist sub message

CakePHP controller alias

I know there are a couple of other topics about this subject, but non of them seems to fit my needs.
What I have
example.com/log/
LogsController.php
I have LogsController instead of LogController (plural) because CakePHP wants you to have controllers in plural.
But as you might know/notice, example.com/log/ will never use LogsController because of the missing 's' in the url.
Now, I want to have /log/* being redirected to /logs/*. Works perfectly fine with the following code:
Router::connect ('/log/*', array('controller'=>'logs'));
But, when I try to access example.com/log/actions/foo/bar it doesn't seem to work. So after some Googeling I found this:
Router::connect ('/log/:action/*', array('controller'=>'logs'));
Works great. But now when I'm trying to access example.com/log/ again, it says
Error: LogController could not be found.
Question
So my question is, how do I set up an alias for my url so that /log/ will use LogsController instead of trying to use LogController.
I have a few more Controllers where I'd like to change this, like flight => FlightsController, profile => ProfilesController.
Have a look at this question. It is about the same subject, but slightly different. It might help you in some way.
Ok, with the help of some other people on IRC and stuff like that. I found out the following.
A combination of
Router::connect('/flight/:action/*', array('controller'=>'flights'));
Router::connect('/flight/*', array('controller'=>'flights'));
does the trick. I tried this before, but in a other order, like so:
Router::connect('/flight/*', array('controller'=>'flights'));
Router::connect('/flight/:action/*', array('controller'=>'flights'));
which doesn't work.
So the first 2 lines of code in this post solved it for me. Another guy told me that the solution of Arun Jain isn't a proper solution, because it changes the nameconventions in the core as well. Which will cause problems with the FormsHelper and classes like that. So I think I will prefer the code in this post since this is just an alias instead of a core changing piece of script. Thanks for the help anyway.
To do this with routing the correct approach is as follows.
Router::connect('/flight', array('controller'=>'flights','action'=>'index'));
Router::connect('/flight/:action/*', array('controller'=>'flights'));
This tells the router that when an action is found in the URL to use it, but it no params are found then to default is to use the index action.
I have a slightly different take on all of this. The plural is more often the more accurate way to go with things but in occassions when the plural is just plain wrong, i add an exception into the Inflector class (/lib/Cake/Utility/Inflector).
In your example I would add log to this list of uninflected words. This means that system wide cake will not append the 's'. You'll have your LogController your views would sit in the Log view folder etc...
EDIT
I've come across a much neater way to do this from within app/config/bootstrap.php
Inflector::rules(
'plural',
array(
'uninflected' => array('log')
)
);
This would add log to the uninflected list without having to alter the files within the Core to allow easier version updating.
You can simply do it using following:
class LogsController extends AppController
{
public $name = 'Log';
..... YOUR REMAINING CODE ......
}
Your router connnect code will remain same. Kindly ask if it not worked for you.

Is it a good idea to allow the router to look up controllers from a database?

In most of the tutorials for PHP MVC design structures, a router class is used to take user input and look up the right controller in order to process that input accurately. The input normally takes the form of a url. For example http://example.com/foo/bar/ would ask the router to find the controller named foo and fire the method bar.
PHP also has an auto-include function which requires a consistent naming system to used for your classes. For example, if I wanted to get an instance of the class Foo, I would need the file to be called Foo.php and inside would be a class called Foo.
Unfortunately, in tandem, these mechanisms place competing demands on the naming system. The url is very 'front facing' and as such, clients will often need it to reflect the content of a particular page. For example, if I have a page that gives directions to a venue, the client may need this page to be at http://example.com/venues/directions/. Later the content may change and the number of venues is reduced to 1 and now the client wishes the url to read http://example.com/venue/directions/. Obviously, this is a very trivial example but I think the need to change urls occasionally is clear.
Since the urls are very tightly connected to the controller classes, a change to a url means the class file name, the class name itself and any instances of that class will all require changing. For more complex systems this seems very time consuming, to me.
What sort of solutions are there to this problem? It seems to me that a directory of sorts will be necessary in which relations between urls and controllers are stored such that any url could be used to call any controller regardless of what either is named. Thus we would have a venues controller and a venues url and when the client requests a change in the url, we just make a change in the directory translating the new "venue" into "venues".
I think the best way to do this would be in a database table but this then requires an extra query for every user request. Is a database the right way to implement a directory? Is a directory even the best way to solve the above problem? Is this problem even a problem in the first place???
Some solutions I have seen to this is to explicitly specify a routing "connection" to a controller/action.
For example, in NiceDog, you can specify routes like
R('venues?/directions')
->controller('VenueController')
->action('directionsAction')
->on('GET');
Allowing a regular expression to match the URL. (The expression above will match venue/directions or venues/directions) I like this method, because it decouples the controller naming scheme from the URL naming scheme.
Another more configuration-based approach would be to have some kind of explicit mapping:
$routes = array(
'venues?' =>
array('controller'=>'VenueController','action'=>'indexAction'),
'venues?/directions' =>
array('controller'=>'VenueController','action'=>'directionsAction')
);
And then a simple dispatch function:
function dispatch($url,$routes) {
foreach ($routes as $pattern=>$map) {
if (preg_match($pattern,$url,$matches)) {
$controller = new $map['controller']();
$action = $map['action'];
call_user_func_array(
array($controller,$action),
array_slice($matches,1)
);
return true;
}
}
throw new Exception('Route not found.');
}
A good way to solve this problem is for the MVC framework to allow you to specify your own routing rules. For example, see URI Routing in the CodeIgniter framework's documentation.
To go along with your example, this would allow you to remap requests for /venues/ to /venue.

How can I change Zend Framework's routing schema to not use key/value pairs?

Rather than using controller/action/key1/value1/key2/value2 as my URL, I'd like to use controller/action/value1/value2. I think I could do this by defining a custom route in my Bootstrap class, but I want my entire application to behave this way, so adding a custom route for each action is out of the question.
Is this possible? If so, how would I then access valueN? I'd like to be able to define the parameters in my action method's signature. e.x.:
// PostsController.php
public function view($postID) {
echo 'post ID: ' . $postID;
}
I'm using Zend Framework 1.9.3
Thanks!
While I don't think it's possible with the current router to allow N values (a fixed number would work) you could write a custom router that would do it for you.
I would question this approach, however, and suggest that actually listing all of your routes won't take long and will be easier in the long run. A route designed as you've suggested would mean that either your named parameters are always in the same order, i.e.
/controller/action/id/title/colour
or that they are almost anonymous
/controller/action/value1/value2/value3
With code like
$this->getRequest()->getParam('value2'); //fairly meaningless
Does it have to be N or can you say some finite value? For instance can you imagine that you'll never need more than say 5 params? If so you can set up a route:
/:controller/:action/:param0/:param1/:param2/:param3/:param4
Which will work even if you don't specify all 5 params for every action. If you ever need 6 somewhere else you can just add another /:paramN onto the route.
Another solution I've worked with before is to write a plugin which parses the REQUEST_URI and puts all the extra params in the request object in the dispatchLoopStartup() method. I like the first method better as it makes it more obvious where the params are coming from.

Categories