Отношения Laravel: один foreignKey для нескольких localKey - PullRequest
0 голосов
/ 12 января 2019

Мне нужно разработать API с Laravel, и я застрял с этой проблемой: Мне нужно получить все совпадения, и для каждого совпадения мне нужно получить пользователей, которые принадлежат этому совпадению (в каждом совпадении 2 пользователя)

Я нашел ответ на эту проблему, и нашел это https://github.com/topclaudy/compoships, но у меня это не сработало.

Пока у меня есть это:

class Match extends Model
{
    protected $table = 'matchs';

    public $primaryKey = 'id';

    public function playerOne() {
    return $this->hasMany('App\User', 'id', 'playerOne_id');
    }

    public function playerTwo() {
        return $this->hasMany('App\User', 'id', 'playerTwo_id');
    }
}

Метод контроллера:

public function index()
{
    $matchs = Match::with('playerOne', 'playerTwo')->orderBy('created_at', 'asc')->get();

    return $matchs; 
    //return new MatchsCollection($matchs);
}

и моя база данных выглядит так: (Таблица матчей)

id    | playerOne_id   | playertwo_id | winner_id | status 
------------------------------------------------------------
1     | 1              | 3            | 0         | PENDING
2     | 2              | 1            | 0         | PENDING
3     | 3              | 2            | 0         | PENDING

и таблица пользователей:

id    | name      | email           
-----------------------------------
1     | John      | John@email.com 
2     | Mark      | Mark@email.com
3     | Harry     | Harry@email.com

и когда я вызываю мой API, я получаю такой результат:

[
  {
    id: 1,
    playerOne_id: 1,
    playerTwo_id: 3,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-10 00:00:00",
    updated_at: null,
    users: [
      {
        id: 1,
        name: "John",
        email: "John@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      }
    ]
  },
  {
    id: 2,
    playerOne_id: 2,
    playerTwo_id: 1,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-11 08:26:28",
    updated_at: "2019-01-11 08:26:28",
    users: [
      {
        id: 2,
        name: "Mark",
        email: "Mark@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:40:13",
        updated_at: "2019-01-11 10:40:13"
      }
    ]
  },
  {
    id: 3,
    playerOne_id: 3,
    playerTwo_id: 2,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-11 08:45:22",
    updated_at: "2019-01-11 08:45:22",
    users: [
      {
        id: 3,
        name: "harry",
        email: "harry@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:40:13",
        updated_at: "2019-01-11 10:40:13"
      }
    ]
  }
]

Что я не хочу получить, так это результат (я просто покажу вам первый матч)

[
  {
    id: 1,
    playerOne_id: 1,
    playerTwo_id: 3,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-10 00:00:00",
    updated_at: null,
    users: [
      {
        id: 1,
        name: "John",
        email: "John@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      },
      {
        id: 3,
        name: "Harry",
        email: "Harry@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      }
    ]
  }
]

возможно ли это в Ларавеле? спасибо:)

1 Ответ

0 голосов
/ 13 января 2019

Чтобы иметь возможность вернуть всех игроков как часть массива user, вы можете либо изменить соотношение между Match и User, чтобы оно стало ProperToMany (многие ко многим) или просто манипулируйте данными соответствия, прежде чем возвращать их из контроллера.

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

Вам необходимо:

  1. переименуйте вашу таблицу matchs в matches (это также будет означать, что вы можете удалить
    protected $table = 'matchs'; из вашего Match модельного класса).
  2. Создать таблицу с именем match_user. Если ваш проект использует миграции, вы можете запустить:
    php artisan make:migration create_match_user_table --create=match_user
    В этой миграции вам необходимо изменить содержимое метода up() на:

    public function up()
    {
        Schema::create('match_user', function (Blueprint $table) {
            $table->integer('match_id')->unsigned();
            $table->integer('user_id')->unsigned();
            $table->timestamps();
    
            $table->primary(['match_id', 'user_id']);
        });
    }
    
  3. Выполнить php artisan migrate

  4. В вашей Match модели измените отношение users() на:

    public function users()
    {
        return $this->belongsToMany(User::class)->withTimestamps();
    }
    
  5. Если данные в ваших таблицах являются фиктивными, вы можете пропустить этот шаг. В противном случае вам нужно переместить информацию playerOne_id и playertwo_id в новую сводную таблицу. Вы можете сделать это следующим образом:

    Match::all()->each(function ($match) {
        $match->users()->attach([$match->playerOne_id, $match->playertwo_id]);
    });
    

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

  6. Затем идет очистка. Опять же, если у вас есть только фиктивные данные, я бы просто удалил исходную миграцию playerOne_id и playertwo_id, в противном случае создаю новую миграцию, которая удаляет эти поля Удаление столбцов документов


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

$matches = Match::with('users')->latest()->get();
...