2013-07-29 41 views
2

隨着推進我們有findOneOrCreate()Symfony2的教義FindOneOrCreate

實施例。

$bookTag = BookTagQuery::create() 
->filterByBook($book) 
->findOneOrCreate(); 

在控制器中的任何地方的教條我們可以做類似的事情。

................... 
     $filename='something'; 
     $document_exists = $em->getRepository('DemoBundle:Document') 
       ->findOneBy(array('filename' => $filename)); 

     if (null === $document_exists) { 
      $document = new Document(); 
      $document->setFilename($filename); 
      $em->persist($document); 
      $em->flush(); 
     }  

是否有另一種方法可以在Doctrine中實現這一點?

可以在Entity Repository中調用實體管理器嗎? 有什麼建議嗎?

回答

0

看看Doctrine\ORM\Repositoryhere的構造函數。

EntityManager是構建存儲庫必需的。管理員可以 - 默認情況下 - 不能直接從存儲庫對象訪問,因爲屬性_em和獲取者函數getEntityManagerprotected

但是...是的,確定通過存儲庫中的_em屬性調用EntityManager是「OK」。所有其他的方法,如findBy,...等藏漢使用它,需要的實體管理器實際工作:)

/** 
* @var EntityManager 
*/ 
protected $_em; 

public function __construct($em, Mapping\ClassMetadata $class) 
{ 
    $this->_entityName = $class->name; 
    $this->_em   = $em; 
    $this->_class  = $class; 
} 

/** 
* @return EntityManager 
*/ 
protected function getEntityManager() 
{ 
    return $this->_em; 
} 

您可以輕鬆地添加一個findOneOrCreate方法來你的實體存儲庫或創建一個通用的擴展庫包括該方法。

然後,只要需要具體實體存儲庫中的方法,您就可以擴展此新的基礎存儲庫。

+0

我在_construct()函數中得到這個錯誤。我必須錯過別的東西? 「可捕獲的致命錯誤:傳遞給Acme \ DemoBundle \ Entity \ DemoFileRepository :: __ construct()的參數2必須是一個Acme \ DemoBundle \ Entity \ Mapping \ ClassMetadata實例,Doctrine \ ORM \ Mapping \ ClassMetadata實例」 – mirk

+0

更改參數鍵入到'ClassMetaData'並添加'use Doctrine \ ORM \ Mapping'語句。否則,它會在您的名字空間中尋找該類。 – althaus

+0

再次出現同樣的錯誤。 – mirk

3

最簡單的方法是擴大基礎庫:

// src/Acme/YourBundle/Entity/YourRepository.php 
namespace Acme\YourBundle\Entity; 

use Doctrine\ORM\EntityRepository; 

class YourRepository extends EntityRepository 
{ 
    public function findOneOrCreate(array $criteria) 
    { 
     $entity = $this->findOneBy($criteria); 

     if (null === $entity) 
     { 
      $entity = new $this->getClassName(); 
      $entity->setTheDataSomehow($criteria); 
      $this->_em->persist($entity); 
      $this->_em->flush(); 
     } 

     return $entity 
    } 
} 

然後告訴你的實體使用這個倉庫,甚至進一步擴大在特定的實體:

// src/Acme/StoreBundle/Entity/Product.php 
namespace Acme\StoreBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity(repositoryClass="Acme\YourBundle\Entity\YourRepository") 
*/ 
class Product 
{ 
    //... 
} 

,並在控制器中使用它:

$em = $this->getDoctrine()->getManager(); 
$product = $em->getRepository('AcmeStoreBundle:Product') 
       ->findOrCreate(array('foo' => 'Bar')); 

來源:http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

只需注意存儲庫中的flush,因爲它會以這種方式刷新EntityManager中所有未保存的更改。

+0

這工作。但是如何能夠像這樣在庫中調用實體管理器。 – mirk

+0

查看@ nifr的評論:存儲庫獲取與實體管理器初始化。它必須有它...否則它不能運行任何查詢。你也可以使用'$ this-> getEntityManager()'而不是直接訪問受保護的變量。 – althaus