Sharing business logic with PHP Doctrine 2

I am using symfony 2.3 and php doctrine 2.

The program has the following models:

  • entity Order - typical sales order
  • BadOrderEntry object (fields: id, order - one-to-one unidirectional communication with Order, createdAt)
  • factory BadOrderEntryFactory for the creation object BadOrderEntry
  • BadOrderEntryRepository repository for BadOrderEntry object search methods
  • BadOrderEntryManager manager for saving / editing / deleting BadOrderEntry entity methods
  • AND THE MAIN CLASS BadOrderList - a list of failed orders, the code of this class:

    private $factory; private $repository; private $manager; public function __construct( BadOrderEntryFactory $f, BadOrderEntryRepository $r, BadOrderEntryManager $m ) { $this->factory = $f; $this->repository = $r; $this->manager = $m; } public function has(Order $order) { return $this->repository->existsByOrder($order); } public function add(Order $order) { if (! $this->has($order)) { $entry = $this->factory->create($order); $this->manager->save($entry); } } public function remove(Order $order) { $entry = $this->repository->findOneByOrder($order); if ($entry !== null) { $this->manager->delete($entry); } } 

I really like the design of this class. I thought a lot about it. Everything is wonderful. BUT! There is one problem: operations in the add and remove methods must be performed in transactions.

The transaction code in PHP Docrine 2 is as follows:

 <?php $em->getConnection()->beginTransaction(); try { //... do some work $em->getConnection()->commit(); } catch (Exception $e) { $em->getConnection()->rollback(); throw $e; } 

But how can I call this code inside a BadOrderList?

I spent a lot of time and deleted depending on the database (and, accordingly, PHP Doctrine 2), and again to create it? The dependency is now hidden in the BadOrderEntryRepository and BadOrderEntryManager classes.

How to hide the dependence on the transaction mechanism in the BadOrderList class?

+7
php orm symfony doctrine2 datamapper
source share
2 answers

After our discussion, I have an answer to your question. Actually, the question is not β€œHow to hide the dependence on the transaction mechanism in the BadOrderList class?”, But how to separate the model from the level of persistence? (Doctrine2 in this particular case).

I tried to illustrate my suggestion with some code

 class BadOrderEntry // Bad - is too bad word to describe an order here. Why is it bad? Is it Declined? Cancelled? { private $order; // some code } class BadOrderEntryFactory { // If there is not to much processing to build BadOrderEntry better use factory method like BadOrderEntry::fromOrder($order); } class BadOrderEntryRepository { // here is some read model } class BadOrderEntryManager // ITS a part of our model and shouldn't be coupled to ORM { public function save(BadEntry $be) { // some model events, model actions $this->doSave($be); // here we should hide our storage manipulation } protected function doSave($be) // it can be abstract, but may contain some basic storage actions { } // similar code for delete/remove and other model code } class ORMBadOrderEntryManager extends BadOrderEntryManager // IT NOT the part of your model. There is no business logic. There is only persistent logic and transaction manipulation { protected $entityManager; // some constructor to inject doctrine entitymanager protected doSave($be) { $em = $this->entityManager; $em->getConnection()->beginTransaction(); // suspend auto-commit try { $em->persist($be); $em->flush(); $em->getConnection()->commit(); } catch (Exception $e) { $em->getConnection()->rollback(); throw $e; } } } // You can also implement ODMBadOrderEntryManager, MemcacheBadOrderEntryManager etc. 

So, if we are talking about the directory structure, your whole model can be moved from the bundle and used anywhere. The Bundle structure will look like this:

 BadEntryBundle | + Entity | | | --- BadOrderEntryEntity.php | + ORM | | | --- ORMBadOrderEntryManager.php 

And then you just enter ORMBadOrderEntryManager in your BadOrderEntryList

+4
source share

You can convert your class as a service and call it however you want after injecting your service container inside your class. You can find more information on dependency injection :

 $injectedContainerOfService->get("id_of_your_service") 
+1
source share

All Articles