Laravel Eloquent: Accès aux propriétés et aux noms de table dynamiques
Je suis en utilisant le Framework Laravel et cette question est directement liée à l'utilisation Éloquent dans Laravel.
Je suis en train de faire un Éloquent modèle qui peut être utilisé dans plusieurs tables différentes. La raison pour cela est que j'ai plusieurs tables qui sont essentiellement identiques, mais varient d'une année à l'autre, mais je ne souhaite pas dupliquer le code pour accéder à ces différentes tables.
- gamedata_2015_nations
- gamedata_2015_leagues
- gamedata_2015_teams
- gamedata_2015_players
Je pourrais bien sûr, ont un grand tableau avec une colonne d'année, mais avec plus de 350 000 lignes de chaque année et de nombreuses années pour faire face à j'ai décidé qu'il serait mieux de les diviser en plusieurs tableaux, plutôt que de 4 énormes tables avec un supplément " où " à chaque demande.
Donc ce que je veux faire est d'avoir une classe pour chaque et faire quelque chose comme ceci à l'intérieur d'une classe de Dépôt:
public static function getTeam($year, $team_id)
{
$team = new Team;
$team->setYear($year);
return $team->find($team_id);
}
J'ai utilisé cette discussion sur le Laravel forums pour me faire: http://laravel.io/forum/08-01-2014-defining-models-in-runtime
Pour l'instant j'ai ceci:
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();
}
}
Cela semble fonctionner, cependant, je suis inquiet qu'il ne fonctionne pas dans le droit chemin.
Parce que je suis en utilisant le mot-clé static la propriété $année est conservé au sein de la classe plutôt que de chaque objet, de sorte que chaque fois que je créer un nouvel objet, il détient toujours le $année de la propriété basée sur la dernière fois qu'il a été défini dans un autre objet. Je serais plutôt de l'année a été associée à un objet unique et doit être fixé à chaque fois que je créé un objet.
Maintenant, je suis en train de suivre le chemin que Laravel crée Éloquent modèles, mais vraiment du mal à trouver le bon endroit pour ce faire.
Par exemple, si je le changer à cela:
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();
}
}
Cela fonctionne bien lorsque vous essayez d'obtenir une seule et même Équipe. Cependant, avec les relations qu'elle ne fonctionne pas. C'est ce que j'ai essayé avec les relations:
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;
}
De nouveau, cela fonctionne très bien si je suis en utilisant statique::$l'année, mais si j'essaie de le modifier pour utiliser $this->année puis ce arrêts de travail.
L'erreur provient du fait que $this->l'année n'est pas définie dans getTable (), de sorte que le parent getTable() la méthode est appelée et le mauvais nom de la table retournée.
Ma prochaine étape est d'essayer et de comprendre pourquoi c'était de travailler avec la propriété statique, mais pas avec le non de la propriété (pas sûr du terme juste pour ça). J'ai supposé qu'il était tout simplement à l'aide de la statique::$année de l'Équipe de la classe en essayant de construire le Joueur relation. Cependant, ce n'est pas le cas. Si j'essaie et la force d'une erreur à quelque chose comme ceci:
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);
}
Maintenant ce qui se passe, c'est que je reçois un message d'erreur indiquant gamedata_1800_players n'est pas trouvé. Pas étonnant peut-être. Mais il exclut la possibilité que Éloquent est tout simplement à l'aide de la statique::$ans la propriété de la classe d'Équipe puisqu'il est clairement réglage de la coutume de l'année que j'envoie à la getPlayerModel() la méthode.
Donc maintenant je sais que lorsque l' $l'année est situé au sein d'une relation et est définie de manière statique puis getTable() a accès, mais si c'est le jeu non-statique puis il se perd quelque part et que l'objet ne sait pas à propos de cette propriété par le temps getTable() est appelée.
(note de l'importance de ce travail différent quand il suffit de créer un nouvel objet et lors de l'utilisation de relations)
Je me rends compte que je vous ai donné beaucoup de détail à présent, afin de simplifier et de clarifier ma question:
1) Pourquoi est-static::$année de travail, mais $this->année pas de travail pour les relations, lorsque le travail quand il suffit de créer un nouvel objet.
2) Est-il une manière que je peux utiliser un non statique de la propriété et de réaliser ce que je suis déjà réaliser à l'aide d'une propriété statique?
Justification: La propriété statique de la classe, même après que j'ai fini avec un objet et suis en train de créer un autre objet avec cette classe, ce qui ne semble pas juste.
Exemple:
//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);
Cela peut ne pas être la pire chose dans le monde, et comme je l'ai dit, c'est en fait de travail en utilisant les propriétés statiques sans erreurs critiques. Toutefois, il est dangereux pour l'exemple de code ci-dessus fonctionne de cette façon, donc je voudrais faire correctement et d'éviter un tel danger.
source d'informationauteur robjbrain
Vous devez vous connecter pour publier un commentaire.
Je suppose que vous savez comment naviguer dans le Laravel API /base de code, puisque vous en aurez besoin pour bien comprendre cette réponse...
Avertissement: Même si j'ai testé certains cas, je ne peux pas garantir qu'Il fonctionne toujours. Si vous avez un problème, faites le moi savoir et je vais essayer de mon mieux pour vous aider.
Je vois que vous avez de multiples cas où vous avez besoin de ce genre de dynamique nom de la table, nous allons donc commencer par la création d'un
BaseModel
donc nous ne devons pas nous répéter.Rien d'excitant jusqu'à présent. Ensuite, nous prenons un coup d'oeil à l'un des statique fonctions dans
Illuminate\Database\Eloquent\Model
et écrire notre propre fonction statique, nous allons l'appeleryear
.(Mis cela dans la
BaseModel
)Cette fonction ne fait rien, mais de créer une nouvelle instance du modèle actuel et ensuite initialiser le générateur de requêtes. D'une manière similaire à la façon dont Laravel t-il dans la classe du Modèle.
La prochaine étape sera de créer une fonction qui définit la table sur un instancié modèle. Appelons cela un
setYear
. Et nous allons également ajouter une variable d'instance pour stocker de l'année séparément à partir de la table nom.Maintenant, nous devons changer la
year
à fait appelsetYear
Et le dernier mais non le moindre, nous devons remplacer
newInstance()
. Cette méthode est utilisée mon Laravel lors de l'utilisation defind()
par exemple.C'est l'essentiel. Voici comment l'utiliser:
La prochaine étape sont relations. Et c'est là que ça devient super compliqué.
Les méthodes pour les relations (comme:
hasMany('Player')
) ne supportent pas le passage dans les objets. Ils prennent une classe, puis en créer une instance. La solution la plus simple j'ai pu trouvé, c'est par la création de la relation d'objet manuellement. (enTeam
)Remarque: la clé étrangère sera toujours appelé
team_id
(sans l'année) je suppose que c'est ce que vous voulez.Malheureusement, vous devrez le faire pour chaque relation que vous définissez. Pour d'autres types de relations de regarder le code dans
Illuminate\Database\Eloquent\Model
. Vous pouvez copier coller et de faire quelques changements. Si vous utilisez un grand nombre de relations sur votre année-dépendante modèles vous pouvez également remplacer la relation méthodes dans votreBaseModel
.Vue de la pleine
BaseModel
sur PastebinBien ce n'est pas une réponse, mais juste mon avis.
Je suppose que vous essayez de faire évoluer votre application juste en fonction de
php
partie. Si vous vous attendez à ce que votre application va grandir par le temps, alors il sera judicieux de répartir les responsabilités entre la somme de tous les autres composants. Les données relatives à la partie devrait traitées parRDBMS
.Comme par exemple, si vous utilisez
mysql
, vous pouvez facilementpartitionize
vos données parYEAR
. Et il y a beaucoup d'autres sujet qui va vous aider à gérer efficacement vos données.Peut-être, un Constructeur personnalisé est le chemin à parcourir.
Puisque tout ce qui varie, c'est l'année dans le nom de la db correspondant, vos modèles pourraient mettre en œuvre un constructeur comme suit:
N'ai pas testé ce que...
L'appeler comme ça: