Вложенные отношения запросов в laravel 5.6

Привет, ребята, мне нужно спросить о глубоких отношениях ...

Моя модель store

<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class Store extends Model
{
    protected $table = 'stores';

    public function address(){

        return $this->morphOne('App\Model\Address', 'addressable');
    }

}

Моя модель Address

class Address extends Model
{
    protected $table = 'address';
    protected $fillable = [
        'province_id',
        'city_id',
        'brgy_id',
        'street_lot_blk',
        'longitude',
        'latitude'
    ];

    public function addressable(){

         return $this->morphTo();
    }

    public function province(){

        return $this->hasOne('App\Model\Province', 'id', 'province_id');
    }

    public function city(){

        return $this->hasOne('App\Model\City', 'id', 'city_id');
    }

     public function brgy(){

        return $this->hasOne('App\Model\Brgy', 'id', 'brgy_id');
    }
}

Моя модель province

<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class Province extends Model
{

    protected $table = 'refprovince';
}

Мой запрос

$request = app()->make('request');

        return response()->json([
                'stores' => Store::where('name', 'LIKE', '%'. $request->name . '%')
                    ->with(['address.province', 'address.city', 'address.brgy'])
                    ->take(10)->get()
            ]);

result см. Прилагаемое фото

enter image description here

Проблема в том, что если пользователь вводит имя магазина, он вернет только имя магазина, а если пользователь введет «Camarines», он вернет только тот магазин, у которого есть слово «Camarines» в провинции.

Мой код выглядит так ... но он не работает.

 $results = Store::where('name', 'LIKE', '%'. $request->name . '%')
                    ->with(['address.province' => function($query) use ($request) {

                        $query->where('provDesc', 'LIKE', '%'. $request->name . '%');

                    }])
                    ->take(10)->get();

        return response()->json([
                'stores' => $results
            ]);

Я не знаю, возможно ли это, просто скажите мне, чтобы я мог реструктурировать свою базу данных. TY

Обновления: все еще не работает с этим кодом.

$request = app()->make('request');

         $stores = Store::where('name', 'LIKE', "%{$request->name}%")
        ->orWhereHas('address.province', function ($query) use ($request) {
            $query->where('provDesc', 'LIKE', "%{$request->name}%");
        })
        ->with(['address.province', 'address.city', 'address.brgy'])
        ->get();

enter image description here

Итак, вам нужны магазины, в которых имя совпадает ИЛИ где совпадает provDesc?

Travis Britz 26.10.2018 04:58

Да ... но это не работает. Это возможно?

Rbex 26.10.2018 04:59
0
2
170
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

2 вещи:

  1. У вас должно быть предложение OR для поиска записей, в которых выполняется то или иное условие (имя магазина соответствует поиску ИЛИ область provDesc соответствует поиску). Вы можете использовать orWhere(), чтобы добавить в запрос предложение OR.

https://laravel.com/docs/5.6/queries#where-clauses

  1. Здесь магазины - это ваши главные результаты, а провинции - связанные записи. Метод with() не будет фильтровать основные результаты, он будет фильтровать только связанные модели, которые возвращаются вместе с основными результатами. Чтобы отфильтровать основные результаты по запросу по связанным записям, используйте whereHas() (или orWhereHas(), whereDoesntHave() и т. д.).

https://laravel.com/docs/5.6/eloquent-relationships#querying-relationship-existence

Попробуйте что-то вроде этого:

$results = Store::whereHas('province', function($query) use ($request) {
    $query->where('provDesc', 'LIKE', '%'. $request->name . '%');
})->orWhere('name', 'LIKE', '%'. $request->name . '%');

не работает ... пробовал. Может быть, из-за полиморфности или нетерпеливой загрузки with()?

Rbex 26.10.2018 07:18
Ответ принят как подходящий

Проблема с вашим кодом заключается в том, что with() не ограничивает и не добавляет условий к запросу. Он только сообщает Laravel, какие отношения загружать позже (в отдельном запросе) после выполнения первого запроса. Обратный вызов, который вы передаете, ограничивает модели, загружаемые во время вторичного запроса, но не при принятии решения о том, какие магазины нужно получить.

В настоящее время он читается так:

  • Загрузите первые (до) 10 магазинов с именем% name%
    • Загрузите адрес для каждого из этих (до) 10 возвращенных идентификаторов (выполняя запрос whereIn () для идентификаторов)
      • Загрузите область для каждого из этих адресов, но только если provDesc был LIKE% name% (снова с запросом whereIn () по идентификаторам адресов)

Решение: ДобавитьorWhereHas() на запрос Магазина:

Store::where('name', 'LIKE', "%$foo%")

    ->orWhereHas('address.province', function ($query) {
        $query->where('provDesc', 'LIKE', "%$foo%");
    });

Но по-прежнему использую with() для включения отношений, которые вы хотите использовать:

$stores = Store::where('name', 'LIKE', "%{$request->name}%")
    ->orWhereHas('address.province', function ($query) use ($request) {
        $query->where('provDesc', 'LIKE', "%{$request->name}%");
    })
    ->with('address.province')
    ->take(10)
    ->get();

Или, если вы хотите, чтобы была загружена страстная связь с провинциями, только когда он совпадает% name%:

$stores = Store::where('name', 'LIKE', "%{$request->name}%")
    ->orWhereHas('address.province', function ($query) use ($request) {
        $query->where('provDesc', 'LIKE', "%{$request->name}%");
    })
    ->with(['address.province' => function ($query) use ($request) {
        $query->where('provDesc', 'LIKE', "%{$request->name}%");
    }])
    ->take(10)
    ->get();

@Rbex, нужно ли магазинам всегда загружать связь провинции с адресом, или это просто для поиска нужных магазинов?

Travis Britz 26.10.2018 05:22

нет ... это должно быть или где, но меня это устраивает ... я могу это изменить. Оба они должны использовать orWhere ... магазин и провинцию. Как насчет address.city, я тоже добавлю его в with?

Rbex 26.10.2018 05:25

Да, если вы хотите, чтобы был загружен и address.city, вы можете включить его: with('address.city', 'address.province') или with(['address.city', 'address.province'])

Travis Britz 26.10.2018 05:30

По-прежнему не работает ... может быть, из-за полиморфизма?

Rbex 26.10.2018 07:11

@Rbex, что сейчас не работает? Я думал, ты сказал, что это работает как шарм?

Travis Britz 26.10.2018 07:12

Обновляю вопросы ... Я думал, тоже работает, но после проверки с моей командой. Не работает. Он отображает все, хотя есть совпадение "provDesc"

Rbex 26.10.2018 07:14

как видите, строка поиска - "ceb", но она отображает все ...

Rbex 26.10.2018 07:15

Вы можете использовать teamviewer, если он вам не слишком удобен.

Rbex 26.10.2018 07:17

Ваш параметр запроса называется search (?search=ceb), но в вашем коде используется name. Вместо этого попробуйте $request->search и убедитесь, что он не равен нулю (который вернет все совпадения, если вы проверяете LIKE %% - что, вероятно, он делает прямо сейчас. Это означает, что $ request-> name, вероятно, пусто, что приводит к возврату всего.

Travis Britz 26.10.2018 07:19

О, мне так жаль ... Я больше не в моих мыслях. Спасибо ... теперь действительно работает.

Rbex 26.10.2018 07:21

Другие вопросы по теме