2014-07-03 16 views
6

tôi đang làm việc trên Laravel 4. Như tôi biết, tôi có thể làm subquery:Làm thế nào để tùy chỉnh cơ sở dữ liệu Laravel của Query Builder (chắc subquery tốt hơn)

Project::whereIn('project_id', function($q) { 
    $q->select('project_id') 
     ->from('company') 
     ->whereNull('deleted_at'); 
}); 

tôi thấy biến chứng, mà tôi có thể' t sử dụng phạm vi trong truy vấn phụ và vô hiệu hóa soft_delete làm cho tôi thay đổi mã nguồn rất nhiều.

Tôi muốn nó là:

Project::whereIn('project_id', function(&$q) { 
    $q = Company::select('project_id')->getQuery(); 
}); 

Bây giờ, tôi có thể thêm phạm vi, vô hiệu hóa soft_delete dễ dàng.

tôi đã cố gắng, và tìm thấy một giải pháp, mà tôi phải thay đổi mã Laravel của Cơ sở dữ liệu \ Query \ Builder, chức năng whereInSub, dòng 786.

call_user_func($callback, $query = $this->newQuery()); 

tới:

$query = $this->newQuery(); 
call_user_func_array($callback, array(&$query)); 

Đó là có hại cho sửa đổi Nhà cung cấp khung của Laravel. Vì vậy, tôi muốn hỏi làm thế nào để làm điều đó một cách an toàn.

Xin lỗi vì tiếng Anh xấu của tôi.

Cảm ơn bạn đã đọc.

Trả lời

12

Oooh! Điều này khá phức tạp vì mô hình của bạn sẽ mở rộng Eloquent, sau đó Eloquent sử dụng Illuminate\Database\Query\Builder.

Nhưng điều tôi nhận thấy là Eloquent thực sự là một bí danh trong tệp app/config/app.php. Vì vậy, những gì bạn có thể làm là làm theo các bước sau.

  1. Mở rộng Illuminate\Database\Query\Builder đến MyQueryBuilder với tùy chỉnh whereInSub().
  2. Kéo dài Illuminate\Database\Eloquent\Model đến MyModel và đặt thành useMyQueryBuilder của bạn.
  3. Đặt Eloquent bí danh trong app/config/app.php thành lớp mới MyModel của bạn.

Something như thế này:

MyQueryBuilder.php:

use Closure; 
use Illuminate\Support\Collection; 
use Illuminate\Database\ConnectionInterface; 
use Illuminate\Database\Query\Grammars\Grammar; 
use Illuminate\Database\Query\Processors\Processor; 

class MyQueryBuilder extends Illuminate\Database\Query\Builder 
{ 
    protected function whereInSub($column, Closure $callback, $boolean, $not) 
    { 
     $type = $not ? 'NotInSub' : 'InSub'; 

     $query = $this->newQuery(); // Your changes 
     call_user_func_array($callback, array(&$query)); // Your changes 

     $this->wheres[] = compact('type', 'column', 'query', 'boolean'); 

     $this->mergeBindings($query); 

     return $this; 
    } 
} 

MyModel.php:

use DateTime; 
use ArrayAccess; 
use Carbon\Carbon; 
use LogicException; 
use Illuminate\Events\Dispatcher; 
use Illuminate\Database\Eloquent\Relations\Pivot; 
use Illuminate\Database\Eloquent\Relations\HasOne; 
use Illuminate\Database\Eloquent\Relations\HasMany; 
use Illuminate\Database\Eloquent\Relations\MorphTo; 
use Illuminate\Support\Contracts\JsonableInterface; 
use Illuminate\Support\Contracts\ArrayableInterface; 
use Illuminate\Database\Eloquent\Relations\Relation; 
use Illuminate\Database\Eloquent\Relations\MorphOne; 
use Illuminate\Database\Eloquent\Relations\MorphMany; 
use Illuminate\Database\Eloquent\Relations\BelongsTo; 
// use Illuminate\Database\Query\Builder as QueryBuilder; 
use Illuminate\Database\Eloquent\Relations\MorphToMany; 
use Illuminate\Database\Eloquent\Relations\BelongsToMany; 
use Illuminate\Database\Eloquent\Relations\HasManyThrough; 
use Illuminate\Database\ConnectionResolverInterface as Resolver; 
use MyQueryBuilder as QueryBuilder; // MyModel should now use your MyQueryBuilder instead of the default which I commented out above 

abstract class MyModel extends Illuminate\Database\Eloquent\Model 
{ 

} 

app/config/app.php:

'aliases' => array(
    ... 
    'Eloquent'  => 'MyModel', 
    ... 
); 

Lưu ý rằng tôi đặt danh sách dài use lên đó vì "use" keyword does not get inherited. Ngoài ra tôi đã không đặt MyQueryBuilderMyModel vào một không gian tên vì mục đích đơn giản. Danh sách use của tôi cũng có thể khác với danh sách của bạn tùy thuộc vào phiên bản Laravel mà chúng tôi sử dụng, vì vậy hãy kiểm tra việc sử dụng.

+4

Tôi đã chỉnh sửa câu hỏi của mình vì tôi đã tìm thấy giải pháp. Cần ghi đè hàm được bảo vệ newBaseQueryBuilder() trong lớp mới MyModel –

+0

Không cần bao gồm danh sách "sử dụng" trừ khi bạn thực sự ... sử dụng chúng trong lớp con của bạn. Trong trường hợp này, bạn chỉ cần MyQueryBuilder của bạn, cái mà sẽ được sử dụng trong phiên bản mới của newBaseQueryBuilder() như @ LêTrầnTiếnTrung được chỉ ra một cách chính xác. – LePhleg

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