Нестатический метод не должен вызываться статически

Я использую шаблон репозитория и пытаюсь установить отношения между моделями. Когда я пытаюсь запустить метод store() (в контроллере), который пытается использовать метод user() (который устанавливает связь с моделью Party), я получаю следующее сообщение об ошибке:

Нестатический метод Party::user() не должен вызываться статически, предполагая $this из несовместимого контекста.

Я не понимаю, почему я получаю эту ошибку, когда пытаюсь запустить метод отношения user(), но все остальные методы (включая $this->party->all(), $this->party->create( $data)), работают нормально.

Вот соответствующий код:

// PartiesController.php
public function __construct(Party $party){
  $this->party = $party
}

public function store(){
  $data = Input::all();
  $user = Sentry::getUser(); 
  $this->party->user()->create($data);
}

// Party.php
class Party extends Eloquent{
  public function user(){
    return $this->belongsTo('User');
  }
}

// User.php
use Cartalyst\Sentry\Users\Eloquent\User as SentryUserModel;

class User extends SentryUserModel implements UserInterface, RemindableInterface {
  public function party(){
    return $this->hasMany('Party');
  }
}

// PartyRepository.php
namespace repositories\Party;

interface PartyRepository{
  public function all();

  public function findByID($id);

  public function create($input);

  public function user();
}

// EloquentPartyRepository.php
namespace repositories\Party;
use Party;

class EloquentPartyRepository implements PartyRepository{
  public function all(){
    return Party::all();
  }

  public function create($input){
    return Party::create($input);
  }

  public function user(){
    return Party::user();
  }
}

person user3691644    schedule 17.07.2014    source источник


Ответы (2)


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

В вашем случае это просто вызов статического метода. PHP позволит это, за исключением того факта, что в методе, на который вы ссылаетесь, $this, и PHP не знает, что с ним делать. Вызовы статических методов по определению не знают ни о каких экземплярах класса.

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

//Class: EloquentPartyRepository
public function __construct(Party $party) 
{
    $this->party = $party;
}

public function user($partyId) 
{
    return $this->party->find($partyId)->user();
}

Экземпляр Party, который вы отправляете в конструктор, не должен быть записью из базы данных, просто пустым экземпляром Party (т.е. new Party()), хотя я считаю, что если вы просто добавите его в конструктор, IoC сможет использовать внедрение зависимостей и предоставить вам экземпляр.

Эквивалентная реализация здесь, которая добавляет метод byId:

//Class: EloquentPartyRepository
public function __construct(Party $party) 
{
    $this->party = $party;
}

public function byId($partyId)
{
    return $this->party->find($partyId);
}

public function user($partyId) 
{
    if($party = $this->byId($partyId)) {
        return $party->user();
    }

    return null;
}
person Jeff Lambert    schedule 17.07.2014
comment
На самом деле all() - это статический метод модели (оба, используемые OP, являются статическими: all и create). Большинство вызовов Eloquent передаются классу Eloquent\Builder за моделью, и вы правы, что он создается первым. - person Jarek Tkaczyk; 17.07.2014
comment
@deczo ты прав! Я забыл об этом, спасибо, что указали на это. Я изменю свой пример, чтобы вместо него использовать find - person Jeff Lambert; 17.07.2014
comment
@watcher, а как насчет кода в контроллере. Когда я изменяю EloquentPartyRepository, как предписано, я получаю сообщение об ошибке Вызов функции-члена user() для не-объекта. - person user3691644; 18.07.2014
comment
Вашему контроллеру нужно, чтобы репозиторий был внедрен в него, вы вводите саму модель (это основная точка шаблона репозитория, вы не хотите, чтобы что-либо напрямую полагалось на классы вашей модели). Вам также нужен какой-то способ определить, на какой стороне искать пользователя (читайте, как вы определяете идентификатор партии для загрузки?) - person Jeff Lambert; 18.07.2014
comment
Понял. Поиск partyId является проблемой, поскольку запись создается в это время. Я пытаюсь использовать отношение, чтобы вставить user_id в модель при создании Party - person user3691644; 18.07.2014

Я решил проблему. Спасибо @watcher и @deczo за ваши отзывы. Оба были очень полезны и относились к этому сообщению об ошибке.

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

// PartiesController.php
public function store(){
  $data = Input::all();
  $user = Sentry::getUser(); 
  $user->party()->create($data);
}

В моем случае, чтобы удалить нестатическую ошибку и правильно вставить модель User в модель Party, мне нужно было только внести вышеупомянутое изменение.

Я ссылался на http://laravel.com/docs/eloquent/#inserting-related-models для соответствующей последовательности.

person user3691644    schedule 18.07.2014