Problème Model Giix

Salut à tous !

Je suis toute nouvelle dans la communauté et je cherche une solution à mon problème !

J’ai une dizaine de bases de données (une par magasin) qui sont utilisées par le même site. J’ai, dans chacune d’entre elles une table avec la même structure (produit). Est-il possible de créé un modèle qui utiliserais les différentes tables de chaque base ?

Merci d’avance !!

Salut !

Je ne suis pas certain d’avoir complètement compris le problème, mais ce que je peux te dire :

  • tu peux configurer plusieurs connexions de bases de données dans le fichier de configuration de Yii :



return array(

    ...

    'components' => array(

        'db' => array(    // Connexion par défaut

            'connectionString' => 'mysql:host=dbhost;dbname=mydb1',

            ...

        ),

        'db2' => array(    // Deuxième connexion

            'connectionString' => 'mysql:host=dbhost;dbname=mydb2',

            'username'         => '********',

            'password'         => '********',

            ...

            'class'            => 'CDbConnection'          // A rajouter pour que Yii comprenne que c'est une autre connexion

        ),



  • avec Giix, tu peux sélectionner quelle connexion de base de données est utilisée pour générer tes modèles. Cependant (je m’avance peut-être), Giix ne devrait pas pouvoir te permettre de réaliser un modèle “multi-base”. C’est à toi de le modifier manuellement de manière à permettre cela.

J’ai bien compris le problème ou je suis hors-sujet ? :D

Tu as bien compris le problème !

J’ai trouvé une autre solution, dis moi ce que tu en penses ! :)

J’ai généré un model d’une base d’un des magasin que j’ai modifié :


abstract class BaseProduct extends GxActiveRecord

{


        var $store = NULL;


        public function __construct($store)

        {

                $this->store = $store;

                Yii::app()->user->setState('orderDatabase', $this->store);

                $model = new BOorders();

                $model->getDbConnection();

        }   


	public static function model($className=__CLASS__)

        {

		return parent::model($className);

	}


	public function tableName()

        {

		return 'BD_store_'.$this->store.'.products';

	}




...}

Pour l’instant ça fonctionne mais je n’ai pas fait beaucoup de tests.

Merci pour la réponse aussi rapide !

Ah bah tu as fait ce que je disais dans le second point :)

Sache que si tu configures l’ensemble de tes bases en config, tu pourras ensuite accéder à tes connexions de la manière suivante :




$connexion = Yii::app()->db;

$connexion2 = Yii::app()->db2;



Et ainsi de suite, mais c’est surtout utile si tu veux effectuer une requête SQL à la main par exemple.

Le principal problème c’est que je ne peux pas avoir une liste exhaustive de toutes les bases de données.

Ma solution m’a très vite bloqué :

Impossible de créer un nouvel objet…

Ca coince avec la classe CActiveRecord.

exemple :




$product = new Product($store);

$product->name = 'abricot';



ca me renvoie une erreur :

"You must set store before search orders. "

Car il utilise plusieurs fonctions de CActiveRecord qui reviennent toujours au constructeur de ma classe mais avec un paramètre NULL.

Ce fut laborieux, mais j’ai une solution qui fonctionne. Je poste la solution pour les personnes qui rencontreront le même problème :

Surcharger le constructeur de mon model n’a pas du tout fonctionné :

beaucoup de conflits avec CActiveRecord

Solution :

Il suffit surcharger la fonction getDbConnection dans le model [color="#FF0000"]Products et non BaseProducts[/color].


public function getDbConnection()

    {

        $dbconnection = Yii::createComponent(

            array(

                'connectionString'=>'mysql:host=localhost;dbname= /*Utilisation de Yii!!app()->user->getState('store')*/',

                'username'=>'user',

                'password'=>'password',

                'charset' => 'utf8',

                'class' => 'CDbConnection'

            )

        );


        if ($dbconnection instanceof CDbConnection)

        {

            return $dbconnection;

        }

        else

            return NULL;

       

dans la fonction ou je déclare une nouvelle instance de la classe Products, j’assigne la valeur de mon store (avant l’instance):

Yii!!app()->user->setState(‘store’, ‘10’/le store n°10 par exemple/);

et j’ai changé la fonction tableName dans BaseProducts pour quelle s’adapte à la base de donnée de chaque magasin.

Voila !

Nouvelle mise à jour de ma solution !!

Ma solution a très bien fonctionné jusqu’au moment ou j’ai du faire beaucoup, beaucoup de requêtes sur ma base de donnée.

===> SQLSTATE[HY000] [1040] Too many connections.

Ma 1ère solution ouvrait une nouvelle connexion à chaque instance de la classe.

Pour palier à ce problème, j’ai créé un tableau de connexions dans la classe Products :




    protected static $connections = array();




    public function getDbConnection()

    {

        $store = Yii::app()->user->getState('Store')


        if (isset(static::$connections[$store]))

            return static::$connections[$store];


        $dbconnection = Yii::createComponent(

            array(

                'connectionString'=>'mysql:host=localhost;dbname= 'database_'.$store,'

                'username'=>'user',

                'password'=>'password',

                'charset' => 'utf8',

                'class' => 'CDbConnection'

            )

        );


        if ($dbconnection instanceof CDbConnection)

        {

            static::$connections[$store] = $dbconnection;

            return $dbconnection;

        }

        return NULL;

    }

       

Bonjour

Par rapport à la proposition, je préfère éviter que la configuration se retrouve dans la classe spécifique. Il me semble flexible et suffisamment efficace de passer par un "component":


public function getDbConnection() {

   $store = Yii::app()->user->getState('Store');

   return Yii::app()->getComponent('db_'.$store);

}

Ceci nécessite alors d’avoir autant de configurations de base de données qu’il y a des boutiques. Au lieu de


'db'=>array(...)

il faut écrire


'db_store1'=>array(...)

.

Mon deuxième réflexe est d’éviter d’avoir une connaissance spécifique concernant comment on récupère le nom de la boutique dans cette classe. J’ajouterai une classe supplémentaire:




class Store extends CComponent {

	public static function getCurrentStoreDb() {

   		$store = Yii::app()->user->getState('Store');

           return self::getStoreDb($store);

        }


        public static function getStoreDb($store=null) {

		

   		$db=Yii::app()->getComponent('db_'.$store);

   		if($db===null)

              throw new CException(Yii::t('app','Unknown store "{store}"',array('{store}'=>$store)));

   		else

              return $db;

        }

}



et ensuite:


public function getDbConnection() {

	return Store::getCurrentStoreDb();

}

Ceci facilite les évolutions futures et permet d’organiser les spécificités concernant Store dans cette classe.