2012-02-08 34 views
15

Giả sử tôi có hai bảng trong cơ sở dữ liệu của tôi: Thỏ và Cà rốt. Thỏ có thể có 0 hoặc bội số cà rốt và cà rốt thuộc về một con thỏ. Đó là mối quan hệ 1, n giữa hai bảng đó.Symfony2 - Truy cập chức năng kho lưu trữ trong Entity

Tôi có hai thực thể, thỏ và cà rốt.

Tôi có một loạt thỏ được truyền trong mẫu của tôi và tôi muốn lấy cà rốt cụ thể từ mỗi con thỏ trưng bày chúng: giả sử tôi muốn mua 10 củ cà rốt đắt hơn (giá cà rốt sẽ được lưu trữ trong bàn cà rốt) từ mỗi con thỏ $ trong mảng.

Cái gì như:

{% for rabbit in rabbits %} 
    {% for carrot in rabbit.getMoreExpensiveCarrots %} 

     {{ carrot.price }} 

    {% endfor %} 
{% endfor %} 

Tôi đang sử dụng lớp kho, nhưng nếu tôi tạo một hàm getMoreExpensiveCarrots ($ thỏ) trong một lớp kho thỏ, tôi sẽ không thể truy cập vào chức năng đó từ một thực thể lớp như vậy, đó là những gì tôi muốn:

$ rabbit-> getMoreExpensiveCarrots()

tôi nghĩ rằng một cách để làm điều đó sẽ tạo ra một getMoreExpensiveCarrots() trong thực thể thỏ:

// Entity rabbit 
class Rabbit 
{ 
    public function getMoreExpensiveCarrots() 
    { 
     // Access repository functions like getMoreExpensiveCarrots($rabbit) 
     // But how can I do such thing ? Isn't that bad practise ? 
     return $carrots; 
    }   
} 

Tôi nghĩ tôi có thể làm điều đó quá:

// Entity rabbit 
    class Rabbit 
    { 
     public function getMoreExpensiveCarrots() 
     { 
      $this->getCarrots(); 

      // Then try here to sort the carrots by their price, using php    

      return $carrots; 
     }   
    } 

Đây là bộ điều khiển của tôi:

public function indexAction() 
    { 
     $em = $this->getDoctrine()->getEntityManager(); 

     $rabbits = $em->getRepository('AppNameBundle:Rabbit')->getSomeRabbits(); 

     return $this->render('AppNameBundle:Home:index.html.twig', 
       array(
        "rabbits"=>$rabbits 
     )); 
    } 

thực hành tốt nhất để gọi một hàm getMoreExpensiveCarrots từ mỗi con thỏ trong mẫu là gì?

Cảm ơn!

+4

Tôi thích món thỏ và cà rốt này.<3 –

Trả lời

8

Quay lại vấn đề cơ bản. Quên về kho lưu trữ vs dịch vụ và chỉ tập trung vào thỏ và cà rốt.

class Rabbit 
{ 
/** @ORM\OneToMany(targetEntity="Carrot", mappedBy="rabbit" */ 
protected $carrots; 

public function getCarrots() { return $this->carrots; } 

public function getMoreExpensiveCarrots() 
{ 
    // Get all carrots 
    $carrots = $this->getCarrots()->toArray(); 

    // Sort by price 
    // http://php.net/manual/en/function.usort.php 
    usort(&$carrots,array($this,'compareTwoCarrotsByPrice')); 

    // Now slice off the top 10 carrots (slice - carrots, hah, kindo of funny 
    $carrots = array_slice($carrots, 0, 10); 

    // And return the sorted carrots 
    return $carrots; 
} 
public function compareTwoCarrotsByPrice($carrot1,$carrot2) 
{ 
    if ($carrot1->getPrice() > $carrot2->getPrice()) return -1; 
    if ($carrot1->getPrice() < $carrot2->getPrice()) return 1; 
    return 0; 
} 
} 

Xóa tất cả các thứ cà rốt khỏi truy vấn của bạn và chỉ nhận danh sách thỏ.
mẫu ban đầu của bạn bây giờ sẽ làm việc chính xác như mong đợi:

{% for rabbit in rabbits %} 
    {% for carrot in rabbit.getMoreExpensiveCarrots %} 

     {{ carrot.price }} 

    {% endfor %} 
{% endfor %} 

Nhược điểm duy nhất ở đây là cho mỗi thỏ, một truy vấn riêng biệt cho tất cả cà rốt sẽ được tự động tạo ra bởi Doctrine. Tại một số điểm hiệu suất sẽ bị cản trở. Khi bạn đạt đến điểm đó thì bạn có thể quay lại truy vấn ban đầu của mình và xem cách mang cà rốt hiệu quả hơn. Nhưng có được lớp trên làm việc đầu tiên vì tôi nghĩ rằng đây có thể là điểm chặn của bạn.

+0

Cảm ơn! Vì $ this-> getCarrots() ouputs một ArrayCollection, tôi nhận được một "usort() hy vọng tham số 1 là mảng, đối tượng được đưa ra" ... Tôi sẽ cố gắng gỡ lỗi đó. – httpete

+1

Loại ngạc nhiên khi usort không thể xử lý một Iterator triển khai onject. Trong mọi trường hợp: $ carrots = $ this-> getCarrots() -> toArray(); – Cerad

+0

oh người đàn ông, nó cuối cùng là làm việc \ o/Cảm ơn bạn rất nhiều :) – httpete

7

Các lớp thực thể của bạn chỉ nên quan tâm đến đối tượng mà chúng đại diện và hoàn toàn không có kiến ​​thức về người quản lý thực thể hoặc kho lưu trữ.

Một giải pháp khả thi ở đây là sử dụng đối tượng dịch vụ (RabbitService) có chứa phương pháp getMoreExpensiveCarrots. Dịch vụ được phép biết về người quản lý thực thể và các kho lưu trữ, do đó, ở đây bạn thực hiện bất kỳ hoạt động phức tạp nào.

Bằng cách sử dụng đối tượng dịch vụ, bạn duy trì sự tách biệt các mối quan ngại và đảm bảo rằng các lớp thực thể của bạn thực hiện công việc mà chúng có ý nghĩa và không có gì khác.

Bạn cũng có thể sử dụng tùy chọn thứ hai, giả sử cà rốt được lưu trữ trong ArrayCollection. Bạn chỉ cần thực hiện bất kỳ logic sắp xếp nào bạn cần trong phương thức. Điều này sẽ ổn vì bạn sẽ hoạt động trên dữ liệu được cung cấp cho thực thể.

+0

Sau đó, tôi sẽ gọi dịch vụ đó từ Thỏ Thực thể của tôi? – httpete

+0

Bạn sẽ gọi riêng dịch vụ, như từ bộ điều khiển. –

+1

Tôi xin lỗi, tôi là người mới bắt đầu và tôi không hoàn toàn hiểu sự khác biệt giữa kho và dịch vụ trong trường hợp này vì tôi phải gọi nó từ bộ điều khiển: (Tôi không muốn gọi getMoreExpensiveCarrots từ bộ điều khiển của mình, nhưng từ mỗi con thỏ $ trong mẫu của tôi Thực ra trong bộ điều khiển của tôi, đó là những gì tôi làm để có được thỏ của mình: $ thỏ = $ em-> getRepository ('AppNameBundle: Rabbit') -> getSomeRabbits(); Bây giờ nên Tôi gọi getMoreExpensiveCarrots của dịch vụ? – httpete

7

Hãy để tôi chụp ảnh giải thích. Doctrine 2 ORM yêu cầu một chút suy nghĩ lại. Bạn hiện có suy nghĩ rằng một con thỏ sẽ có thể truy vấn nó là cà rốt bất cứ khi nào nó cần chúng. Bạn cần phải thay đổi suy nghĩ đó.

Đối với Giáo lý 2, ý tưởng là cung cấp cho thỏ cà rốt của họ ngay khi bạn tạo thỏ. Nói cách khác, nó được thực hiện tại thời điểm truy vấn. Giả định là bất cứ quá trình nào truy vấn cơ sở dữ liệu cho thỏ đều biết rằng bạn cũng muốn có một bộ cà rốt cụ thể.

Trong trường hợp này, bạn muốn có 10 củ cà rốt đắt nhất nên quy trình của bạn cần phải biết điều đó. Vì vậy, bây giờ bạn quay trở lại @Arms trả lời và làm cho mình một dịch vụ RabbitManager với một phương pháp gọi là loadRabbitsWithExpensiveCarrots. Giá trị trả về sẽ là một mảng thỏ với cà rốt của chúng đã được điền sẵn.

Cập nhật địa chỉ này để giải quyết các nhận xét.

  1. thuyết 2 Repository vs Symfony 2 Dịch vụ

một kho lưu trữ có xu hướng tập trung vào một loại thực thể ví dụ một Repository Rabbit được sử dụng tốt nhất khi chỉ đối phó với Thỏ. Khi bạn bắt đầu gặp phải các yêu cầu phức tạp hơn đòi hỏi nhiều loại thực thể, nó có thể bắt đầu trở nên khó khăn để xác định kho lưu trữ nào có chức năng nhất định. Chương trình ứng dụng (bộ điều khiển) của bạn sẽ phải biết kho lưu trữ nào mang vào và có lẽ nhiều thông tin hơn về nội dung thực sự cần biết.

Dịch vụ Symfony 2 ẩn tất cả chi tiết về cách thức tổ chức thỏ và cà rốt của bạn. Đó là một khái niệm tổng quát hơn và có thể xử lý các loại truy vấn phức tạp hơn liên quan đến nhiều thực thể. Đó là một khối xây dựng cơ bản của S2 và bạn thực sự cần phải thoải mái với nó.

Đối với yêu cầu hiện tại của bạn, một trong hai cách tiếp cận sẽ hoạt động.

  1. Cà rốt param câu hỏi

Vẫn không chắc chắn chính xác những gì bạn muốn nói. Có lẽ bạn có thể đăng truy vấn mẫu? Hãy nhớ rằng bạn chắc chắn có thể thêm phương thức getExpensiveCarrots() vào đối tượng thỏ của bạn. Phương thức sẽ bắt đầu gọi getCarrots(). Cà rốt trở lại sẽ được tải bởi truy vấn ban đầu. Phương pháp của bạn sẽ lọc và sắp xếp.

Và hãy nhớ rằng chúng tôi đang cố gắng giải quyết trường hợp thỏ có thể có hàng trăm hoặc hàng nghìn cà rốt gắn liền với nó. Vì vậy, chúng tôi đang cố gắng tránh tải tất cả cà rốt chỉ để xem xét hiệu suất. Nó có thể dễ dàng hơn để bắt đầu bằng cách không tải cà rốt ở tất cả trong truy vấn ban đầu. Thay vào đó, lần đầu tiên thỏ của bạn- getCarrots() được gọi, Doctrine 2 sẽ tự động đưa ra một truy vấn và tải tất cả cà rốt cho con thỏ đó. Và sau đó một lần nữa phương thức getExpensiveCarrots của bạn sẽ lọc và sắp xếp nếu cần.

Hy vọng trợ giúp này. Có lẽ chỉ làm bạn bối rối hơn nữa.

+0

Được rồi, cảm ơn vì sự giúp đỡ, bây giờ tôi đã hiểu rõ hơn về cách nó có thể hoạt động. Nhưng tôi vẫn không thể quản lý theo nghĩa đen để nó hoạt động được;) Điều gì sẽ là sự khác biệt giữa việc thực hiện một chức năng trong kho chứa thỏ loadRabbitsWithExpensiveCarrots ($ thỏ = $ em-> getRepository ('AppNameBundle: Rabbit') -> loadRabbitsWithExpensiveCarrots();) và sử dụng một dịch vụ để làm điều tương tự? Plus Tôi sẽ không thể thực hiện truy vấn để truy xuất con thỏ của tôi được sắp xếp theo thông số và trong cùng một thời gian để cà rốt theo giá. – httpete

+0

Tôi đã thêm câu trả lời cho bạn :) http://stackoverflow.com/a/9251217/668157 – httpete

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