2 votes

Laravel 4 : Noms de tables dynamiques avec setTable()

Je ne suis pas sûr de ce que je dois faire pour que les noms de tables dynamiques fonctionnent.

Considérons le modèle suivant (la table 'test' n'existe pas) :

<?php

// app/models/Test.php

class Test extends Eloquent {

}

et ensuite si je le fais (la table 'fields' existe) :

<?php

// app/routes.php

$test = new \Test;
$test->setTable('fields');
$data = $test->find(1);
dd($data);

Je reçois une erreur :

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.tests' doesn't exist (SQL: select * from `tests` where `id` = ? limit 1) (Bindings: array ( 0 => 1, ))"

Notez que la définition du nom de la table à partir du modèle de test fonctionne parfaitement.

L4 utilise en fait la méthode setTable(), comme je le voudrais, dans le constructeur vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations.Pivot.php, mais je n'ai pas réussi à le faire fonctionner en suivant cet exemple.

Merci pour votre aide.

7voto

Daniel Cantarin Points 110

Peut-être cela vous sera-t-il utile : http://laravel.io/forum/08-01-2014-defining-models-in-runtime

Plus exactement, d'ici : http://laravel.io/forum/08-01-2014-defining-models-in-runtime?page=1#reply-11779

class ModelBuilder extends Eloquent {

    protected static $_table;

    public static function fromTable($table, $parms = Array()){
        $ret = null;
        if (class_exists($table)){
            $ret = new $table($parms);
        } else {
            $ret = new static($parms);
            $ret->setTable($table);
        }
        return $ret;
    }

    public function setTable($table)
    {
        static::$_table = $table;
    }

    public function getTable()
    {
        return static::$_table;
    }
}

$user = ModelBuilder::fromTable("users")->find(1);

Ce n'est pas ma mise en œuvre finale, qui est beaucoup plus complexe (et plus sale) que cela en raison de mes cas d'utilisation. Mais je pense que l'exemple peut vous mener à ce dont vous avez besoin.

0voto

trm42 Points 623

Vous devez surcharger le modèle statique d'Eloquent Model. find car elle est utilisée pour la recherche :

public static function find($id, $columns = array('*'))
{
    if (is_array($id) && empty($id)) return new Collection;

    $instance = new static;

    return $instance->newQuery()->find($id, $columns);
}

Cette méthode consiste à créer une nouvelle instance de votre classe modèle au lieu de réutiliser la classe instiuée. Par défaut, cela "oublie" la table que vous avez définie. Et probablement vous devez passer le nom de la table pour cela. Dans mon cas d'utilisation, mon code déduit la table utilisée en se basant sur le nom de la table. id pour ne pas avoir à passer le nom complet de la table. Hourra pour l'héritage ;-)

L'autre option est d'utiliser une classe d'usine supplémentaire telle que Daniel Cantarin Proposition de

Il se peut que vous deviez surcharger certaines méthodes statiques supplémentaires pour gérer tous les cas d'utilisation. Par exemple, je viens de remarquer que l'utilisation du chargement rapide casse mes tables modulaires. with le comportement de la méthode sans casser l'API d'appel, yay -_____-

0voto

malcolmhall Points 1909

La conception de Larvael ne prend pas totalement en charge les modèles dynamiques. Bien qu'il existe la méthode setTable, sa limite est qu'il s'agit d'une méthode d'instance. De plus, dans le cadre de travail, de nombreuses requêtes commencent par la création d'une instance de modèle via "new static", il n'y a donc aucun moyen pour vous de définir la table sur les requêtes internes. Oui, vous pouvez appeler setTable sur vos propres requêtes, mais au fur et à mesure que vous développez votre application en utilisant plus de fonctionnalités de Laravel, par exemple SoftDeletes forceDelete, vous vous heurterez progressivement à un mur de briques. Une solution consiste à utiliser la fonction eval de PHP pour générer des classes de modèles au moment de l'exécution, de cette façon, les nouvelles statiques fonctionneront comme elles ont été conçues.

    // load all the models
    $eval = "namespace App\\Records;";
    foreach($container->tables()->get() as $table){
        $recordType = $table->recordType;
        $recordTable = $table->getRecordTableName();
        $eval .= "class $recordType extends \\App\\Record { protected \$table = '$recordTable'; }";

    }
    eval($eval);

Dans le cas où j'ai un recordType 'Venue' qui utilise la recordTable 'venue', j'ai maintenant une classe \App\Records\Venue qui utilise la table "lieu", donc je peux maintenant faire ceci

$class = "\App\Records\Venue";
$venue = $class::find(1);

Vous êtes maintenant libre d'utiliser Laravel tel qu'il a été conçu, sans autre forme de procès. Il s'agit d'une solution de contournement très puissante qui s'accompagne d'un risque de sécurité. Veillez donc à désinfecter tous les paramètres utilisés dans eval. Espérons qu'un jour, Laravel mettra en œuvre un moyen de prendre en charge les modèles dynamiques.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X