2012-07-10 24 views
12

Có thể có kho lưu trữ tùy chỉnh không được liên kết với một thực thể trong Symfony 2 và Doctrine 2 không? Tôi muốn đưa vào nó một số SQL bản địa không phù hợp tốt trong các kho lưu trữ khác (nó có thể ám chỉ đến hệ thống phân cấp trừu tượng hoặc thực thể).Có kho lưu trữ tùy chỉnh không được liên kết với một thực thể trong Symfony 2/Doctrine 2?

Làm cách nào để thay thế mã điều khiển $this->getDoctrine()->getRepositoty(/* ??? */)?

Trả lời

13

Có thể có nhiều vị trí lưu trữ như bạn muốn. Tuy nhiên, chỉ có một kho lưu trữ duy nhất có thể được liên kết với trình quản lý thực thể.

Bạn cần xác định một số dịch vụ để thêm kho lưu trữ tùy chỉnh.

<!-- My custom repository --> 
<service id="acme.repository.my_entity" class="Acme\FQCN\MyEntityRepository" > 
    <argument type="service" id="doctrine.orm.entity_manager" /> 
    <argument type="service" id="acme.metadata.my_entity" /> 
</service> 

<!-- MyEntity metadata --> 
<service id="acme.metadata.my_entity" class="Doctrine\ORM\Mapping\ClassMetaData"> 
    <argument>Acme\FQCN\MyEntity</argument> 
</service> 

Lớp lưu trữ sẽ phải kế thừa từ EntityRepository.

namespace Acme\FQCN; 

use Doctrine\ORM\EntityRepository; 

class MyEntityRepository extends EntityRepository 
{ 
    /** 
    * If you want to inject any custom dependencies, you'd have either have to 
    * add them to the construct or create setters. I'd suggest using setters 
    * in which case you wouldn't need to use the constructor in this class. 
    * 
    * public function __construct($em, Doctrine\ORM\Mapping\ClassMetadata $class, $custom_dependency) 
    * { 
    *  parent::__construct($em, $class); 
    * } 
    * 
    */ 
} 

Rất tiếc, bạn sẽ không thể truy lục thông qua dịch vụ học thuyết. Thay vào đó, lấy nó thẳng từ container:

$this->get('acme.repository.my_entity'); 

EDIT

Nếu bạn đang tạo một kho lưu trữ mà không cần phải được liên kết với bất kỳ tổ chức, chỉ cần tạo một dịch vụ và tiêm phụ thuộc cần thiết.

<!-- Repository for misc queries --> 
<service id="acme.repository.misc" class="Acme\FQCN\MiscRepsitory"> 
    <argument type="service" id="database_connection" /> 
</service> 

Vì bạn không sử dụng bất kỳ tính năng ORM nào của Doctrine trong kho tùy chỉnh, không cần phải mở rộng EntityManager.

namespace Acme\FQCN; 

use \Doctrine\DBAL\Connection; 

class MiscRepository 
{ 
    protected $conn; 

    public function __construct(Connection $conn) 
    { 
     $this->conn = $conn; 
    } 
} 
+0

Xin lỗi, tôi có nghĩa là kho lưu trữ không được liên kết với bất kỳ pháp nhân nào. Vì vậy, tại sao điều siêu dữ liệu? – gremo

+0

@Gremo trong trường hợp đó nó sẽ có ý nghĩa để chỉ cần tạo ra một dịch vụ bổ sung và tiêm một kết nối cơ sở dữ liệu chính nó. – gilden

+0

sau khi tiêm database_connection tôi chỉ nên tạo một lớp kế thừa từ EntityRepository, tôi có đúng không? – gremo

1

Đề xuất của tôi là tạo một lớp PHP đơn giản với các phụ thuộc cần thiết trong hàm tạo và nhận nó thông qua vùng chứa dịch vụ.

4

Tôi đã sử dụng một giải pháp hơi khác với các dịch vụ phụ huynh của Symfony2.

Trước hết, tôi tạo một dịch vụ gốc, một lớp GenericRepository hiển thị một vài phương pháp và giúp cuộc sống dễ dàng hơn trong trường hợp chúng tôi muốn cấu trúc lại mã của chúng tôi trong tương lai.

services.yml

acme_core.generic_repository: 
    abstract: true 
    class: Acme\Bundle\CoreBundle\Repository\GenericRepository 
    arguments: [@doctrine.orm.entity_manager] 

Acme\Bundle\CoreBundle\Repository\GenericRepository

<?php 

namespace Acme\Bundle\CoreBundle\Repository; 

use Doctrine\ORM\EntityManager; 

/** 
* Class GenericRepository 
* @package Acme\Bundle\CoreBundle\Repository 
*/ 
abstract class GenericRepository { 
    /** 
    * @var EntityManager 
    */ 
    private $entityManager; 

    /** 
    * @param EntityManager $entityManager 
    */ 
    public function __construct(EntityManager $entityManager) { 
     $this->entityManager = $entityManager; 
    } 

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

    /** 
    * @return \Doctrine\DBAL\Connection 
    */ 
    public function getConnection() { 
     return $this->getEntityManager()->getConnection(); 
    } 

    /** 
    * @return string 
    */ 
    abstract function getTable(); 
} 

Bây giờ chúng ta muốn xác định một kho lưu trữ mới:

services.yml

# Repositories 
acme_product.repository.product_batch: 
    parent: acme_core.generic_repository 
    class: Acme\Bundle\ProductBundle\Repository\ProductBatchRepository 

Acme\Bundle\ProductBundle\Repository\ProductBatchRepository

<?php 

namespace Acme\Bundle\ProductBundle\Repository; 

use Acme\Bundle\CoreBundle\Repository\GenericRepository; 

/** 
* Class ProductBatchRepository 
* @package Acme\Bundle\ProductBundle\Repository 
*/ 
class ProductBatchRepository extends GenericRepository { 
    /** 
    * @param int $batchId 
    * @return integer The number of affected rows. 
    */ 
    public function deleteBatch($batchId) { 
     $table = $this->getTable(); 

     return $this->getConnection()->delete($table, [ 
      'id' => $batchId 
     ]); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function getTable() { 
     return 'product_batch'; 
    } 
} 

Phương pháp deleteBatch() tạo ra và thực hiện các truy vấn sau đây:

DELETE FROM product_batch WHERE id = ?

Cuối cùng trong bộ điều khiển của chúng tôi:

public function deleteAction() { 
    $batchId = $this->getRequest()->get('batchId'); 

    $affectedRows = $this->get('acme_product.repository.product_batch')->deleteBatch($batchId); 

    return $this->render(/**/); 
} 

Để biết thêm thông tin và quản lý thực thể/kết nối cách sử dụng, vui lòng tham khảo tài liệu chính thức: http://doctrine-orm.readthedocs.org/en/latest/reference/native-sql.html

Các vấn đề liên quan