references class "Doctrine\ODM\MongoDB\UnitOfWork" but no such service exists - symfony

I'm currently using Symfony 4 with Doctrine MongoDB Bundle, following the instruction from this link:
DoctrineMongoDBBundle. So, I have a UserDocument:
src/Document/UserDocument.php
/** #MongoDB\Document(collection="user", repositoryClass="App\Repository\UserRepository") */
class UserDocument
{
/**
* #MongoDB\Id
* #var ObjectId
*/
private $id;
/**
* #MongoDB\Field(type="string", name="first_name")
* #var string
*/
private $firstName;
/**
* #MongoDB\Field(type="string", name="middle_name")
* #var string
*/
private $middleName;
/**
* #MongoDB\Field(type="string", name="last_name")
* #var string
*/
private $lastName;
}
src/Repository/UserRepository.php
use Doctrine\ODM\MongoDB\DocumentRepository;
class UserRepository extends DocumentRepository
{
}
src/Controller/Content.php
class Content extends Controller
{
/**
* #Route("/content", name="content")
* #param UserRepository $user
* #return Response
*/
public function index(UserRepository $user)
{
$user->findAll();
return new Response();
}
}
So, after running the content page, I got the following error:
Cannot autowire service "App\Repository\UserRepository": argument "$uow" of method "__construct()" references class "Doctrine\ODM\MongoDB\UnitOfWork" but no such service exists.
The DocumentRepository constructor looks like this:
public function __construct(DocumentManager $dm, UnitOfWork $uow, ClassMetadata $classMetadata)
{
parent::__construct($dm, $uow, $classMetadata);
}

Repository shouldn't be Services, but if you want to keep it that way, just Autowire the DocumentManager and get the uow and classmetdata from the Document Manager.
UnitOfWork and ClassMetadata can't be autowired
Do something like that in your UserRepository, it should work.
public function __construct(DocumentManager $dm)
{
$uow = $dm->getUnitOfWork();
$classMetaData = $dm->getClassMetadata(User::class);
parent::__construct($dm, $uow, $classMetaData);
}

Make sure to exclude your repository class from autowiring. Example here: https://symfony.com/doc/current/service_container/3.3-di-changes.html
In case you want your repository class as a service you should do it using a factory service.

Related

Override #Security annotation inside controller in symfony 4

Today I started upgrading my application from symfony 3 to 4 (and so the related libraries) and I couldn't understand why I couldn't make certain routes work (I had a 401 error but they were supposed to be public routes so no security checks were made there), then I ended up finding this question: #Security annotation on controller class being overridden by action method
A recent comment on the question says that while in a previous version of symfony framework extra bundle, if you put the security annotation on both a class and a method inside that class, the method annotation would override the class annotation, now they stack instead.
This can also be seen (altough it's not very clear since you could already put a #Security annotation on both class and method) on the SensioFramework changelog https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/CHANGELOG.md for version 4.0
allowed using multiple #Security annotations (class and method)
This is a very big change for me since a lot of routes in my application relied on that behavior (which was similar to Symfony 1 where you could set a default security behavior and then a more specific one for each action)
/**
* #Route("my-route")
* #Security("is_granted('IS_AUTHENTICATED_FULLY')")
*/
class MyController extends Controller {
/**
* In Symfony 3.x this would've removed security checks for the route,
* now it checks both the class and the method Security expressions
* #Security(true)
*/
public function myAction(Request $request) {
}
}
Is there some way other than "don't upgrade to symfony 4" or "reorganize your code" (which is my "plan B") to have this behavior back? Something like a configuration option or similar...
I can't seem to find anything about this
I had forgot about this question but I did solve this issue by making my own annotation and EventListener.
Disclaimers:
1) My code uses the Dependency Injection bundle to inject and declare services using annotations
2) I'm sharing the code AS IS, with no warranty it'd work for you too, but i hope you can get the gist of it
I created 2 annotations (#IsGrantedDefault and #SecurityDefault) that work exactly like #IsGranted and #Security (they actually extend the original annotations) except they can be applied only to classes, then i created 2 event listeners, one for each annotation. The event listeners also extend the original event listeners, but they just check if a method already has a Security or IsGranted annotation, in which case they do nothing.
IsGrantedDefault.php
<?php
/*
* #author valepu
*/
namespace App\Project\AppBundle\Annotation;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
/**
* #Annotation
* #Target("CLASS")
*/
class IsGrantedDefault extends IsGranted {
public function getAliasName() {
return 'is_granted_default';
}
public function allowArray() {
return false;
}
}
SecurityDefault.php
<?php
/*
* #author valepu
*/
namespace App\Project\AppBundle\Annotation;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
/**
* #Annotation
* #Target("CLASS")
*/
class SecurityDefault extends Security {
public function getAliasName() {
return 'security_default';
}
public function allowArray() {
return false;
}
}
DefaultListenerTrait.php (Values::DEFAULT_LISTENER_PREFIX is just a string with an underscore "_")
<?php
/*
* #author valepu
*/
namespace App\Project\AppBundle\Event\Traits;
use App\Project\AppBundle\Utils\Values;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
Trait DefaultListenerTrait {
/**
* #var string
*/
private $defaultAttribute;
/**
* #var string
*/
private $otherAttributes = [];
/**
* #var string
*/
private $attribute;
/**
* Sets the class attributes
* #param [type] $defaultAnnotation
* #param string|null $modifyAttr
* #return void
*/
protected function setAttributes($defaultAnnotation, ?string $modifyAttr) {
//Get the attirbutes names
$this->attribute = $modifyAttr;
$this->defaultAttribute = Values::DEFAULT_LISTENER_PREFIX . $defaultAnnotation->getAliasName();
$annotations = [new IsGranted([]), new Security([])];
foreach($annotations as $annotation) {
$this->otherAttributes[] = Values::DEFAULT_LISTENER_PREFIX . $annotation->getAliasName();
}
}
/**
* Checks wheter or not the request needs to be handled by the annotation. If it does adds the correct attribute to the request
* #param \Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent $event
* #return boolean
*/
protected function updateDefaultListener(FilterControllerArgumentsEvent $event) {
$request = $event->getRequest();
$default = $request->attributes->get($this->defaultAttribute);
//If there's already an "IsGranted" annotation or there's no "IsGrantedDefault" annotation
if (!$default) {
return false;
}
foreach($this->otherAttributes as $attr) {
if ($request->attributes->get($attr) || !$default) {
return false;
}
}
//We set IsGranted from the default and then call the parent eventListener so that it can handle the security
$request->attributes->set($this->attribute, [$default]);
return true;
}
/**
* Calls the event listener for the class if the request is handled by the class
* #param \Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent $event
* #return void
*/
protected function callEventListener(FilterControllerArgumentsEvent $event) {
if($this->updateDefaultListener($event)) {
parent::onKernelControllerArguments($event);
}
}
}
IsGrantedDefaultListener.php
<?php
/*
* #author valepu
*/
namespace App\Project\AppBundle\Event;
use App\Project\AppBundle\Annotation\IsGrantedDefault;
use App\Project\AppBundle\Event\Traits\DefaultListenerTrait;
use App\Project\AppBundle\Utils\Values;
use RS\DiExtraBundle\Annotation as DI;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\EventListener\IsGrantedListener;
use Sensio\Bundle\FrameworkExtraBundle\Request\ArgumentNameConverter;
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* #DI\Service(autowire = true)
* #DI\Tag("kernel.event_subscriber")
*/
class IsGrantedDefaultListener extends IsGrantedListener {
use DefaultListenerTrait;
/**
* #param \Sensio\Bundle\FrameworkExtraBundle\Request\ArgumentNameConverter $argumentNameConverter
* #param \Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface $authChecker
* #DI\InjectParams({
* "argumentNameConverter" = #DI\Inject("framework_extra_bundle.argument_name_convertor"),
* "authChecker" = #DI\Inject("security.authorization_checker")
* })
*/
public function __construct(ArgumentNameConverter $argumentNameConverter, AuthorizationCheckerInterface $authChecker = null) {
parent::__construct($argumentNameConverter, $authChecker);
$modifyAttr = new IsGranted([]);
$this->setAttributes(new IsGrantedDefault([]), Values::DEFAULT_LISTENER_PREFIX . $modifyAttr->getAliasName());
}
/**
* #param \Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent $event
* #return void
*/
public function onKernelControllerArguments(FilterControllerArgumentsEvent $event) {
$this->callEventListener($event);
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents() {
return [KernelEvents::CONTROLLER_ARGUMENTS => 'onKernelControllerArguments'];
}
}
SecurityDefaultListener.php
<?php
/*
* #author valepu
*/
namespace App\Project\AppBundle\Event;
use App\Project\AppBundle\Annotation\SecurityDefault;
use App\Project\AppBundle\Event\Traits\DefaultListenerTrait;
use App\Project\AppBundle\Utils\Values;
use Psr\Log\LoggerInterface;
use RS\DiExtraBundle\Annotation as DI;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener;
use Sensio\Bundle\FrameworkExtraBundle\Request\ArgumentNameConverter;
use Sensio\Bundle\FrameworkExtraBundle\Security\ExpressionLanguage;
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
* #DI\Service(autowire = true)
* #DI\Tag("kernel.event_subscriber")
*/
class SecurityDefaultListener extends SecurityListener {
use DefaultListenerTrait;
/**
* #param \Sensio\Bundle\FrameworkExtraBundle\Request\ArgumentNameConverter $argumentNameConverter
* #param \Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface $authChecker
* #DI\InjectParams({
* "argumentNameConverter" = #DI\Inject("framework_extra_bundle.argument_name_convertor"),
* "language" = #DI\Inject("sensio_framework_extra.security.expression_language.default"),
* "trustResolver" = #DI\Inject("security.authentication.trust_resolver"),
* "roleHierarchy" = #DI\Inject("security.role_hierarchy"),
* "tokenStorage" = #DI\Inject("security.token_storage"),
* "authChecker" = #DI\Inject("security.authorization_checker"),
* "logger" = #DI\Inject("logger")
* })
*
*/
public function __construct(ArgumentNameConverter $argumentNameConverter, ExpressionLanguage $language = null, AuthenticationTrustResolverInterface $trustResolver = null, RoleHierarchyInterface $roleHierarchy = null, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authChecker = null, LoggerInterface $logger = null) {
parent::__construct($argumentNameConverter, $language, $trustResolver, $roleHierarchy, $tokenStorage, $authChecker, $logger);
$modifyAttr = new Security([]);
$this->setAttributes(new SecurityDefault([]), Values::DEFAULT_LISTENER_PREFIX . $modifyAttr->getAliasName());
}
public function onKernelControllerArguments(FilterControllerArgumentsEvent $event) {
$this->callEventListener($event);
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents() {
return [KernelEvents::CONTROLLER_ARGUMENTS => 'onKernelControllerArguments'];
}
}
You can delete the class annotation and declare them on all methods

Every parent controller must have `get{SINGULAR}Action($id)` method when i have multi level sub resource in FOS Rest Bundle

I have three controller named BlogController, PostController, CommentController that CommentController is sub resource of PostController and PostController sub resource of BlogController.
/**
* #Rest\RouteResource("blog", pluralize=false)
*/
class BlogController extends FOSRestController
{
public function getAction($blogUri)
{
...
}
}
/**
* #Rest\RouteResource("post", pluralize=false)
*/
class PostController extends FOSRestController
{
public function getAction($postId)
{
...
}
}
/**
* #Rest\RouteResource("comment", pluralize=false)
*/
class CommentController extends FOSRestController
{
public function getAction($commentId)
{
...
}
}
routing.yml
mgh_blog:
resource: MGH\BlogBundle\Controller\BlogController
type: rest
mgh_blog_post:
resource: MGH\BlogBundle\Controller\PostController
type: rest
parent: mgh_blog
mgh_blog_post_comment:
resource: MGH\PostBundle\Controller\CommentController
type: rest
parent: mgh_blog_post
I define getAction methods, but i get following error:
[InvalidArgumentException]
Every parent controller must have `get{SINGULAR}Action($id)` method
where {SINGULAR} is a singular form of associated object
Edit:
I also try to change the method's name to getCommentAction($commentId), getPostAction($postId) and getBlogAction, but it no work.
When I use #RouteResource annotations, method name must be getAction($id), otherwise it doesn't work.
When I change parent of mgh_blog_post_comment router to mgh_blog, it's working!
That error description is awful and a big time waster because it doesn't tell you what the real problem is. Try the following:
/**
* #Rest\RouteResource("blog", pluralize=false)
*/
class BlogController extends FOSRestController
{
public function getAction($blogUri)
{
...
}
}
/**
* #Rest\RouteResource("post", pluralize=false)
*/
class PostController extends FOSRestController
{
public function getAction($blogUri, $postId)
{
...
}
}
/**
* #Rest\RouteResource("comment", pluralize=false)
*/
class CommentController extends FOSRestController
{
public function getAction($blogUri, $postId, $commentId)
{
...
}
}
You didn't have the correct number of arguments in the descendant controller actions. It took me two days of step debugging to figure this out.
The parent route, Blog, looks like:
/blog/{blogUri}
It will match
public function getAction($blogUri)
The child route, Post, looks like:
/blog/{blogUri}/post/{postId}
It will not match the code below because it needs two parameters. The same is true for the grandchild--which is looking for three parameters:
public function getAction($postId)
The grandchild route, Comment, looks like:
/blog/{blogUri}/post/{postId}/comment/{commentId}
The code keeps track of the ancestors of each controller.
The post has 1 ancestor. When building the routes for the post controller, the code looks at the number of parameters on the 'get action'. It take the number of parameters and subtracts the number of ancestors. If the difference is not equal to one, it throws the error.
Conclusion, for each descendant, it needs to include the ID parameters of it ancestors AND its own ID. There should always be one more parameter than there are ancestors.
Have you tried?:
class CommentController extends FOSRestController
{
public function getCommentAction($commentId)
{
...
}
}
Try:
public function cgetAction(Request $request)
{
...
}
This is my controller example:
<?php
namespace Cf\SClinicBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\Annotations\RouteResource;
use Cf\SClinicBundle\Entity\CfAcquireImage;
use Doctrine\DBAL\DBALException as DBALException;
use Doctrine\ORM\NoResultException as NoResultException;
/**
* CfAcquireImage controller.
*
* #RouteResource("acquire-image")
*/
class ApiCfAcquireImageController extends FOSRestController
{
/**
* #var array
*/
public $status;
/**
* #var
*/
public $parameter;
/**
* #var
*/
private $role_name;
/**
* Constructor
*/
public function __construct()
{
}
/**
* Lists all Cf Acquire Image entities.
*
* #param Request $request
*
* #return mixed
*/
public function cgetAction(Request $request)
{
}
/**
* Finds a Cf Acquire Image entity by id.
*
* #param Request $request
* #param $id $id
*
* #return array
*/
public function getAction(Request $request, $id)
{
}
/**
* Create a new Cf Acquire Image entity.
*
* #param Request $request
*
* #return mixed
*/
public function postAction(Request $request)
{
}
/**
* #param Request $request
* #param $id
*
* #return array
*/
public function putAction(Request $request, $id)
{
}
/**
* Deletes a Cf Acquire Image entity.
*
* #param Request $request
* #param $id
*
* #return mixed
*/
public function deleteAction(Request $request, $id)
{
}
}

How to access to Doctrine Document Manager from Doctrine Entity Repository

I have a doctrine entity User and a document Address (stored in mongoDB). I want to set an one to many relation between them by userId property. (the user has many addresses)
My User Entity:
namespace BlaBla\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $firstName;
... and so on
My Address document:
namespace BlaBla\UserBundle\Document;
/**
* BlaBla\UserBundle\Document\Address
*/
class Address
{
/**
* #var MongoId $id
*/
protected $id;
/**
* #var string $firstName
*/
protected $firstName;
/**
* #var string $lastName
*/
protected $lastName;
/**
* #var int $userId
*/
protected $userId;
... and so on
My goal is to create the getUser() method for the Address object and the getAddresses() method for the User object.
I've decided to place the method getAddresses() to the doctrine UserRepository class and to inject there the necessary document manager to be able to access to the Address Document. I've overriden the constructor of the userRepository and passed to it the necessary document manager object.
Please, look to the UserRepository class:
<?php
namespace BlaBla\UserBundle\Repository;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
/**
* #var \Doctrine\ODM\MongoDB\DocumentManager
*/
private $_dm;
/**
* #param \Doctrine\ORM\EntityManager $dm
*/
public function __construct(\Doctrine\ORM\EntityManager $em, $dm) {
$metaData = new \Doctrine\ORM\Mapping\ClassMetadata('BlaBla\UserBundle\Entity\User');
parent::__construct($em, $metaData);
$this->_dm = $dm;
}
/**
* #param $user_id integer
* #return \BlaBla\UserBundle\Document\Address
*/
public function getAddress($user_id) {
$address = $this->_dm->getRepository('BlaBlaUserBundle:Address');
$rt = $address->findByUserId($user_id);
return $rt;
}
public function getAllUsers()
{
return $this->findAll();
}
}
After this I can access to the repository from my controller via:
$em = $this->getDoctrine()->getManager();
$dm = $this->get('doctrine_mongodb')->getManager();
$t = new \BlaBla\UserBundle\Repository\UserRepository($em, $dm);
var_dump($t->getAddress($id));
var_dump($t->getAllUsers());
Both methods work just fine, but now I can't access to the repository using shortcuts like:
$user = $this->getDoctrine()->getRepository('BlaBlaUserBundle:User');
I thought about making the Repository as service with something like this:
user.repository:
class: BlaBla\UserBundle\Repository\UserRepository
arguments: [#doctrine.orm.entity_manager, #doctrine.odm.mongo_db.document_manager]
in my services.yml file, but this only lets me to access the repository with:
$this->get('user.repository');
the default shortcuts doesn't work still.
Please help to find a correct solution for this problem.
Thanks.
Where did you specified the UserRepository? In your User.php with annotation ? Maybe that is the only thing what is missing.
But if you want to use entity and document repository, I advise you to use Doctrine extensions, specifically Reference.

Symfony2 Manager classes and Entity Repositories dependencies

I am currently refactoring bits of a medium sized project and encountered the following. (Bit of pseudo code to simplify the example)
class PostRepository {
}
class PostManager {
/**
* #var PostRepository
*/
private $repository;
public function __construct(PostRepository $repository)
{
$this->repository = $repository;
}
}
class DeletePostCommand {
/**
* #var PostManager
*/
private $postManager;
/**
* #var PostRepository
*/
private $postRepository;
public function __construct(PostManager $postManager, PostRepository $postRepository)
{
$this->postManager = $postManager;
$this->postRepository = $postRepository;
}
}
Should this be refactored? Or is it fine as it is?
Or should I create a getPostRepository function in my PostManager class? Wouldn't that go against the idea of the Single Responsibility Principle?

How to inject non-default entity managers?

In Symfony2 you can work with multiple entity managers and use something like the code below:
$em = $this->get('doctrine')->getManager();
$em = $this->get('doctrine')->getManager('default');
$customerEm = $this->get('doctrine')->getManager('customer');
We can inject the default manager to any service by using:
"#doctrine.orm.entity_manager"
How can you inject non-default entity managers into services?
If your entity managers config name is non_default then you can reference it as #doctrine.orm.non_default_entity_manager
For those who are using Symfony 3+, use the console :
php bin/console debug:container
Then you should see many lines starting with : 'doctrine.orm.MY_CUSTOM_ENTITY_MANAGER_xxxxxxxxxx'
So if you want the entity manager corresponding to your custom entity manager, find the line :
'doctrine.orm.MY_CUSTOM_ENTITY_MANAGER_entity_manager'
You can insert it in your service arguments.
Hope it helps.
You should define your custom entity manager as a service:
services:
name_of_your_custom_manager:
class: %doctrine.orm.entity_manager.class%
factory_service: doctrine
factory_method: getEntityManager
arguments: ["name_of_your_custom_manager"]
Then, you can inject it in the same way as you do with every service:
#name_of_your_custom_manager
Edit:
Pay attention that factory method may differ between symfony's version (it could be getEntityManager or getManager)
Hello first of all create your manager, in my example I create the manager for my Item class that is in a CoreBundle:
<?php
// src/Sybio/Bundle/CoreBundle/Manager/ItemManager.php:
namespace Sybio\Bundle\CoreBundle\Manager;
use Sybio\Bundle\CoreBundle\Entity\Item;
class ItemManager
{
/**
* #var \Doctrine\ORM\EntityManager $em entity manager
*/
protected $em;
/**
* #var \Doctrine\ORM\EntityRepository $em repository
*/
protected $repository;
/**
* #var string $entityName
*/
protected $entityName;
/**
* Constructor
*
* #param EntityManager $em
* #param string $entityName
*
* #return void
*/
public function __construct(EntityManager $em, $entityName)
{
$this->em = $em;
$this->repository = $em->getRepository($entityName);
$this->entityName = $entityName;
}
/**
* Save a entity object
*
* #param Object $entity
*
* #return Object Entity
*/
public function save($entity)
{
$this->persistAndFlush($entity);
return $entity;
}
/**
* Remove a entity object
*
* #param Object $entity
*
* #return Object Entity
*/
public function remove($entity)
{
return $this->removeAndFlush($entity);
}
/**
* Persist object
*
* #param mixed $entity
*
* #return void
*/
protected function persistAndFlush($entity)
{
$this->em->persist($entity);
$this->em->flush();
}
/**
* Remove object
*
* #param mixed $entity entity to remove
*
* #return void
*/
protected function removeAndFlush($entity)
{
$this->em->remove($entity);
$this->em->flush();
}
/**
* Returns entity repository object
*
* #return EntityRepository
*/
public function getRepository()
{
return $this->repository;
}
/**
* Create a new object
*
* #return mixed
*/
public function createNewObject()
{
return new Item();
}
// Create your own methods to manage the object
}
If the manager structure is shared between multiple manager, you can create a BaseManager extended by all other managers !
Then register it in the services.yml (or xml) file of your bundle:
# src/Sybio/Bundle/CoreBundle/Resources/config/services.yml or xml !:
parameters:
# Managers _________________
sybio.item_manager.entity: SybioCoreBundle:Item
sybio.item_manager.class: Sybio\Bundle\CoreBundle\Manager\ItemManager
services:
# Managers _________________
sybio.item_manager:
class: %sybio.item_manager.class%
arguments: [#doctrine.orm.entity_manager, %sybio.item_manager.entity%]
That's it, you can now use it:
// Controller:
$im = $this->get('sybio.item_manager');
$item = $im->createNewObject();
$im->save($item);
You can then improve your manager, here I give an array of config parameters to my manager:
# src/Sybio/Bundle/CoreBundle/Resources/config/services.yml or xml !:
sybio.item_manager:
class: %sybio.item_manager.class%
arguments: [#doctrine.orm.entity_manager, %sybio.item_manager.entity%, {'item_removed_state': %item_removed_state%, 'item_unpublished_state': %item_unpublished_state%, 'item_published_state': %item_published_state%}]
// src/Sybio/Bundle/CoreBundle/Manager/ItemManager.php:
public function __construct(EntityManager $em, $entityName, $params = array()) {
// ...
$this->params = $params;
}
If you create a BaseManager, you can also create a usefull generic method to initialize an object:
// src/Sybio/Bundle/CoreBundle/Manager/BaseManager.php:
/**
* Create a new object
*
* #return mixed
*/
public function createNewObject()
{
$entityName = explode(":", $this->entityName);
$entityName = "Sybio\Bundle\CoreBundle\Entity\\".$entityName[1];
return new $entityName;
}

Resources