Symfony2 - How to use #Entity annotations in Controllers? - php

Symfony's manual on ParamConverter has this example:
/**
* #Route("/blog/{post_id}")
* #Entity("post", expr="repository.find(post_id)")
*/
public function showAction(Post $post)
{
}
Source: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html#fetch-via-an-expression
But using #Entity annotation gives me this error.
The annotation "#Entity" in method AppBundle\Controller\CurrencyController::currencyAction() was never imported. Did you maybe forget to add a "use" statement for this annotation?
Obviously, I need to use a namespace, but which one? Please help.

The Entity annotation only exist on master (or futur v4).
Source file here
But as you can see, this is only a shortcut to #ParamConverter annotation with expr option, so you have to use this one until next release.
Best regards.

You are trying to use ParameterConverter so this syntax is just wrong.
Use this instead
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
/**
* #Route("/blog/{post_id}")
* #ParamConverter("post_id", class="VendorBundle:Post")
*/
public function showAction(Post $post)
{
}
VendorBundle:Post should be replaced with whatever your Vendor is (if any) and Bundle is.

Using annotation #ParamConverter with option repository_method is deprecated
The repository_method option of #ParamConverter is deprecated and will be removed in 6.0. Use the expr option or #Entity.
Thus it's better to use #Entity (documentation)
You have to add the namespace :
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;

Related

Turn off pluralisation for an endpoint in APi Platform

In a Symfony 5 project we're using the APi Platform to generate a REST API.
One of the entity classes is called FarmMetadata.
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Table(... some settings ...)
* #ORM\Entity
*/
class FarmMetadata
{
// properties and methods
}
When I run php bin/console debug:router it shows the following routes for this resource:
api_farm_metadatas_get_collection GET ANY ANY /api/farm_metadatas.{_format}
api_farm_metadatas_post_collection POST ANY ANY /api/farm_metadatas.{_format}
api_farm_metadatas_get_item GET ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_delete_item DELETE ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_put_item PUT ANY ANY /api/farm_metadatas/{id}.{_format}
api_farm_metadatas_patch_item PATCH ANY ANY /api/farm_metadatas/{id}.{_format}
However the word "metadata" is already plural. There's no such thing as metadatas. How can I turn off the pluralisation for this endpoint?
I tried using shortName:
* #ApiResource(
* shortName="FarmMetadata" // also "farm_metadata"
* )
but it doesn't change the output.
If I use:
* #ApiResource(
* shortName="Metadata"
* )
then the route names and paths are changed:
api_metadata_get_collection GET ANY ANY /api/metadata.{_format}
api_metadata_post_collection POST ANY ANY /api/metadata.{_format}
api_metadata_get_item GET ANY ANY /api/metadata/{id}.{_format}
api_metadata_delete_item DELETE ANY ANY /api/metadata/{id}.{_format}
api_metadata_put_item PUT ANY ANY /api/metadata/{id}.{_format}
api_metadata_patch_item PATCH ANY ANY /api/metadata/{id}.{_format}
but that's not what I want.
I know that I can declare a path for every operation, but that would hurt the DRY principle.
How can I achieve the desired behaviour?
You could use "path" option on each operation.
Cf https://api-platform.com/docs/core/operations/#configuring-operations
For example
* shortName="Metadata",
* itemOperations={
* "get"={
* "path"="/metadata/{id}"
I don't think this is possible by configuration: these routes are built in the private method ApiPlatform\Core\Bridge\Symfony\Routing\ApiLoader::addRoute (at least in v2.6 which I'm using), and this uses a static call to a pluralizer - so: decorating the ApiLoader is not easily possible (as the addRoute method is private), and exchanging the ways of generating the route is not possible (due to the usage of a static method call).
Looks like you need to open a feature request ticket in their bug tracker...
you can do easily as you want
api_platform:
...
path_segment_name_generator: App\InfraStructure\ApiPlatform\Core\SingularPathSegmentNameGenerator
create SingularPathSegmentNameGenerator
<?php
declare(strict_types=1);
namespace App\InfraStructure\ApiPlatform\Core;
use ApiPlatform\Core\Operation\PathSegmentNameGeneratorInterface;
use ApiPlatform\Core\Util\Inflector;
final class SingularPathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
public function getSegmentName(string $name, bool $collection = true): string
{
return Inflector::tableize($name);
}
}

FOSRestBundle Annotations for GET

I am currently developing an API and am using FOSRestBundle. I've gone wrong somewhere with the annotation side of my controller.
Please see my code below:
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
class DefaultController extends FOSRestController
{
/**
* #Rest\("/default/{string})
* #param string $string
*/
public function defaultAction($string)
{}
}
I am trying to to pass a parameter to the default action and do something with it. However, the parameter I include in the URL isn't getting passed to the action. Any help will be appreciated.
You're just missing the Get from your first annotation, it should be: #Rest\Get("/default/{string}")

Doctrine attributes namespace

trying to understand what is the Doctrine. I using PHPStorm 2016.3.2 and plugin "PHP Annotations".
When i'm create the Model i'm trying to use annotations like this:
use \Doctrine\ORM\Mapping as ORM;
/**
* Class Region
* #package models
* #ORM\Entity()
* #ORM\Table(name="regions")
*/
class Region { ... }
In annotations i'm using not #Entity, i'm using #ORM\Entity() because IDE understanding what is that and making tips for me. But on this way Doctrine didnt see my classes. How i can to resolve this problem? Thanks.
I came across the same issue while creating the Doctrine configuration through the
Setup::createAnnotationMetadataConfiguration()
method. When you set its fifth parameter $useSimpleAnnotationReader to false you can use the name-spaced syntax the PhpStorm extension expects.

Symfony routing annotation Entity

I need to get 2 entity objects from the path parameter in Symfony 3.
From the document, I can do:
/**
* #Route("/blog/{id}/comments/{comment_id}")
* #Entity("comment", expr="repository.find(comment_id)")
*/
public function showAction(Post $post, Comment $comment)
{
}
However, I could not find out where that #Entity comes from. The page return with error:
[Semantical Error] The annotation "#Entity" in method ABCBundle\Controller\ABCController::editAction() was never imported. Did you maybe forget to add a "use" statement for this annotation? in /srv/www/symfony3/src/ABCBundleController (which is being imported from "/srv/www/symfony3/src/ABCBundle/Resources/config/routing.yml").
Does anyone know?
You may want to add this use statement:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
See SensioFrameWorkExtraBundle at github

Can't call custom repository function in Symfony2

We're having problems calling a certain custom entity repository function from our controller in a Symfony2 project. We have successfully done it before with other entities so we're probably missing something and I can't figure out what it could be.
Our repository class looks like this:
<?php
namespace OurSite\Bundle\OurBundle\Entity;
use Doctrine\ORM\EntityRepository;
class BlogRepository extends EntityRepository
{
public function findPreviousPosts($limit = 6)
{
$q = $this->createQueryBuilder('q')
->where('q.category = :category')
->setMaxResults($limit)
->add('orderBy', 'q.published ASC')
->getQuery();
$res = $q->getResult();
return $res;
}
}
The entity:
<?php
namespace OurSite\Bundle\OurBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
/**
* OurSite\Bundle\OurBundle\Entity\Blog
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="OurSite\Bundle\OurBundle\Entity\BlogRepository")
*/
class Blog {
// Non-relevant stuff here
}
When we call the method like this:
$em = $this->getDoctrine()->getEntityManager();
$previousPosts = $em->getRepository('OurSiteOurBundle:Blog')->findPreviousPosts();
We get this:
Undefined method 'findPreviousPosts'. The method name must start with either findBy or findOneBy!
If we do echo get_class($em->getRepository('OurSiteOurBundle:Blog')); it outputs BlogRepository, as expected.
What could be causing the problem? We have a superfluous bundle directory in the project but I'm guessing that can't be causing it?
From the source you provided, this may not be your issue, but it may save others some search time.
I was coming across the same "must start with either findBy or..." error, and it turns out in my Entity definition I had accidentally made a call to the #ORM\Entity annotation Twice. The first time I used it properly and set the repositoryClass, but the second time I just used it by itself (as with an Entity that wouldn't have a custom repository) and so that overwrote the previous repositoryClass definition.
/**
*
* #ORM\Entity(repositoryClass="Company\TestBundle\Entity\MyEntityRepository")
* #ORM\Table(name="testing_my_entity")
* #ORM\Entity
*/
class MyEntity
{
etc...
}
If you get this error: The method name must start with either findBy or findOneBy! that means that your custom repository isn't loaded.
Check for typos in the code, clear cache, make sure "OurSiteOurBundle" is the actual shortcut name.
I had the same problem. I've seen many posts about that but nothing solved it.
Finally I found out that was because I was previously using generated yml files, so Doctrine didn't read annotations for mapping !
So just be sure you don't have any yml/xml Doctrine files.
And then :
app/console doctrine:cache:clear-metadata
Did you used this entity before? I see strange entity shortcut for Blog
OurSiteOurBundle:Blog
but your Blog have OurSite\ Bundle\OurBundle\Entity namespace. I think it should be
OurSiteBundleOurBundle:Blog
and entity manager points you to wrong repository class
If use xml for mapping(pass tested):
Update xml or yml mapping file, add repository-class attribute:
<entity name="Ccd\Bundle\FrontendBundle\Entity\UvUpdatePageContent" table="uv_update_page_content" **repository-class="Ccd\Bundle\FrontendBundle\Entity\UvUpdatePageContentRepository"**>
http://doctrine-mongodb-odm.readthedocs.org/en/latest/cookbook/mapping-classes-to-orm-and-odm.html
Then update doctrine cache:
php app/console doctrine:cache:clear-metadata
use yml(not tested):
Acme\DemoBundle\Entity\Post:
type: entity
table: posts
RepositoryClass: Acme\DemoBundle\Entity\PostRepository

Categories