Неопределенный метод отношений в построителе запросов - Laravel - PullRequest
2 голосов
/ 30 сентября 2019

У меня есть 3 таблицы users, teams, athletes.

Пользователь может быть командой или спортсменом.

Я положил user_id в teams& athletes таблица.

Я поставил ниже код в User.php модель.

public function team()
{
    return $this->hasOne (Team::class);
}


public function athlete()
{
    return $this->hasOne (Athlete::class);
}

Я поставил ниже код в Team.php модель

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

Iвведите код ниже Athlete.php

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

Я использую код ниже в контроллере.

$staff_picks = User::notAdmin()->active()->orderBy('id','desc')->take(10)->team()->athlete()->get();

Я получаю ошибку ниже

laravel.ERROR: Вызов неопределенного метода Illuminate \ Database \ Eloquent \ Builder :: team () `

Есть идеи, почему это происходит?

Ответы [ 2 ]

2 голосов
/ 30 сентября 2019

Хорошо, так что ошибка говорит

Вызов неопределенного метода Illuminate \ Database \ Eloquent \ Builder :: team ()

Это означает, что метод team()не определен в классе Builder

Теперь класс Builder находится в vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php в пространстве имен Illuminate\Database\Eloquent

Логически следует, что для функции с именем team() невозможнобыть там правильно?


Что такое команда ()? тогда и как я могу это назвать?

team() - это функция внутри вашей модели app/User.php, и она возвращает hasOne функцию

Хорошо, так где же hasOne()?

hasOne находится в признаке vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php под пространством имен Illuminate\Database\Eloquent\Concerns

Смотрите здесь

namespace Illuminate\Database\Eloquent\Concerns;
// Imports ommitted for brevity

trait HasRelationships
{
// Other methods ommitted for brevity

/**
 * Define a one-to-one relationship.
 *
 * @param  string  $related
 * @param  string  $foreignKey
 * @param  string  $localKey
 * @return \Illuminate\Database\Eloquent\Relations\HasOne
 */
public function hasOne($related, $foreignKey = null, $localKey = null)
{
    $instance = $this->newRelatedInstance($related);
    $foreignKey = $foreignKey ?: $this->getForeignKey();
    $localKey = $localKey ?: $this->getKeyName();
    return $this->newHasOne($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey);
}
// Other methods are omitted for brevity

Но как это называется? Я не использую черту HasRelationships

Это правда, класс app/User.php не использует черту HasRelationships, но расширяет класс, который *

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable

* не напрямую, хотя

Подсветка \ Foundation \ Auth \ Расширения пользователя Подсветка \ База данных \ Eloquent \ Модель

См. Здесь

namespace Illuminate\Foundation\Auth;

// Other Imports ommitted for brevity
use Illuminate\Database\Eloquent\Model;

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

И

Подсветка \ База данных \ Eloquent \ Model использует черту Concerns \ HasRelationships

См. Здесь

namespace Illuminate\Database\Eloquent;

// Imports ommitted for brevity

abstract class Model implements Arrayable, ArrayAccess, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
    use Concerns\HasAttributes,
        Concerns\HasEvents,
        Concerns\HasGlobalScopes,
        Concerns\HasRelationships, // <-- THERE IT IS HERE!!!!
        Concerns\HasTimestamps,
        Concerns\HidesAttributes,
        Concerns\GuardsAttributes,
        ForwardsCalls;
// Rest of class ommitted for brevity

Подождите! как этот класс узнает, откуда взята черта Concerns\HasRelationships без импорта?

Поскольку Concerns - это пространство имен, добавленное (или вложенное в) к тому же пространству имен, этот класс определен в

Этот класс находится в Illuminate\Database\Eloquent и HasRelationships в Illuminate\Database\Eloquent\Concerns, поэтому достаточно простого вызова Concerns\HasRelationships

Теперь черта HasRelationships имеет функцию hasOne

Хорошо, как избежать этой ошибки?

Убедитесь, что вы вызываете отношение, определенное в модели, из экземпляра модели, а не из построителя запросов

Пример

Неверно

User::where('name', 'John Doe')->teams;

Правильно

User::where('name', 'John Does')->first()->teams;

Но почему?

Хорошо, любая операция SQL, которую вы выполняете на модели до , вы получитемодель является экземпляром Query Builder

Но как только вы получите саму модель, например, с first(), вы можете вызвать отношение

Обновление: чтобы ответить на конкретный сценарий вопроса

Вы можете выбрать более одной модели, поэтому не идеальнофункция связи team() для каждой записи после ее выборки

Решение?

Стремительная загрузка

Использование withметод для включения данных отношений в коллекцию, извлеченную с помощью get()

Пример

Допустим, у меня есть User и Profile

У каждого пользователя есть одини только один профиль, поэтому я определяю отношение hasOne для User модели

public function profile()
{
    return $this->hasOne(Profile::class);
}

Теперь нам нужен внешний ключ в миграции, чтобы связать таблицу profiles с таблицей users

Schema::create('profiles', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->integer('age'); // Column to test with
    $table->unsignedBigInteger('user_id');
    $table->foreign('user_id')->references('id')->on('users');
    $table->timestamps();
});

Теперь давайте посеем некоторые данные

public function run()
{
    factory(User::class, 10)->create()->each(function ($user) {
        $user->profile()->create(['age' => rand(20, 60)]);
    });
}

Теперь давайте откроем ремесленника и посмотрим, что произойдет

>>> App\User::take(10);
=> Illuminate\Database\Eloquent\Builder {#3067}

take() Функция на модели User возвращаетЭкземпляр Builder

Давайте попробуем получить профиль для этого

>>> App\User::take(10)->profile();

Ошибка

BadMethodCallException с сообщением «Вызов неопределенного метода Illuminate / Database / Eloquent / Builder:: profile () '

Но теперь мы знаем, почему

Теперь давайте попробуем Eager Загрузка

>>> App\User::take(10)->with('profile');
=> Illuminate\Database\Eloquent\Builder {#3056}

Возвращает построитель запросов

Давайте назовем get() для этого

>>> App\User::take(10)->with('profile')->get();

Теперь мы получаем нашу коллекцию данных

=> Illuminate\Database\Eloquent\Collection {#3070
     all: [
       App\User {#3022
         id: 1,
         name: "Augusta Botsford MD",
         email: "xwaelchi@example.net",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3095
           id: 1,
           age: 29,
           user_id: 1,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3017
         id: 2,
         name: "Olga Leannon",
         email: "ufay@example.com",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3096
           id: 2,
           age: 24,
           user_id: 2,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3019
         id: 3,
         name: "Bria Prosacco DDS",
         email: "hartmann.trystan@example.com",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3097
           id: 3,
           age: 43,
           user_id: 3,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3054
         id: 4,
         name: "Clare Bayer",
         email: "rosalinda60@example.org",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3098
           id: 4,
           age: 52,
           user_id: 4,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3058
         id: 5,
         name: "Vickie Kub",
         email: "katherine.abbott@example.com",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3099
           id: 5,
           age: 42,
           user_id: 5,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3059
         id: 6,
         name: "Tressie Gottlieb",
         email: "elmira.osinski@example.net",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3100
           id: 6,
           age: 21,
           user_id: 6,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3042
         id: 7,
         name: "Saige Pollich",
         email: "gkemmer@example.org",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3101
           id: 7,
           age: 24,
           user_id: 7,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3087
         id: 8,
         name: "Dr. Emiliano Sauer",
         email: "marks.florida@example.net",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3102
           id: 8,
           age: 42,
           user_id: 8,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3086
         id: 9,
         name: "Genoveva Abshire",
         email: "colt.harber@example.com",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3103
           id: 9,
           age: 27,
           user_id: 9,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
       App\User {#3088
         id: 10,
         name: "Dimitri Moore",
         email: "slockman@example.net",
         email_verified_at: "2019-09-30 16:40:12",
         created_at: "2019-09-30 16:40:12",
         updated_at: "2019-09-30 16:40:12",
         profile: App\Profile {#3104
           id: 10,
           age: 30,
           user_id: 10,
           created_at: "2019-09-30 16:40:12",
           updated_at: "2019-09-30 16:40:12",
         },
       },
     ],
   }

Надеюсь, это прояснит ситуацию

2 голосов
/ 30 сентября 2019

Измените свой код на

$staff_picks = User::notAdmin()
    ->active()
    ->orderBy('id','desc')
    ->take(10)
    ->with('team', 'athlete')
    ->get();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...