2015-01-17 5 views
0

У меня есть 2 стола: users и articles. users таблицы содержит столбец с именем is_suspendedyes, который принимает или no и articles таблицы содержит столбец с именем is_published, который принимает 0 или 1. Чтобы получить данные из базы данных, articles.is_published должен равняться 1, а users.is_suspended должен равняться no. Теперь предположим, что users.is_suspended равен yes, если я пытаюсь получить данные о статье с помощью Query Builder, как это:Laravel's Eloquent ORM против Query Builder

// first code: 

    $articles = Article::join('users', 'articles.user_id', '=', 'users.user_id') 
     ->select(['articles.*', 'users.user_name', 'users.user_email']) 
     ->where('articles.article_id', '=', 9) 
     ->where('articles.is_published', '=', 1) 
     ->where('users.is_suspended', '=', 'no') 
     ->get(); 

Это будет прекрасно работать и не будет возвращать ничего (потому что users.is_suspended = yes). Теперь давайте попробуем извлечь ту же статью с Laravel красноречивый ОРМ, как это:

// second code: 

$articles = Article::with([ 
    'user' => function($query) { 
     $query->select(['user_id', 'user_name', 'user_email']) 
      ->where('users.is_suspended', '=', 'no'); 
    }]) 
    ->where('articles.article_id', '=', 9) 
    ->where('articles.is_published', '=', 1) 
    ->get(); 

В этом случае я получаю следующий результат:

[ 
    { 
    article_id: 9, 
    user_id: 1, 
    article_title: "Article title here", 
    article_body: "Article body here", 
    is_published: 1, 
    created_at: "2015-01-17 02:26:24", 
    updated_at: "2015-01-17 02:26:24", 
    user: null 
    } 
] 

он будет получать данные статьи, даже если пользователь приостановлено, что неверно. Итак, мой вопрос заключается в том, как исправить второй код, как первый код?

ответ

2

Возможно, вы захотите использовать with, чтобы убедиться, что вы ленивые отношения нагрузки, но любые ограничения, которые вы наложили на него, применимы только к загруженным отношениям. Чтобы ограничить ответ на статьи, в которых пользователь не заблокирован, вы должны использовать метод whereHas.

$articles = Article::with(['user' => function($q){ 
     $q->select(['user_id', 'user_name', 'user_email', 'created_at']); 
    }]) 
    ->whereHas('user', function($q) { 
     $q->where('is_suspended', '=', 'no'); 
    }) 
    ->where('articles.article_id', '=', 9) 
    ->where('articles.is_published', '=', 1) 
    ->get(); 
+0

Это замечательно. Но как я могу выбрать конкретные столбцы и где я должен поместить: select (['user_id', 'user_name', 'user_email']). Я попытался сделать это следующим образом: $ q-> select (['user_id', 'user_name', 'user_email', 'created_at']) -> где ('is_suspended', '=', 'no'); но это вызывает ошибку: (Нарушение кардинальности: 1241 Операнд должен содержать 4 столбца). – Amr

+0

Добавил его для вас, вы положили его там, где у вас это было, в обратном вызове методов 'with'. –

+0

Он вызывает ошибку: explode() ожидает, что параметр 2 будет строкой, указанным объектом. – Amr

0

Вам нужно whereHas вместо with (или оба, но нет необходимости в with в данном случае), как сказал @DavidBarker.

Однако я предлагаю больше, рассмотреть читаемость этого кода:

$article = Article::whereHas('user', function ($q) { 
    $q->active(); 
})->published()->find(9); 

Это делает использование scopes.

Так вот что вы можете сделать, чтобы сделать вашу жизнь проще:

  1. Изменение is_suspended в bool, потому что:

    $user->is_suspended; // no 
    (bool) $user->is_suspended; // true  
    
  2. Определение SCOPES suspended на User модели и published на Article:

    // Article model - on User accordingly 
    public function scopePublished($query) 
    { 
        $query->where('is_published', 1); 
    } 
    
  3. Если вы хотите получить одну модель, используйте find($id) или where('col', $id)->first() вместо get, потому что последняя вернет коллекцию, хотя есть один результат.

Смежные вопросы