I’ve planned for a while the ability to call objects methods in dispatch_* functions. Useful if you want to group your controller functions in a class for example (or simply for those who can’t write a PHP project without having a class keyword in each file).
I’ve added Matěj Grabovský’s commit that adds support for dispatching to lambda functions/closures in the new 0.5 branch; and i forgot that it also “activates” the dispatching objects methods features!
Because we use call_user_func() to call our controller function, our parameter is a callback function, and can also be object methods, including static clas methods and lambda functions.
So now we can write
# will call my_hello_function() function
dispatch('/hello', 'my_hello_function');
# Static class method call, MyClass::hello();
dispatch('/hello', array('MyClass', 'hello'));
# Object method call, $obj->hello();
dispatch('/hello', array($obj, 'hello'));
# Static class method call (As of PHP 5.2.3), MyClass::hello();
dispatch('/hello', 'MyClass::hello');
# Using lambda function (As of PHP 5.3.0)
dispatch('/hello', function(){
return 'Hello World!';
});
PS: thanks to datashaman for noticing it
See changes.
This a maintenance release with some bug fixes.
I’ve also updated the README files with some notes about Url rewriting.
Now i can start to work on 0.5 and new features ;-)
Too many spam in the Wikir demo !!! So I finally decided to update it with a CSRF protection that i developped for Vincent Hélye’s portfolio. This is not a perfect solution but it’s first step to fight against those nasty spams.
This little set of functions will be the first one of a serie that I call “Lemons”. Lemons can be seen as loose coupled extensions for Limonade. I will initiate a git repository for lemons in a few days, but you can already check lemon_security.php in the wikir example
You’ll find all changes in the CHANGES file, but let’s have a quick look to some new features:
Session features
Session starts automatically by defaut. Then you can access session variables like you use to do, with $_SESSION array.
You can disable sessions with the session option.
⌘ see snippet example
Flash features
Flash is a special use of sessions. A flash value will be available only on next request and will be deleted after. It’s very useful to raise errors on a form or to notice a successful action.
This is the same behaviour as in Rails, and the syntax is very closed to it:
-
flash($name, $value...) defines a flash for the next request
- in views, you can get current flash values with the
$flash array or flash_now($name) function.
⌘ see snippet example
Url rewriting support
Limonade now support url rewriting for beautiful urls.
With a .htaccess in your app folder
<IfModule mod_rewrite.c>
Options +FollowSymlinks
Options +Indexes
RewriteEngine on
# RewriteBase /my_app/ # if your app is in a subfolder
# test string is a valid files
RewriteCond %{SCRIPT_FILENAME} !-f
# test string is a valid directory
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [NC,L]
</IfModule>
And setting explicitly the option('base_uri') in your configure() function:
option('base_uri', '/my_app'); # '/' or same as the RewriteBase in your .htaccess
You can access your site with urls like http://your.new-website.com/my/limonade/path instead of http://your.new-website.com/?/my/limonade/path.
Errors redesign
Enjoy your errors! (screenshot)
08/5, @4:00pm
Beautiful errors: the new limonade default view design, since 0.4
Changes since 0.4:
- [NEW] support for HEAD requests [#12 state:resolved]
- [FIXED] internal routes are at the begining of the lib so can’t be bypassed [#13 state:resolved]
- [FIXED] internal CSS we’re renderred with a layout if defined [#14 state:solved]
- [FIXED] bug in file_is_text
- [CHANGED] removes mime_content_type compatibility function and add file_mime_content_type() [#15 state:resolved]
- [NEW] Adding an $exit optional parameter to the stop_and_exit() function
- [FIXED] Fixing flash bug while redirect_to [#16 state:resolved]
- [FIXED] Fixing redirect_to bug with multiple parameters [#17 state:resolved]
- [FIXED] Fixing bug setting an error_layout [#18 state:resolved]
- [FIXED] buggy url_for()
- [NEW] url rewriting support by explictly setting option(‘base_uri’)
See http://github.com/sofadesign/limonade/blob/master/CHANGES for all changes.
Working on the new Limonade 0.4 branch, it’s also time to read and read again current code, and checking code design consistency.
Something i didn’t notice before suddenly appears: options are managed with the singular function option but params are retrieved with the plural option params… very confusing…
I probably had in mind those two naming ways:
- using plural, like accessing a member of an array
- using singular, like an action method or like saying “get/set option”
I’ll try in this post to explain each feature in order to find the right naming. As me, you’ll probably be surprised how such a small question raises new problematics and reveals hidden design defects.
About function naming
Every code project has its conventions. Habits also depends on the language. But there are common rules that you can find most of the time.
In Limonade, i choosed to be as close as possible to the PHP native API conventions:
- lowercase
- underscored names
- prefixed by module name (but i’ve not prefixed all my functions with
limonade_… too verbosed…)
I’m trying to keep functions names short and simple but always meaningful. For simplicty and compacity, some function are in the same time a getter and a setter: so i don’t need to, and i can’t, use a get_ or set_ prefix. But remember those functions are still verbs.
Options features
Many features are covered in this single option() function
- getting all options (no argument provided)
- getting an option (one argument provided)
- setting an option (two arguments provided)
I should have wrote option with three function instead of one:
get_all_options()
get_option($name)
set_option($name, $value)
This all-in-one getter/setter function is very convenient but it’s also the source of our problem.
I’m not sure that getting all options is useful: perhaps for internal use ? There’s no need of it for now, so i should remove it in the next release (never implement unnecessary features…).
So, we only use it for getting and setting an option: prefering a singular naming is probably the most common and logical solution.
Params features
Actually, params() does 4 things:
- getting all params (no argument provided)
- getting a param (by providing a argument)
- setting a param (by providing a $name argument and a $value argument, or n arguments…)
- resetting params (with a null argument)
Getting a param is the main use. Maybe getting all can be useful too. But setting and resetting should really be reserved for an internal use. Params should be read-only: they are passed by current uri, so they can’t be changed.
Maybe you might want to filter a param in the before function, like in Wikir
function before()
{
if($page_name = params('page'))
{
params('page', rawurldecode($page_name));
}
}
In this case, if params() has no writing feature anymore, we need to use a global variable or better, creating our own filter function and calling it when needed
function my_filtered_params()
{
$params = params();
if(array_key_exists('page', $params)) $params['page'] = rawurldecode($page_name);
return $params;
}
And about the reset feature, there is no reason to use it unless for internal use: this is a good example to show that using public API in a private context makes it more complicated that it needs to be.
So we only need to get all params or one. 95% of the time, we’ll call a unique param: so it will be singular
And next… refactoring
Now I really need to refactor those functions. I will also apply the same process to all functions of the limonade public API to improve it.
I read recently this great article by Yehuda Katz. Heaven if we can’t compare with such a huge task (Rails 3.0 refactoring), i note 4 refactoring good practices:
- Having a test suite for each part that will be refactored
- Don’t add any new features during a refactoring cycle
- Make changes step by step, by logical groups and make tests after each change
- Separate public api from internal functions / don’t use public api functions for internal use.
So Limonade will need a good refactoring phase: not for 0.4 branch because it adds new features, maybe in the 0.5 branch after completing unit testing.
(Author: Fabrice Luraine - second reading/corrections: Mathias Standaert)