Reputation: 147
I registered my services.yml file like this :
services:
bb_shop.product_repository:
class: BB\ShopBundle\Entity\ProductRepository
factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository
arguments: ['BBShopBundle:Product']
bb_shop.product_service:
class: BB\ShopBundle\Service\ProductService
arguments: [@bb_shop.product_repository]
This is my Repository Class :
class ProductRepository extends EntityRepository
{
public function saveProduct( $p)
{
$this->_em->persist($p);
$this->_em->flush();
}
}
This My Service Class :
class ProductService {
protected $productRepository;
public function __construct(ProductRepository $R)
{
$this->productRepository =$R;
}
public function saveProduct( $p)
{
$this->productRepository->saveProduct($p);
}
}
And this is how i call my service in the Controller :
$this->get('bb_shop.product_service')->saveProduct($product);
And All work. my questions are : 1- Can you explain to me why i need this 2 lines even i have the EntityManager in the EntityRepository ( used by $this->_em ) ???
factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository
2 - Is this the good way to do dependency injection ???
Upvotes: 1
Views: 104
Reputation: 48883
You need the two lines because the repository does not extend the entity manager. So basically you are passing persist/flush onto the entity manager. This avoids the need to expose the entity manager to your service. You could inject the manager and call persist/flush directly but really why bother.
I use your approach all the time. So it must be great. As of yet I have not encountered any serious problems.
You should be aware of the side effect of calling saveProduct. As it stands, your save product flushes the entity manager so you end up saving/updating any entities (not just the specific product) that might have changed since all repositories share the same manager.
This has not been a problem for me. Just something to be aware of. If your modifying multiple products within a single request then you might want to break apart your persist and flush. The way all of your changes will be added to the database in one shot.
class ProductRepository
{
public function persist($product) { return $this->_em->persist($product); }
public function flush($product) { return $this->_em->flush(); }
One more for reason for this approach is that it allows you to swap out the repository for testing. I have yaml based repositories which load some entities from a yaml file. The repositories expose simple find/findAll methods making it easy to write test functions. And who knows, someday you may decide to switch to something other than Doctrine 2.
I use a base repository class:
use Doctrine\ORM\EntityRepository as BaseRepository;
class EntityRepository extends BaseRepository
{
// Create main entity
public function createEntity($params = array())
{
$entityName = $this->getEntityName();
return new $entityName($params);
}
// Allow null for id
public function find($id)
{
return $id ? parent::find($id) : null;
}
/* ==========================================================
* Persistence
*/
public function persist($entity) { return $this->getEntityManager()->persist($entity); }
public function refresh($entity) { return $this->getEntityManager()->refresh($entity); }
public function detach ($entity) { return $this->getEntityManager()->detach ($entity); }
public function remove ($entity) { return $this->getEntityManager()->remove ($entity); }
public function flush() { return $this->getEntityManager()->flush(); }
public function clear() { return $this->getEntityManager()->clear();
public function getReference($id) { return $this->getEntityManager()->getReference($this->getEntityName(),$id); }
Upvotes: 0