Hacking everything (the good way)
Posted on 10/3/06 by Felix Geisendörfer
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
Why I've been a slacker about blogging
Well I admit it, I've been very bad about blogging the last weeks. I've been working on some Drupal pages (see fg-webdesign.de or osterzgebirge.cz for example) and have been doing some other stuff besides computers (snowboarding, friends, school, etc.). But I think it's never to late to make up for my inactivity and I'll try be more productive from now on.
What this post is about
The first post after my little break is mostly inspired by the experiences I made and am making with my current project SpliceIt! (Official Homepage / CakeForge Project) which aims to add more functionality to the plugins of cakephp (especially making them communicate with each other) and to create a set of plugins for very common tasks (user management, theming, i18n, url aliasing, etc.). The main thing I discovered was that the structure of CakePHP is the most flexible one I've ever come across and that it is possible to change nearly anything within it without having to hack any core files. This post will present some of the things I figured out and aims to inspire other developers to think outside the cake(-box) ; ).
Dynamic Routes
While I think that the routes.php is great for what it does I also do think that it somewhat limits you in the way routes can be done. Because sometimes you want to let the user of your website decide which path a certain page should get which puts you in the situation where you need a MySql table that contains your routing information. Now the problem is that the routes.php is static and won't let you ask a Model before execution. So wouldn't it be cool to have a controller that takes care of routing? I think it would! It took me a good while but after reading several times through the CakePHP Dispatching code I found a way that overwrites a local variable. It works like this:
This would go into your config/routes.php:
{
define ('DISPATCH_ROUTE', 'routing_controller/routing_action');
$from_url = DISPATCH_ROUTE;
}
And this is what you do inside of your routing_controller:routing_action():
{
$url = @$this->params['url']['url'];
// Here you can make changes to the Url so a different page get's
// displayed. Use a Model, some Regex and some Fantasy and you'll
// be able to come up with some great ideas ; ).
$this->requestAction($url);
$this->autoRender = false;
}
Plugins require their own PluginAppController / PluginAppModel
While I see that this is the right way if you look at plugins as sub-apps inside your main-app I think this can be a bit annoying if you work on a system where plugins are used as modules that are supposed to work with the same resources. The trick I use can be done either from the routes.php (maybe bootstrap.php also) or (best) from a central routing plugin. Here is how:
Put this in your central routing controller or maybe the routes.php:
// and that this url is a plugin path.
list($pluginName, $controller,$action) = explode('/', $url);
$pluginName = Inflector::camelize(Sanitize::paranoid($pluginName));
// This fakes the existance of our [Plugin]AppController and [Plugin]AppModel
eval('class '.$pluginName.'AppController extends AppController{}
class '.$pluginName.'AppModel extends AppModel{}');
Adding default Helpers, Models, etc.
Well while this little trick won't make your friends think you're a big wizard people who haven't seen it before will be happy to see it. The problem is that sometimes you have a controller and want certain Models/Helpers/etc. to be standard for them. Now this works fine if you set $this->uses = array(..) to whatever you need in the common controller all those sub-controllers extend, but whenever you want to use an additional Model/etc. for one of those Controllers you have to retype the entire array. I say do it like this:
{
parent::__construct();
array_push($this->uses, 'User');
array_push($this->uses, 'Access');
array_push($this->uses, 'etc..');
}
Theming for everybody
For all of you who have been thinking of integrating some kind of theming support into there app PhpNut_ has created an elegant solution that will help you. Take a look at it here. Now after dropping it into the app/views folder all you have to do is to modify your AppController to look like this:
{
var $view = 'Theme';
}
Final thoughts
While the last two things are fairly harmless and I wouldn't even call them real hacks the two things above are fairly hot. So: Only try them at home ; ). When using them keep in mind that the way I've published them here can just be understood as proof of concepts and you'll have to deal with certain issues they could possibly cause. If you have any problems with them let me know.
I have some other hacks in work as well but I didn't want to publish them yet since they are not working good enough, yet ; ).
Enjoy coding,
Felix aka the_undefined
You can skip to the end and add a comment.
Nate, are you refering to: "Plugins require their own PluginAppController / PluginAppModel"?
Well I think you could put that in bootstrap (as I wrote) but I wasn't quite sure if the Url already got routed at this point (don't think so?) so putting it into a controller that handles Url Aliasing seemed to be more fail safe. But well if it works in bootstrap I agree that it would belong there.
Hi Felix, the idea of adding a routing controller is the best way for having dynamic routes. Thanks for sharing your ideas.
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
FYI, the latest version of Cake includes app/config/bootstrap.php, which was created for this very purpose.