Laravel — Как использовать выразительный ORM для заполнения столбца внешнего ключа при получении всех результатов из таблицы?

#laravel

Вопрос:

Я настроил свою модель следующим образом:

 class Items extends Model {
    use HasFactory;
    protected $table = 'item';
    protected $primaryKey = 'id';
    protected $connection = 'mysql';
    public $timestamps = false;
    protected $fillable = ['user_id', 'title', 'desc', 'start_datetime', 'due_datetime', 'priority', 'status'];
    public function getManager() {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function getAssignees() {
        return $this->belongsToMany(User::class);
    }
}

 

Я получаю все элементы, используя метод контроллера ниже, что я хочу сделать, так это заполнить поле user_id в каждом из элементов, используя метод getManager (), который я объявил в своей модели элементов. Я знаю, как это сделать, когда вы получаете только один элемент, но как заполнить каждую запись, когда получаете их все?

 public function getall() {
        try {
            $items = Item::get();
            return response()->json(['items' => $items], 200);
        } catch (Throwable $err) {
            return response()->json($err, 400);
        }
    }
 

Я пробовал это, но не повезло:

  public function getall() {
        try {
            $items = Item::get();
            $items = array_map(function ($el) {
                return $el->manager = $el->getManager()->get();
            }, $items);

            return response()->json(['items' => $items], 200);
        } catch (Throwable $err) {
            return response()->json($err, 400);
        }
    }
 

Комментарии:

1. Почему у вас есть и BelongsTo то, и другое, и BelongsToMany отношения, настроенные для этой модели? Как только вы правильно настроите отношения, вы можете просто сделать Item::with('user')->get();

2. Ваши методы отношений также не должны называться так. Они должны быть названиями из одного слова, отражающими модель, с которой они связаны, как public function user() это сделает вашу жизнь намного проще, когда все уладится.

Ответ №1:

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

Название модели

Ваша модель называется Items, но она должна быть единственной, Item. Это помогает Laravel автоматизировать работу, чтобы у вас было меньше работы.

https://laravel.com/docs/8.x/eloquent#eloquent-model-conventions

 class Item extends Model {
 

Настройки базы данных

Вы установили атрибуты $table, $PrimaryKey и $connection, но они должны быть автоматическими. Вероятно, вы можете их удалить.

 protected $table = 'items'; // assuming your model name is Item, this would automatically be 'items'
protected $primaryKey = 'id'; // default is already 'id'
protected $connection = 'mysql'; // default is your main db, probably already 'mysql', unless if you have multiple db connections
 

Метки времени

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

https://laravel.com/docs/8.x/eloquent#timestamps

 public $timestamps = false;
 

Отношения с менеджером

Ваши отношения с менеджером-это getManager, но вы должны быть просто менеджером. Это все равно будет работать, но не так, как должен был работать Ларавель. Я бы предложил изменить его на manager () и не указывать имя столбца. Это автоматически сделает имя столбца manager_id, поэтому вам придется его обновить. Или вы можете сохранить имя столбца «идентификатор пользователя».

https://laravel.com/docs/8.x/eloquent-relationships#one-to-many-inverse

  public function manager() {
        return $this->belongsTo(User::class);
 }
 

Отношения цессионариев

Так же, как и в отношениях с менеджером, вы должны изменить getAssignees() на assignees(). Я предполагаю, что у вас уже есть миграция базы данных, настроенная для вашей таблицы «item_user», которую будет искать Laravel. Если нет, проверьте документы Laravel о том, как его настроить.

https://laravel.com/docs/8.x/eloquent-relationships#many-to-many

 public function assignees() {
    return $this->belongsToMany(User::class);
}
 

Извлечение Предметов

Наконец, с учетом вышеуказанных изменений получить все предметы должно быть легко. Чтобы загрузить отношения, используйте метод $with. Это называется Нетерпеливой загрузкой. Проверьте документы для получения дополнительной информации.

https://laravel.com/docs/8.x/eloquent-relationships#eager-loading

 $items = Item::with('manager','assignees')->get();
 

Возвращаемые Коды Ответов

Вы неправильно отвечали на свои ответы. Вам не нужно задавать код ответа 200, так как это значение по умолчанию. Если вы собираетесь установить его на что-то другое, поместите код в метод response() вместо метода json ().

https://laravel.com/docs/8.x/responses

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


return response($err,400);
 

Теперь, собрав все это вместе, ваша модель изделия должна выглядеть примерно так:

 class Item extends Model {
    use HasFactory;

    protected $fillable = ['manager_id', 'title', 'desc', 'start_datetime', 'due_datetime', 'priority', 'status'];

    public function manager() {
        return $this->belongsTo(User::class);
    }

    public function assignees() {
        return $this->belongsToMany(User::class);
    }
}
 

Ответ №2:

     public function getall() {
            try {
                $items = Item::get()
                          ->transform(function($el){
                                $el->manager = $el->getManager()->get();
                            );
                return response()->json(['items' => $items], 200);
            } catch (Throwable $err) {
                return response()->json($err, 400);
            }
        }
 

Попробуйте применить метод преобразования к своим результатам, и он сработает.
https://laravel.com/docs/8.x/collections#method-transform

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

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