Я использую Laravel Framework, и этот вопрос напрямую связан с использованием Eloquent в Laravel.
Я пытаюсь создать модель Eloquent, которая может использоваться в нескольких разных таблицах. Причина этого заключается в том, что у меня есть несколько таблиц, которые по существу идентичны, но меняются из года в год, но я не хочу дублировать код для доступа к этим различным таблицам.
- gamedata_2015_nations
- gamedata_2015_leagues
- gamedata_2015_teams
- gamedata_2015_players
Я мог бы, конечно, иметь один большой стол с колонкой за год, но с более чем 350 000 строк каждый год и много лет, чтобы справиться с этим я решил, что было бы лучше разделить их на несколько таблиц, а не на 4 огромные таблицы с дополнительным 'где' по каждому запросу.
Итак, что я хочу сделать, это один класс для каждого и сделать что-то подобное в классе репозитория:
public static function getTeam($year, $team_id)
{
$team = new Team;
$team->setYear($year);
return $team->find($team_id);
}
Я использовал эту дискуссию на форумах Laravel, чтобы начать меня: http://laravel.io/forum/08-01-2014-defining-models-in-runtime
Пока у меня есть это:
class Team extends \Illuminate\Database\Eloquent\Model {
protected static $year;
public function setYear($year)
{
static::$year= $year;
}
public function getTable()
{
if(static::$year)
{
//Taken from https://github.com/laravel/framework/blob/4.2/src/Illuminate/Database/Eloquent/Model.php#L1875
$tableName = str_replace('\\', '', snake_case(str_plural(class_basename($this))));
return 'gamedata_'.static::$year.'_'.$tableName;
}
return Parent::getTable();
}
}
Это, похоже, работает, однако я беспокоюсь, что он не работает правильно.
Поскольку я использую статическое ключевое слово, свойство $year сохраняется внутри класса, а не каждый отдельный объект, поэтому всякий раз, когда я создаю новый объект, он все еще сохраняет свойство $year, основанное на последнем времени, когда он был установлен в другой объект. Я предпочел бы, чтобы $year был связан с одним объектом и должен был быть установлен каждый раз, когда я создал объект.
Теперь я пытаюсь отслеживать, как Laravel создает модели Eloquent, но действительно пытается найти подходящее место для этого.
Например, если я изменил его на это:
class Team extends \Illuminate\Database\Eloquent\Model {
public $year;
public function setYear($year)
{
$this->year = $year;
}
public function getTable()
{
if($this->year)
{
//Taken from https://github.com/laravel/framework/blob/4.2/src/Illuminate/Database/Eloquent/Model.php#L1875
$tableName = str_replace('\\', '', snake_case(str_plural(class_basename($this))));
return 'gamedata_'.$this->year.'_'.$tableName;
}
return Parent::getTable();
}
}
Это прекрасно работает при попытке получить одну команду. Однако с отношениями это не работает. Это то, что я пробовал с отношениями:
public function players()
{
$playerModel = DataRepository::getPlayerModel(static::$year);
return $this->hasMany($playerModel);
}
//This is in the DataRepository class
public static function getPlayerModel($year)
{
$model = new Player;
$model->setYear($year);
return $model;
}
Снова это работает абсолютно нормально, если я использую static:: $year, но если я попытаюсь изменить его на использование $this- > year, это перестанет работать.
Фактическая ошибка связана с тем фактом, что $this- > year не установлен в getTable(), так что вызывается родительский метод getTable() и возвращается неправильное имя таблицы.
Мой следующий шаг состоял в том, чтобы попытаться выяснить, почему он работает со статическим свойством, но не с нестатическим свойством (не уверен в правильном члене для этого). Я предположил, что он просто использовал static:: $year из класса Team при попытке построить отношения с игроком. Однако, это не так. Если я попытаюсь сделать ошибку с чем-то вроде этого:
public function players()
{
//Note the hard coded 1800
//If it was simply using the old static::$year property then I would expect this still to work
$playerModel = DataRepository::getPlayerModel(1800);
return $this->hasMany($playerModel);
}
Теперь случается, что я получаю сообщение об ошибке, когда gamedata_1800_players не найден. Не удивительно, возможно. Но это исключает возможность того, что Eloquent просто использует свойство static:: $year из класса Team, поскольку он четко устанавливает пользовательский год, который я отправляю методу getPlayerModel().
Итак, теперь я знаю, что когда $year устанавливается в пределах отношения и устанавливается статически, getTable() имеет к нему доступ, но если он установлен не статически, он где-то теряется и объект не знает об этом свойстве к моменту получения getTable().
(обратите внимание на значимость его работы при простом создании нового объекта и при использовании отношений)
Я понимаю, что сейчас я дал много деталей, чтобы упростить и уточнить мой вопрос:
1) Почему статические:: $year работают, но $this- > year не работают для отношений, когда они работают при простом создании нового объекта.
2) Есть ли способ, которым я могу использовать нестационарное свойство и достичь того, чего я уже достигаю, используя статическое свойство?
Обоснование для этого: статическое свойство останется с классом даже после того, как я закончил с одним объектом, и я пытаюсь создать другой объект с этим классом, что кажется неправильным.
Пример:
//Get a League from the 2015 database
$leagueQuery = new League;
$leagueQuery->setYear(2015);
$league = $leagueQuery->find(11);
//Get another league
//EEK! I still think i'm from 2015, even though nobodies told me that!
$league2 = League::find(12);
Это может быть не самое худшее в мире, и, как я уже сказал, он фактически работает с использованием статических свойств без критических ошибок. Однако для вышеуказанного образца кода опасно работать таким образом, поэтому я хотел бы сделать это правильно и избежать такой опасности.