Search code examples
symfonyurl-rewritingroutesextendslug

Patching/Extending route UrlGenerator for url rewriting to replace all spaces with hypens


I have routes like this:

user:
    path: /u/{id}/{name}
    defaults: { _controller: AcmeMyBundle:User:user, name: '' }
    requirements:
        id: '[0-9]+'

{name} is there just to have a nice looking url for users and SEO. I don't use {name} for anything in my application because {id} does the job. {name} usually consists of multiple words (first + last name etc) and generated urls look like this:

http://my.project/u/12/Firstname%20LastName

I generate url either in twig template with path('user', {id: user_id, name: user_name}) or in php with with $this->get('router')->generate(...)

I would like to avoid having %20 and replacing all spaces with hyphens to have links look like this:

http://my.project/u/12/Firstname-LastName

It looks more readable and I read somewhere that google like hyphens more...

The best way would be if route generator would do that. Just replace alle spaces with hyphens. I don't need anything else at the moment and it cannot affect anything because it {name} or some other descriptive params are just used for SEO and they are not used in application. {id} is important param

I was not able to find a way to do it nice by some parameter so I just opened vendor/symfony/symfony/src/Symfony/Component/Routing/Generator/UrlGenerator.php and added "%20" and a space to decodedChars:

protected $decodedChars = array(
    # ...
    '%2A' => '*',
    '%7C' => '|',
    # replace spaces with hyphen
    '%20' => '-',
    ' '   => '-' 
);

It is working but I don't feel well with this solution because I am patching symfony's core. And later on I would maybe like to lowercase {name} or some other params per default.

Is there are some better way for this? I would feel that the best way for adminstrating such stuff would be if it would possible to define some "postSlugify" params in routing.yml...

I could make function getName() and getNameSluggified() in my User entity and something similar in other entities but there should be a way to automate this without creating n number of similar functions in every entity.


Solution

  • As it worked for you, here's the complete answer :

    You can use Doctrine Sluggable extension :

     class Foo
     {
         // your attributes
         // in the folowing "fields", you cas use several fields
        /**
        * @Gedmo\Slug(fields={"name", "bar"})
        * @ODM\String
        */
         private $slug;
    
      // some stuff
    }
    

    If you change your field attribute, you will need to refresh your slugs. Here is the topic I found about refreshing slugs.

    You can implement this in a command-line tool by using this documentation page.