Search code examples
symfonycurlroutessymfony-routing

How to check for absolute paths/routes in Symfony?


First of all thank you for taking your time takling this difficult topic.

Goal:

My URL structure is like facebook/twitter: site.com/Username

To let the user set the username, I need to check if a path of a route matches a username.

Possibilities & problems:

If somebody is interested, the possible solutions I came up with:

1.) Using getRouteCollection()

Problem: This method shouldn't be used because it rebuilds the route cache and kills performance (see https://github.com/symfony/symfony-docs/issues/6710)

2.) Using a blacklist as RegExp in the User (for Username) Entity to blacklist all sites like "settings", "about", "login", "register"...

* @Assert\Regex(pattern="/^(?!register)(?!login)...

Problem: This is nearly guaranteed to explode because sometimes a URL is forgotten to add into this RegExp

3.) Using CURL to check if the site.com/username results in a 404

Problem: This seems to be a "hack" for me and unprofessional.

Question:

Whats the professional, secure way of checking if a route doesn't already exists, so that the username can be set and is guaranteed to be "free" (via absolute path like site.com/Username and no other route is in the way)?

By example something like $app->hasURL('/username')


Solution

  • Add: use \Symfony\Component\RoutingException\ResourceNotFoundException;

    Then, where $router is the routing service, you can attempt to match the url to a route. If it doesn't match anything it will throw an exception, but if you have a default catch-all route it will always match something so you would need to just detect if it matches the catch-all instead:

    $routeIsAvailable = false;
    
    try {
        $route = $router->match( '/' . $username );
    
        // If you are using a catch-all route to load profiles
        if ( $route[ '_route' ] === 'name_of_catch_all_route' )
            $routeIsAvailable = true;
    
    } catch ( ResourceNotFoundException ) {
    
        // If the url didn't match any route at all
        $routeIsAvailable = true;
    }
    

    Make sure that you validate $username first so that it doesn't have any characters like ? or /. You can also urlencode it, but you probably don't want your user's profile urls to have encoded characters in them, so it's better to just restrict the valid usernames.