2015-01-04 88 views
7

我使用symfony的2.3和PHP學說2.分離業務邏輯從PHP學說2

該方案具有以下型號:

  • 實體訂單 - 一個典型的客戶訂單
  • 實體BadOrderEntry(場:id,訂單 - 與訂單的單向一對一關係,createdAt)
  • 工廠BadOrderEntryFactory用於創建實體BadOrderEntry
  • 存儲庫BadOrderEntryReposi保守黨對實體的搜索方法BadOrderEntry
  • 經理BadOrderEntryManager用於保存/編輯/刪除實體的方法BadOrderEntry
  • 和主類BadOrderList - 壞的訂單列表中,這個類的代碼:

    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); 
        } 
    } 
    

我很喜歡這門課的設計。我想了很多。 一切都很美妙。但!有一個問題:必須在事務中執行方法添加和刪除操作。在PHP Docrine 2

事務代碼看起來是這樣的:

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

但我怎麼能叫內BadOrderList這個代碼?

我花了很多時間和取決於數據庫(和相應的PHP Doctrine 2),並再次創建它? 現在依賴關係被隱藏在類BadOrderEntryRepository和BadOrderEntryManager中。

如何在類BadOrderList中隱藏對事務機制的依賴?

+0

添加事務管理你的'經理:: add'和'delete'I也建議你重新考慮你的設計。這不是很好。讓你的模型持久獨立。 – Ziumin 2015-01-04 14:37:51

+0

@Ziumin如何將事務管理添加到Manager :: add(或刪除)?什麼設計問題?經理對於學科對象管理器只是一個額外的抽象層。這並不壞,它不好。但提供更多控制權。 – stalxed 2015-01-04 14:52:04

+0

您可以按照您在示例中提到的相同方式進行操作。 http://doctrine-orm.readthedocs.org/en/latest/reference/transactions-and-concurrency.html#approach-2-explicitly。至於設計問題 - 爲什麼你認爲你的清單是主要對象。主要是你的建築部分?你有沒有想過方法和類名?你能否在沒有教條的情況下測試整個模型? – Ziumin 2015-01-04 15:28:54

回答

4

我們的討論後,我有一個回答你的問題。 問題真的不是「如何在類BadOrderList中隱藏對事務機制的依賴?」,但是如何從持久層分離模型?(該特例中的學說2)。

我想說明我的建議有一些代碼

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'S 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. 

所以,如果我們談論的目錄結構,所有的模型可以被移出束和任何地方使用。你的包結構將是這樣的:

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

然後你只注入ORMBadOrderEntryManager您BadOrderEntryList

+0

這真是一個很酷的解決方案!我在JMSPaymentCoreBundle中看到過類似的解決方案。但是沒有想到......你睜開眼睛!非常感謝! – stalxed 2015-01-04 18:35:45

1

您可以將您的類作爲服務進行轉換,然後在您的類內部注入服務容器後調用它。 您可以在這裏瞭解dependency injection找到更多的信息:

$injectedContainerOfService->get("id_of_your_service") 
+0

Thx。這是非常簡單明瞭的解決方案。但不實用/可測試/可維護的。 – Ziumin 2015-01-04 16:12:01

+0

它的實踐和可測試,但是如果你想測試它,你應該分離你的控制器並將其轉換爲服務 – lsroudi 2015-01-04 16:14:20

+0

你在哪裏看到控制器? – Ziumin 2015-01-04 16:19:42