Использование красноречивой связи ownTo с слагом, а не идентификатором связи

Учитывая следующие две таблицы и отношения:

Контейнеры моделей: id, name, desc, created_at, updated_at

public function items()
{
    return $this->hasMany('App\Models\Items', 'container_id', 'id');
}

Элементы модели: id, container_id, type_id, name, created_at, updated_at

public function containers()
{
    return $this->belongsTo('App\Models\Containers', 'id', 'container_id');
}

Как я могу получить все items, принадлежащие container, где все, что у меня есть, это container:name, не делая что-то вроде:

//Route::get('/api/v1/containers/{container}/items', 'ItemsController@index'); 
public function index($container)
{
    //Show all items in a specific container
    return Containers::where('name', $container)
        ->firstOrFail()
        ->items()
        ->get()
        ->toJson();
}

... и просматривать конкретный элемент в конкретном контейнере без необходимости делать что-то еще более неприятное, например:

//Route::get('/api/v1/containers/{container}/items/{item}', 'ItemsController@show');
public function show($container, $item)
{
    //Show specific item in a specific container
    return Containers::where('name', $container)
        ->firstOrFail()
        ->items()
        ->where('id', $item)
        ->firstOrFail()
        ->toJson();
}

В этом случае у меня есть только имя контейнера в качестве удобного URL-слага, который помогает предотвратить манипулирование URL-адресами.

Есть ли способ, даже если это вторичная принадлежность отношения, добиться этого, указав имя контейнера, чтобы я мог просто сделать Items::find($containerName) без изменения поля primaryKey в моделях.

Попробуйте использовать with(). Просто прочитайте документы @ironchefbadass

mare96 22.05.2019 17:06

Я ценю обратную связь, но я здесь, потому что после прочтения документации мне не ясно, как это решить. Если вы захотите расширить свой ответ, я, безусловно, буду признателен.

ironchefbadass 22.05.2019 17:10
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Что нового в PHP 8.1?
Что нового в PHP 8.1?
Если вы все еще используете PHP 7, то эта статья для вас. В PHP 8, а именно в PHP 8.1, встроены некоторые очень востребованные функции, которые вам...
Разработка LMS на заказ для повышения эффективности работы и обучения
Разработка LMS на заказ для повышения эффективности работы и обучения
За последние годы в образовании произошла большая революция, и сегодня почти все учебные заведения делают упор на эксклюзивное управление учебным...
0
2
194
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Возможно, вы сможете добиться этого, сделав обратное тому, что вы сделали (вызов Item, а не Contractor(s). Это будет выглядеть примерно так:

$items = Item::whereHas(['container' => function($query) use ($container) {
    $query->where('name', $container);
}])->get()->toJson();

Метод ::whereHas() вернет только те items, у которых есть container с указанным вами именем.

Если этого недостаточно, вы можете создать область запроса на своей модели Item, переместив в нее функциональность, указанную выше:

// App\Item.php - or where the model is
public function scopeInContainer($query, $container, $id = null)
{
    $query = $query->whereHas(['container' => function($q) use ($container) {
        $q->where('name', $name);
    }]);

    if ($id) {
        $query = $query->where('id', $id)->firstOrFail();
    }

    return $query;
}

Затем использовать его:

$items = Item::inContainer($container)->get()->toJson();

Тогда при вызове Item через $id вам нужно будет только вызвать:

$item = Item::find($id);

Надеюсь, это то, что вы искали.

Область запроса работает фантастически! Единственное, что меня беспокоит $item = Item::find($id);, это (если я что-то не упустил) вы можете изменить номер идентификатора в URL-адресе и увидеть элемент не в контейнере, в котором вы просматриваете - вот почему я хотел использовать обратное отношение для обеспечения соблюдения ограничение item:id в контейнере. Возможно, это просто еще одна область запроса, в которой я передаю идентификатор элемента вместе с зоной?

ironchefbadass 22.05.2019 18:38

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

thisiskelvin 22.05.2019 19:12

Спасибо, я попробовал: $item) { $q->where('name', $container)->where('items.id', $item); }); } return $query->whereHas('контейнеры', function ($q) use ($container) { $q->where('name', $container); }); } Это работает, но нарушает DRY, от чего у меня мурашки по коже

ironchefbadass 22.05.2019 21:02

@ironchefbadass Я обновил свой ответ, чтобы удовлетворить ваши «сухие» потребности. $id теперь является необязательным аргументом в области запроса ->inContainer().

thisiskelvin 23.05.2019 10:17

Это прекрасно работает - большое спасибо. Единственное редактирование, которое мне пришлось сделать, это удалить "->firstOrFail()" - в результате было возвращено гораздо больше элементов, чем просто переданный элемент: идентификатор.

ironchefbadass 23.05.2019 13:53

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