SensioFrameworkExtraBundle
SensioFrameworkExtraBundle copied to clipboard
Problem with converter and option route parameter
Imagine this route:
feature_product:
pattern: /category/{category}/feature-product/{product}
defaults:
_controller: MyBundle:MyController:feature
product: ~
And this action:
/**
* @Template
*/
public function featureAction(Category $category, Product $product = null)
{
// If a product has been selected
if($product instanceof Product) {
$category->setFeaturedProduct($product);
return $this->redirect(...);
}
// Else, if no product has been selected, propose a list
$featurableProducts = $category->getProducts();
return ['products' => $featurableProducts];
}
Normally, calling URL /category/23/feature-product
should set $category
to a Category
object with id 23
, and $product
should be null
.
But in fact, what happens is that:
-
$category
is aCategory
object with id23
-
$product
is aProduct
object with acategory_id
of23
The converter makes a SELECT ... FROM product WHERE category_id = 23 LIMIT 1
.
I don't think it's the way the converter should work.
I'm also running into this issue when trying to use an optional parameter - is there a known workaround for this issue?
+1
Opting into this would let me have some idea of what's going on. Took about an hour of searching around just to find the magic annotations to do this... except this is now the only thing in my project using annotations and resulted in funky strangeness.
Opting out via annotations is spooky: I never asked my code to do this thing.
+1
I have this route:
/**
* @Route("/{section_slug}/{article_id}", name="article")
* @ParamConverter("section", class="SiteCoreBundle:Section", options={"section_slug"="slug"})
* @ParamConverter("article", class="SiteCoreBundle:Article", options={"article_id"="id"})
* @Template()
*/
public function articleAction(Section $section, Article $article)
{
return compact('article');
}
and when going to "http://localhost/app_dev.php/signins/5" I have result:
Unable to guess how to get a Doctrine instance from the request information.
The slug of section "signins" exists in DB and the "5" article exists too
@ByScripts Tl;dr You can work around this by using the ParamConverter annotation for the optional parameter and explicitly listing the mapping between the route parameters and the entity property. Something like this:
@ParamConverter("product", class="YourProduClass", options={"mapping": {"product": "id"}})
The DoctrineParamConverter will first try to find the entity by id (see apply method). If this fails (as there is not id in your example) it will fall back to class repository->findOneBy() (see findOneBy). If you do not provide a mapping the DoctrineParamConverter will try mappings as parameter => parameter for all route parameters. In your example it will look for fields named product and category in your product class. If such fields happens to exist, it will then call findOneBy with this mapping. So if your product class has a property named category it will fetch a product with category 23.
I hope this made some sense, just have a look at the apply and findOneBy method of the DoctrineParamConverter.