Ross
Ross

Reputation: 47057

Using ParamConverters with relations

I'm trying to match a GitHub-style URL (/{user}/{project}) using Symfony2 @ParamConverters. They retrieve the correct entities, however I would like to ensure that the project belongs to the user in the URL. There is a Doctrine relation between the two entities.

For example, with a Project 'bar', belonging to 'foo', I can access it at /foo/bar. However I can also access it under a different user: /baz/bar.

Is it possible to do this using the ParamConverter, or do I need to manually check in the action?

/**
 * @Route("/{user}")
 * @ParamConverter("user", class="AcmeUserBundle:User", options={"mapping": {"user": "usernameCanonical"}})
 */
class ProjectController extends Controller
{
    /**
     * @Route("/{project}")
     * @ParamConverter("project", class="AcmeProjectBundle:Project", options={"mapping": {"project": "slug"}})
     * @Template()
     */
    public function showAction(User $user, Project $project)
    {
        // Can I automate this check?
        if ($user->getId() !== $project->getOwner()->getId()) {
            throw $this->createNotFoundException();
        }
    }
}

Upvotes: 1

Views: 519

Answers (1)

Ross
Ross

Reputation: 47057

Found the solution to this, largely thanks to @Qoop's comment. By adding "user": "owner" to the mapping, the owner relation is queried using the $user variable (which because of the first @ParamConverter, is already a User instance.

Under-the-hood, this issues two queries - one to retrieve the first user and the second to retrieve the project (with project.owner_id = user.id and project.slug = slug). However I assume these are cacheable at the Doctrine-level.

The result of accessing the (non-existant) /baz/bar is a 404 with the message:

AcmeProjectBundle:Project object not found.

/**
 * @Route("/{user}")
 * @ParamConverter("user", class="AcmeUserBundle:User", options={"mapping": {"user": "usernameCanonical"}})
 */
class ProjectController extends Controller
{
    /**
     * @Route("/{project}")
     * @ParamConverter("project", class="AcmeProjectBundle:Project", options={"mapping": {"user": "owner", "project": "slug"}})
     * @Template()
     */
    public function showAction(User $user, Project $project)
    {
        // Do something with $user and $project,
        // where $project->getOwner() === $user
    }
}

Upvotes: 3

Related Questions