2015-01-04 3 views
7

내가 심포니 2.3과 PHP의 교리 프로그램은 다음과 같은 모델이 2분리 비즈니스 로직 PHP 교리 2

사용에서 :

  • 단체 주문 - 일반 고객 주문
  • 엔티티 BadOrderEntry을 (필드 : ID, 순서 - 주문과 단방향 일대일 관계, createdAt) 생성 엔티티 BadOrderEntry
  • 저장소 BadOrderEntryReposi에 대한
  • 공장 BadOrderEntryFactory

    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); 
        } 
    } 
    
: 나쁜 주문 목록,이 클래스의 코드 - BadOrderEntry
  • 및 메인 클래스 BadOrderList을/편집/저장 엔티티의 방법을 삭제

  • 관리자 BadOrderEntryManager에 대한 개체의 검색 방법에 대한 토리 BadOrderEntry
  • 나는이 클래스의 디자인이 정말 마음에 듭니다. 나는 그것에 대해 많이 생각했다. 모든 것이 훌륭합니다. 그러나! 한 가지 문제가 있습니다. 메소드에서 추가 및 제거 작업을 트랜잭션에서 수행해야합니다. 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

    이 delete'I은 또한 당신이 다시 생각하는 것이 좋습니다'당신'관리자 : add'에 트랜잭션 관리를 추가하고

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

    그리고 당신은 당신의 BadOrderEntryList에 ORMBadOrderEntryManager를 주입 것이다 당신의 디자인. 정말 좋지 않아. 모델을 독립적으로 유지하십시오. – Ziumin

    +0

    @ Ziumin Manager에 트랜잭션 관리를 추가하려면 어떻게해야합니까 :: 추가 (삭제)합니까? 어떤 디자인 문제입니까? 관리자는 단순히 교리 객체 관리자에 대한 추상화의 추가 계층입니다. 나쁘지도 않고 좋지도 않습니다. 그러나 더 많은 통제력을 제공합니다. – stalxed

    +0

    예제에서 언급 한 것과 같은 방법으로이를 수행 할 수 있습니다. http://doctrine-orm.readthedocs.org/en/latest/reference/transactions-and-concurrency.html#approach-2-explicitly. 디자인 문제 - 왜 당신의 목록이 MAIN 객체라고 생각하십니까? 당신의 건축의 주요 부분은 무엇입니까? 방법과 클래스 이름에 대해 생각해 보셨습니까? 교리없이 모델 전체를 테스트해볼 수 있습니까? – Ziumin

    답변

    4

    을 나는 당신의 질문에 대한 답변을 가지고있다. 질문은 실제로는 없습니다 "BadOrderList 클래스의 트랜잭션 메커니즘에 대한 의존성을 숨기는 방법은 무엇입니까?",하지만 지속성 레이어에서 모델을 분리하는 방법은 무엇입니까? (해당 경우 Doctrine2).

    나는 우리가 모든 모델에 번들 밖으로 이동 어디서나 사용할 수 있습니다, 디렉토리 구조에 대해 이야기하는 경우

    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. 
    

    그래서 몇 가지 코드 내 제안을 설명했습니다. 번들 구조는 같을 것입니다 :

    +0

    이것은 정말 멋진 해결책입니다! JMSPaymentCoreBundle에서 비슷한 솔루션을 보았습니다. 하지만 그걸 생각하지 않았어요 ... 당신은 내 눈을 열었습니다! 정말 고맙습니다! – stalxed

    1

    클래스를 서비스로 변형하고 클래스 내에 서비스 컨테이너를 삽입 한 후 원하는대로 호출 할 수 있습니다. 여기에 대한 dependency injection 자세한 정보를 찾을 수 있습니다 : 우리의 토론 후

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

    Thx. 그것은 매우 간단하고 분명한 해결책입니다. 그러나 실용적이지 않고 테스트 할 수있는/유지할 수있는 것이 아닙니다. – Ziumin

    +0

    실용적이고 테스트 가능하지만 컨트롤러를 분리하고 테스트하려는 경우 컨트롤러를 서비스로 변형해야합니다. – lsroudi

    +0

    컨트롤러는 어디에서 볼 수 있습니까? – Ziumin