0

I need to check if entered value, e.g "specialist", is not in use as an URL in Symfony 6 application.

Simple ANY-method paths are simple:

/** @var RouterInterface $router */
$router->match('/specialist');
// returns array

Non-matching methods are also simple:

/** @var RouterInterface $router */
$router->match('/specialist');
// if route path "/specialist" accepts only POST
// Symfony\Component\Routing\Exception\MethodNotAllowedException is thrown

But I need to check urls that are used as a prefix, e.g if I need to check for string "login" and have urls '/login/facebook' and '/login/google' but no simple '/login'. So - how can I check if string is not being used as any url prefix?

Symfony version 6, as said.

EDIT:

How to make this into a Validator, or more specifically, how can I inject Router (or whatever needed) into my validator?

JohnSmith
  • 436
  • 5
  • 17
  • What are you trying to achieve exactly? I think I know how to do what you want, but I feel like you're trying to do something the wrong way. Are you trying to validate if a given URL exists in your app? Can you give some context please so I can try to provide the best solution for you? – Yann Chabot Mar 12 '23 at 18:13
  • 1
    "how can I inject Router (or whatever needed) into my validator" - through the DI container, as you inject all other services – Nico Haase Mar 13 '23 at 06:50
  • @YannChabot "What are you trying to achieve exactly?". Made my example better. What I'm trying to achieve is dynamic routing, i.e user enters its name and I need to check if it does not collide with other users (easy) and with existing system urls (my question). – JohnSmith Mar 13 '23 at 08:17
  • Please add all clarification to your question by editing it. Why not use a common URL for all users (like `/user/$username`) and check for existing usernames only? – Nico Haase Mar 13 '23 at 11:00
  • @NicoHaase Client's request, and I did edit my original question. – JohnSmith Mar 13 '23 at 11:42
  • 1
    @JohnSmith I think that you should compare against usernames instead of the URL if you just want to validate that it does not colide no? You could check via the UserRepository if the username is already taken instead of checking against the route? Or am I missing something? What is inside the route validator that you don't have anywhere else is my point. – Yann Chabot Mar 13 '23 at 13:20
  • Can you share more details about how the routes are build? If you want to allow all possible strings at all possible places, this would also mean that you cannot add new routes in the main application without checking whether they collide with a username that is already in use – Nico Haase Mar 13 '23 at 13:28
  • 1) User can choose username, e.g "peter" 2) I want to check that this a) username is unique (this is easy) b) this username does not collide with existing urls, e.g if some moron chooses username "login" then I can prevent it. This is because I want that www.mysite.com/peter to open info page for that user. Routes are built normally with PHP attributes, nothing fancy here, e.g `#[Route(path: '/me/profile/general', name: 'account_profile_general', methods: ['GET', 'POST'])]`. And yes this is true, I cannot add new routes before checking if it is available. – JohnSmith Mar 13 '23 at 14:28
  • Please add all clarification to your question by editing it – Nico Haase Mar 13 '23 at 14:39

2 Answers2

0

How to make this into a Validator, or more specifically, how can I inject Router (or whatever needed) into my validator?

If you’re using default services configuration (autowire: true and autoconfigure: true), you can just inject needed dependencies into your validator in the same way as into other services.

Quick example below:

use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class MyValidator extends ConstraintValidator
{
    private RouterInterface $router;

    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }

    public function validate($value, Constraint $constraint): void
    {
         // ...
    }
}

See more in the Constraint Validators with Dependencies documentation paragraph.

kniziol
  • 49
  • 2
  • Thanks, I had hard time getting that to work - validator was not even being instantiated. But after some digging I found out that problem was that I was using `CompoundConstraint` and its validator is `final` class and therefore no DI for you, mr smarty pants. – JohnSmith Mar 13 '23 at 11:47
0

I think you want one (or more) catch-all routes, for URLs which don't already have a controller

#[Route(path: '/{friendlyURL}', name: '...', methods: ['GET'], requirements: ['friendlyURL' => '[a-zA-Z0-9_-]{2,32}'], priority: -1, options: ['utf8' => true])]

The priority value means it gets checked last

IanMcL
  • 366
  • 2
  • 10