Подтвердить что ты не робот

Laravel, Как использовать условия для столбца отношения?

Я использую Laravel и имею небольшую проблему с Eloquent ORM.. Я могу заставить это работать просто с SQL-запросом с помощью JOIN, но я не могу заставить его работать с Eloquent!

Это то, что я хочу, у меня есть две таблицы. один - "Рестораны", а другой - "Restaurant_Facilities".

Таблицы являются простыми.. и отношениями "один-к-одному". например, есть таблица restaurant с id, name, slug и т.д. и другая таблица под названием restaurant_facilities с id, restaurant_id, wifi, parking и т.д.

Теперь то, что я хочу сделать, - это загрузить все рестораны с wifi = 1 или wifi = 0.. Как я могу сделать это с помощью Eloquent? Я старался загружать, сводные таблицы с помощью(), collections(), и ничего не работает!

Та же проблема, что и для отношения "Много-ко-многим" для cuisines! У меня та же таблица restaurant и таблица cuisine и таблица restaurant_cuisine_connection.

но как я могу загрузить все рестораны в определенной кухне с помощью ID?

Это работает.

Cuisine::find(6)->restaurants()->get();

но я хочу загрузить это из ресторана:: модель не из кухонь.. потому что у меня много условий, связанных друг с другом.. ее для поиска и фильтрации/просмотра страницы.

Любые идеи или способы? Я боролся с этим в течение 3 дней и до сих пор не отвечаю.

Примеры моделей:

class Restaurant extends Eloquent {

    protected $table = 'restaurants';

    public function facilities() {
        return $this->hasOne('Facilities'); 
    }
}

class Facilities extends Eloquent {

    protected $table = 'restaurants_facilities';

    public function restaurant() {
        return $this->belongsTo('Restaurant');
    }

}

PS: Кажется, это работает... но это не правильно? Правильно?

Restaurant::leftJoin(
                'cuisine_restaurant', 
                'cuisine_restaurant.restaurant_id', 
                '=', 'restaurants.id'
             )
             ->where('cuisine_id', 16)
               ->get();

И какой лучший способ найти количество ресторанов, которые имеют конкретное значение столбца без другого запроса? как.. я должен найти общее количество ресторанов, у которых есть парковка = 1 и wifi = 1?

Пожалуйста, помогите нам в этом.

Спасибо.

4b9b3361

Ответ 1

Я не вижу ничего плохого в том, чтобы делать левое соединение здесь, если вам нужно загрузить из модели ресторана. Я мог бы отвлечь его до метода на моей модели ресторана, например:

class Restaurant extends Eloquent {
    protected $table = 'restaurants'; // will be default in latest L4 beta

    public function facility()
    {
      return $this->hasOne('Facility');
    }

    // Or, better, make public, and inject instance to controller.
    public static function withWifi()
    {
      return static::leftJoin(
        'restaurant_facilities',
        'restaurants.id', '=', 'restaurant_facilities.restaurant_id'
      )->where('wifi', '=', 1);
    }
}

И затем, с ваших маршрутов:

Route::get('/', function()
{
  return Restaurant::withWifi()->get();
});

В пути - не проверял этот код, но я думаю, он должен работать. Вместо этого вы можете использовать активную загрузку с ограничением, но это будет указывать только, является ли объект объекта нулевым или нет. Он все равно вернет все рестораны, если вы не укажете предложение where.

(P.S. Я придерживаюсь единственной формы Facility. Обратите внимание, что hasOne('Facilities') не читается правильно?)

Ответ 2

Я наткнулся на это сообщение, пытаясь улучшить методологию REST API при создании новой парадигмы обмена. Вы хотите использовать Eager Loading Constraints. Скажем, у вас есть маршрут api, где вы загружаете общий элемент и его коллекцию подэлементов, например:

/api/shared/{share_id}/subitem/{subitem_id}

При нажатии этого маршрута с запросом GET вы хотите загрузить этот конкретный подпункт. Конечно, вы можете просто загрузить эту модель с помощью этого идентификатора, но что, если нам нужно проверить, имеет ли пользователь доступ к этому общему элементу в первую очередь? Один ответ рекомендовал загрузить обратные отношения, но это может привести к запутанному и запутанному контроллеру очень быстро. Использование ограничений для нетерпеливой нагрузки - более "красноречивый" подход. Поэтому мы будем загружать его следующим образом:

$shared = Shared::where('id', $share_id)
  ->with([ 'subitems' => function($query) use ($subitem_id) {
    $query->where('subitem_id', $subitem_id)
  }]);

Итак, где нужен только тот подтип, который имеет этот идентификатор. Теперь мы можем проверить, было ли это обнаружено или нет, выполнив что-то вроде этого:

if ($shared->subitems->isEmpty())

Так как подматрицы представляют собой набор (массив подэлементов), мы возвращаем подпункт [0] следующим образом:

return $shared->subitems[0];

Ответ 3

Используйте whereHas для фильтрации по любым отношениям. Он не присоединится к отношению, но он будет фильтровать текущую модель связанным свойством. Также просмотрите локальные области, чтобы помочь с такими ситуациями https://laravel.com/docs/5.3/eloquent#local-scopes

Ваш пример:

Restaurant::whereHas('facilities', function($query) {
    return $query->where('wifi', true);
})->get();


Restaurant::whereHas('cuisines', function($query) use ($cuisineId) {
    return $query->where('id', $cuisineId);
})->get();

Чтобы добиться того же результата с локальными областями:

class Restaurant extends Eloquent
{
    // Relations here

    public function scopeHasWifi($query)
    {
        return $query->whereHas('facilities', function($query) {
            return $query->where('wifi', true);
        });
    }

    public function scopeHasCuisine($query, $cuisineId)
    {
        return $query->whereHas('cuisines', function($query) use ($cuisineId) {
            return $query->where('id', $cuisineId);
        });
    }
}

Для локальных областей вы НЕ хотите определять их как статические методы в своей модели, так как это создает новый экземпляр построителя запросов и мешает вам связывать методы. Использование локальной области будет вводить и возвращает текущий экземпляр построителя запросов, чтобы вы могли связывать столько областей, сколько хотите:

Restaurant::hasWifi()->hasCuisine(6)->get();

Локальные области определяются с префиксом scope в имени метода и вызываются без scope в имени метода, как в примере abover.

Ответ 4

Другое решение в главной роли whereHas():

$with_wifi = function ($query) {
   $query->where('wifi', 1);
};

Facilities::whereHas('restaurant', $with_wifi)

Приятный и аккуратный.

Ответ 5

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

Facilities::with('restaurant')->where('wifi' ,'=', 0)->get();

Это позволит получить все рестораны, которые соответствуют вашим условиям, и с нетерпением загружать ресторан.

Вы можете связать больше условий и подсчитать общее количество, как это.

Facilities::with('restaurant')
  ->where('wifi' ,'=', 1)
  ->where('parking','=', 1)
  ->count();

Это также будет работать с кухней

Cuisine::with('restaurant')->where('id','=',1)->get();

Это захватывает объект кухни с идентификатором 1, загруженным всеми ресторанами, у которых есть эта кухня.