Aerendir Aerendir - 3 days ago 5
PHP Question

Symfony @ParamConverter: exclude the use if the placeholder does not contain a dot

I have this controller:

/**
* {@inheritdoc}
*
* @Route("entity/{domain_host}")
* @ParamConverter("entity", class="AppBundle:Entity", options={
* "repository_method" = "findOneByDomainHost",
* "mapping": {"domain_host": "domainHost"},
* "map_method_signature" = true
* })
*/
class EntityController extends Controller
{
...
}


This way an URL like
http://example.com/entity/another-example.com
is matched by the action and the corresponding
another-example.com
entity is hydrated and passed to the controller.

Now, this entity has also an ID.

I'd like to intercept an URL like
http://example.com/entity/12345
and redirect it to
http://example.com/entity/another-example.com
.

To do this I created another method in the
EntityController
:

/**
* {@inheritdoc}
*
* @Route("entity/{domain_host}")
* @ParamConverter("store", class="AppBundle:Entity", options={
* "repository_method" = "findOneByDomainHost",
* "mapping": {"domain_host": "domainHost"},
* "map_method_signature" = true
* })
*/
class EntityController extends Controller
{
public function redirectIdToDomainAction(Request $request)
{
die(dump($request));
// Following will be the redirect logic
}
}


And in my
routing.yml
, AT THE TOP OF THE FILE:

entity_id_to_domain:
path: /entity/{id}
defaults: { _controller: AppBundle:Entity:redirectIdToDomain }
requirements:
id: ^[^.]*$
methods: [GET]


Practically the
redirectIdToDomain
action is called if the placeholder doesn't contain a dot (the dot is the discrimen: if the placeholder has a dot, a domain is passed, if there isn't the dot, the placeholder probably represents an Entity by uts ID and I have to redirect).

The problem is that, as the controller class
EntityController
uses the
@ParamConverter
the placeholder is ever interpreted as a domain and the consequence is that I get a
AppBundle:Entity object not found.
.

So, is there a way to apply the
@ParamConverter
only if the placeholder has a dot? Or, which other approaches can I use to make the
redirectToIdAction
work without throwing the
Not found
exception?

Answer

A custom ParamConverter might do the trick, but if you don't want to make one, you will have to use different routes for IDs and domain names.

Solution 1

Since your routing is done on the whole class and not on the actions themselves, I'm afraid you will have to move the redirect action to another controller class.

After that, you can match IDs and domain names selectively using requirements

/**
 *@Route(
    "entity/{domain_host}",
     name="entity_domain",
     requirements={"domain_host": "^(?=.*[\w])(?=.*[.]).+$"}
 *)
 *@ParamConverter(...)
 */
someActionOnDomainAction()
{
//...
}


/**
 *@Route(
    "entity/{id}",
     name="entity_domain",
     requirements={"id": "^[\d]$"}
 *)
 */
redirectIdToDomainAction()
{
//...
}

Solution 2

Alternatively, you could change you repository method findOneByDomainHost() to something like findOneByDomainHostOrID(), and make it match both domain names and numeric IDs. This way you get rig of Object Not Found errors, and you can always get the domain name of you entity, and do the redirection in the same controller action.

Comments