2014-09-07 18 views
8

Tôi đang cố gắng truy cập các đối tượng con của các mối quan hệ lồng nhau trả về nhiều kết quả từ đối tượng cha mẹ.Laravel: Truy vấn và truy cập các đối tượng con trong mối quan hệ lồng nhau với mệnh đề

Hãy nói rằng tôi có 4 mô hình: Quốc gia - Các tỉnh - thành phố - Các đô thị

mối quan hệ của họ như sau:

Nước Mẫu

class Country extends Eloquent 
{ 
    protected $table = 'countries'; 

    public function provinces() 
    { 
     return $this->hasMany('Province'); 
    } 
} 

Tỉnh mẫu

class Province extends Eloquent 
{ 
    protected $table = 'provinces'; 

    public function cities() 
    { 
     return $this->hasMany('City'); 
    } 
    public function country() 
    { 
     return $this->belongsTo('Country'); 
    } 
} 

Thành phố Mẫu

class City extends Eloquent 
{ 
    protected $table = 'cities'; 

    public function municipalities() 
    { 
     return $this->hasMany('Municipality'); 
    } 
    public function province() 
    { 
     return $this->belongsTo('Province'); 
    } 
} 

Municipality Mẫu

class Municipality extends Eloquent 
{ 
    protected $table = 'municipalities'; 

    public function cities() 
    { 
     return $this->belongsTo('City'); 
    } 
} 

Bây giờ những gì tôi đang cố gắng làm là có được tất cả các thành phố trong một quốc gia nhất định có một dân số trên 9000 và được đặt tại các tỉnh được coi là phương Tây.

Cho đến nay tôi có một cái gì đó như thế này:

$country_id = 1; 

    $country = Country::whereHas('provinces', function($query){ 
     $query->where('location', 'West'); 
     $query->whereHas('cities', function($query){ 
      $query->whereHas('municipalities', function($query){ 
       $query->where('population', '>', 9000); 
      });    
     }); 
    })->find($country_id); 

Bây giờ tôi có thể dễ dàng nhận được các tỉnh với $country->provinces nhưng tôi không thể đi bất kỳ sâu hơn thế.

EDIT1: Sửa mối quan hệ phụ thuộc như được chú ý bởi Jarek.

EDIT2: Ngoài câu trả lời của Jarek, tôi muốn chia sẻ những gì tôi cũng tìm thấy tuy nhiên Jarek có lẽ là phương pháp thích hợp hơn.

Thay vì cố gắng đi từ trên xuống dưới (quốc gia -> Municipality) Tôi quyết định thử theo cách khác (Đô thị -> Quốc gia) Đây là cách nó hoạt động (và tôi đã thử nghiệm nó, cũng làm việc)

  $municipalities = Municipality::where('population', '>', 9000) 
      ->whereHas('city', function($q) use ($country_id){ 
       $q->whereHas('province', function($q) use ($country_id){ 
        $q->where('location', 'West'); 
        $q->whereHas('country', function($q) use ($country_id){ 
          $q->where('id', $country_id); 
        }); 
       }); 
      })->get(); 

Tôi không có ý tưởng nếu đây là một cách thích hợp thực tế hoặc nếu hiệu suất sẽ được chấp nhận nhưng nó dường như làm các trick cho tôi tuy nhiên câu trả lời của Jarek trông thanh lịch hơn.

Trả lời

9

Municipality - City có lẽ là belongsTo, không phải hasMany như trong hình dán.

Dù sao bạn có thể sử dụng hasManyThrough liên quan đến truy cập vào bộ sưu tập xa liên quan:

Country - City 
Province - Municipality 

Đáng tiếc là không có mối quan hệ với 3 mức độ làm tổ, vì vậy bạn không thể làm điều này chỉ như thế.


Tiếp theo, mã của bạn với whereHas không giới hạn provinces-westmunicipalities-9000+, nhưng chỉ giới hạn cho những countries, có liên quan đến họ.Trong trường hợp của bạn, điều này có nghĩa là kết quả sẽ là Country (nếu quan hệ của nó khớp với các yêu cầu này) hoặc null nếu không.

Vì vậy, nếu bạn thực sự muốn giới hạn các bộ sưu tập có liên quan, sau đó bạn cần mảnh này:

$country = Country::with(['provinces' => function($query){ 
    $query->where('location', 'West'); 
}, 'provinces.cities.municipalities' => function ($query){ 
    $query->where('population', '>', 9000); 
}])->find($country_id); 

này được áp dụng hạn chế tải háo hức, và những gì nó làm là:

1. loads only West provinces for country with id 1 
2. loads all the cities in these provinces 
3. loads only 9k+ municipalities in these cities 

Vì bạn' không quan tâm đến các thành phố, bạn có thể sử dụng hasManyThrough trên Tỉnh:

// Province model 
public function municipalities() 
{ 
    return $this->hasManyThrough('Municipality', 'City'); 
} 

thì:

$country = Country::with(['provinces' => function($query){ 
    $query->where('location', 'West'); 
}, 'provinces.municipalities' => function ($query){ 
    $query->where('population', '>', 9000); 
}])->find($country_id); 

Tuy nhiên, trong cả hai trường hợp, bạn không thể truy cập vào các đô thị trực tiếp, nhưng chỉ như thế này:

// 1 classic 
$country->provinces->first()->cities->first()->municipalities; 
// 2 hasManyThrough 
$country->provinces->first()->municipalities; 

Điều đó đang được nói, nếu bạn muốn làm việc với tất cả những thành phố này, bạn cần thủ thuật này:

$country = Country::with(['provinces' => function($query){ 
    $query->where('location', 'West'); 
}, 'provinces.municipalities' => function ($query) use (&$municipalities) { 

    // notice $municipalities is passed by reference to the closure 
    // and the $query is executed using ->get() 
    $municipalities = $query->where('population', '>', 9000)->get(); 
}])->find($country_id); 

Điều này sẽ chạy truy vấn bổ sung, nhưng bây giờ tất cả các đô thị nằm trong ingle, bộ sưu tập phẳng, vì vậy nó rất dễ dàng để làm việc với. Nếu không, bạn có thể kết thúc với một loạt các vòng foreach.

+0

Cảm ơn bạn! Đây là những gì tôi đang tìm kiếm nhưng không thể tìm ra. Đồng thời tôi cũng tìm ra một cách khác để làm điều đó và nó đã được lọc dưới lên. Tôi sẽ cập nhật câu hỏi của mình để phản ánh những gì tôi đã tìm thấy. – sholmes

+0

Tôi cũng muốn lưu ý rằng điều thú vị là bạn chỉ có thể đi 3 cấp độ làm tổ và bây giờ tôi biết, tôi có thể làm việc xung quanh điều đó. – sholmes

+1

Có, bạn có thể thực hiện theo cách khác xung quanh bằng cách sử dụng 'whereHas'. Đây là một cách tốt, chỉ phụ thuộc vào nhu cầu của bạn. Dù sao tôi không hiểu ý bạn là gì bởi 3 cấp độ làm tổ? –

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