CakePHP with Symfony’s2 router

Zzyzx_road

A couple of months ago I have started my adventure with CakePhp and as every Symfony’s developer I thought that any other framework except Symfony is a piece of crap. Day by day and step by step I began to realize that’s not so bad as it seemed to be in the beginning. Well, the second version of CakePhp still has a lot old-fashioned patterns, singletons or lack of tests, but I can live with that. I saw a lot of better or worse frameworks in my life. However, one module remains a bitter aftertaste – the router.

Let’s just look at the very basic things. Let’s start with new route declaration.

1
2
3
4
5
6
Router::connect ( '/blog/:slug', array (
        'slug' => 'index',
        'controller' => 'blog',
        'action' => 'post',
                'template' => 'white'
));

It looks quite natural and shouldn’t make any unpredictable problems… well, shouldn’t. When I wanted to display an URL to the blog/:slug page in a View file I was struggling with additionals parameters and not found paths. As every developer I opened the declaration of `connect` method and tried to figure out what exactly happens inside. First impression was quite good – `public static function connect($route, $defaults = array(), $options = array()); `.

The author of Clean Code – Robert C. Martin emphasizes on the right naming. All methods, functions, classes or variables should tell you, literally, what responsibility they have. So, when I saw three parameters in `connect` method they seemed obvious – `$route` was for the URL, `$defaults` – filled the missing arguments by default values and `$options` – about additional information for my route.

Everything was clear and I couldn’t find out why my code cannot compose a proper URL until I caught the condition which was commented:

// keys that exist in the defaults and have different values is a match failure.

I was so wrong. In the result I’m pretty sure and, of course, I confirmed that, the code `Html->link($postName, array(‘controller’ => ‘blog’, ‘action’ => ‘post’, ‘slug’ => $slug)); ?>` will break, because we didn’t pass the argument `template`.

I believe that the second parameter in `connect` method should be called `$requires`. One confusing name took me 4 hours of my live and caused a lot of problems.

So, what can I do with this?

Extend! Extend the original routing by something what you really like. I’m huge fan of YML routing implemented in Symfony 2. It’s really simple, transparent and easy to read. Moreover, and what is the most important thing for me, each route has a name. So I can build every single URL without passing all `defaults` parameters, but focus only on mandatory as `slug`.

1
2
3
blog_show:
    path:      /blog/{slug}
    defaults:  { controller: Blog, action: post }

Looks better, right? Inspired by a presentation of @jakub_zalasSymfony in the Wild I decided to start writing a bridge for routing between CakePHP and Symfony2 route component.

CakePhp Symfony Router

Ready to use Plugin can be found at https://github.com/piotrpasich/cakephp-symfony-routeror http://plugins.cakephp.org/p/1725-cakephp-symfony-router. Also, you can find there a exhaustive manual how to install and use this component. I have prepared a god base to eztend this for XML configuration files and annotations.

The main assumptions were to create a really simple in use system based on symfony router component to cover problems with I struggled. So, now you can call each route by name like this:

1
2
<?php echo $this->SymfonyRouter->getPath('blog_post', array('slug' => $post->getSlug())); ?>
<a href="<?php echo $this->SymfonyRouter->getPath('blog_post', array('slug' => $post->getSlug())); ?>"><?php echo $post->getSlug() ?></a>

Conclusion

I really like the wise spectrum of available open source frameworks and platforms on the market. I learned Symfony, Zend, Kohana, CakePhp or even Drupal or WordPress. However, besides of the naming convention, used architecture or design patterns which can be more or less comfortable for me, sometimes I have to face a really huge problem which stops me for a couple of hours and I feel that I need to change that because every time I use it I will suffer (mentally).

Because the open source world emphasizes how the decoupling is important, it’s really easy to get my favourite component from one framework and put it into another. If I connect the framework with external module in a plugin – bridge, this should be easy to use for others. And I hope I did this.

  • http://harikt.com Hari KT

    Good to see integration of componenents on other frameworks.
    Like symfony, zend, aura do provide a few components.

  • http://kadur-arnaud.fr rudak

    Totally agree with that !

  • http://jedistirfry.co.uk David

    Great idea to bridge the two components. I’m confused by your example route though. What is it actually supposed to do? Why is slug defined if it’s a routing token?

    If I assumed that it was to view a blog post I would create a route like:
    `Router::connect(‘/blog/:slug’, [‘controller’ => ‘blogs’, ‘action’ => ‘post’], [‘slug’ => ‘[a-z0-9-]+’, ‘pass’ => [‘slug’]);`

    Then in your `BlogsController::post($slug)` method you would get the slug as a passed parameter. To create a link to view this post I would create a link as `echo $this->Html->link(‘View post’, [‘controller’ => ‘blogs’, ‘action’ => ‘post’, ‘slug’ => $blog[‘Post’][‘id’]]);`

  • http://piotrpasich.com Piotr Pasich

    David,
    your example is good. I cannot fight with that. My point was not to pass all parameters (as in your example) to every single link – ‘echo $this->Html->link(‘View post’, [‘controller’ => ‘blogs’, ‘action’ => ‘post’, ‘slug’ => $blog[‘Post’][‘id’]]);’ should be called without controller, action and template. I want to pass there really, really mandatory “slug”.

    So if the CakePHP has an option to create an url and call it by echo `$this->Html->link(‘View post’, ‘blog_post’, [‘slug’=>$blog[‘Post’][‘slug’]]);` then I’m ok.

    Piotr

  • Pingback: Today on the PHP Community … August 12, 2014 | PHP Community Magazine()

  • http://josediazgonzalez.com Jose Diaz-Gonzalez

    Nice work on the plugin, seemed interesting (I added a question about caching to your issue tracker).

    One question, unrelated to your plugin: Where is CakePHP lacking in tests? You mentioned in your post that we’re lacking in tests, yet the core tests are pretty comprehensive [1]. What gives you the idea that this is the case?

    [1] https://github.com/cakephp/cakephp/tree/master/lib/Cake/Test/Case

  • Pingback: Piotr Pasich: CakePHP with Symfony's2 router | facebooklikes()

  • Pingback: WebCoderPro » Weekly links for PHP developers #6: PHP Podcasts and how to hire PHPers()

  • Fedor

    Why are you talking about cake2 when you should be looking at cake3?

    • http://piotrpasich.com Piotr Pasich

      Hi,

      If I had any choice I will choose Symfony because this is the main framework which I prefer to use. I know that’s the third version is released and as I think the problem and solution is the same, or isn’t? http://book.cakephp.org/3.0/en/development/routing.html