Salve a tutti! Sono un principiante di Yii e avrei bisogno del vostro aiuto. La situazione è la seguente: ho bisogno di copiare una o più righe da una tabella situata in un db in un altra tabella gemella posta in un database differente. L’obiettivo è quello di popolare la tabella sul db di destinazione selezionando le voci da un istanza “madre” situata sul db originale.
Innanzitutto ho generato con Gii il model dell’entità, in questo caso “Sostanza”
class Sostanza extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* @param string $className active record class name.
* @return Sostanza the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'sostanza';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('famiglia_sostanza_id', 'numerical', 'integerOnly'=>true),
array('codice, descrizione', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, famiglia_sostanza_id, codice, descrizione', 'safe', 'on'=>'search'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'famigliaSostanza' => array(self::BELONGS_TO, 'FamigliaSostanza', 'famiglia_sostanza_id'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'famiglia_sostanza_id' => 'Famiglia Sostanza',
'codice' => 'Codice',
'descrizione' => 'Descrizione',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('famiglia_sostanza_id',$this->famiglia_sostanza_id);
$criteria->compare('codice',$this->codice,true);
$criteria->compare('descrizione',$this->descrizione,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* @param int $famiglia_sostanza_id
* @return array for listbuilder (id => name)
*/
public function findSostanzaByFamiglia($famiglia_sostanza_id)
{
$criteria=array(
'select'=>"id, descrizione",
'condition'=>'famiglia_sostanza_id='.$famiglia_sostanza_id,
'order'=>'id',
);
return CHtml::listData($this->findAll($criteria),'id','descrizione');
}
public function updateSostanzaFamiglia($id, $famiglia_sostanza_id)
{
$model=$this->findByPk($id);
$model->famiglia_sostanza_id=$famiglia_sostanza_id;
$model->update('famiglia_sostanza_id');
}
public function findAllSostanza()
{
$criteria=array(
'select'=>"id, descrizione",
'condition'=> '1=1',
'order'=>'id',
);
return CHtml::listData($this->findAll($criteria),'id','descrizione');
}
}
Poi, per gestire le due differenti connessioni ho esteso la classe CActiveRecord definendo la seconda connessione ("dbExport"):
<?php
class ExportedEntity extends CActiveRecord {
private static $dbExport = null;
protected static function getDbExportConnection()
{
if (self::$dbExport!== null)
return self::$dbExport;
else
{
self::$dbExport = Yii::app()->dbExport;
if (self::$dbExport instanceof CDbConnection)
{
self::$dbExport->setActive(true);
return self::$dbExport;
}
else
throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
}
}
}
A questo punto ho replicato la prima entità aggiungendo un override del metodo getDbConnection, di modo da riferire la nuova entità (che rappresenta le righe della tabella "Sostanza" su dbExport) al database di destinazione:
<?php
class SostanzaExport extends ExportedEntity{
public function getDbConnection(){
return self::getDbExportConnection();
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'sostanza';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('famiglia_sostanza_id', 'numerical', 'integerOnly'=>true),
array('codice, descrizione', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, famiglia_sostanza_id, codice, descrizione', 'safe', 'on'=>'search'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'famigliaSostanza' => array(self::BELONGS_TO, 'FamigliaSostanza', 'famiglia_sostanza_id'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'famiglia_sostanza_id' => 'Famiglia Sostanza',
'codice' => 'Codice',
'descrizione' => 'Descrizione',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('famiglia_sostanza_id',$this->famiglia_sostanza_id);
$criteria->compare('codice',$this->codice,true);
$criteria->compare('descrizione',$this->descrizione,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* @param int $famiglia_sostanza_id
* @return array for listbuilder (id => name)
*/
public function findSostanzaByFamiglia($famiglia_sostanza_id)
{
$criteria=array(
'select'=>"id, descrizione",
'condition'=>'famiglia_sostanza_id='.$famiglia_sostanza_id,
'order'=>'id',
);
return CHtml::listData($this->findAll($criteria),'id','descrizione');
}
public function updateSostanzaFamiglia($id, $famiglia_sostanza_id)
{
$model=$this->findByPk($id);
$model->famiglia_sostanza_id=$famiglia_sostanza_id;
$model->update('famiglia_sostanza_id');
}
public function findAllSostanza()
{
$criteria=array(
'select'=>"id, descrizione",
'condition'=> '1=1',
'order'=>'id',
);
return CHtml::listData($this->findAll($criteria),'id','descrizione');
}
/*
public function exportSostanza(){
$this->save();
}
*/
}
Ho aggiunto questa action al mio SiteController per implementare la copia dei dati e il salvataggio
public function actionExportSostanza()
{
if(isset($_POST['Sostanza']['export']))
{
foreach ($_POST['Sostanza']['export'] as $row){
$exportRow = new SostanzaExport;
$exportRow->attributes = $row->attributes;
$exportRow->id = null; //(if it's composite it's going to need more assignments than this)
$exportRow->isNewRecord = true;
$exportRow->save();
}
}
$this->redirect(array('site/index','view'=>'index'));
}
e infine l’ho collegata al widget che utilizzo nella view per visualizzare i due elenchi
<?php echo CHtml::beginForm($this->createUrl('exportSostanza')); ?>
<?php
$this->widget('ext.widgets.multiselects.XMultiSelects',array(
'leftTitle'=>'DB Source',
'leftName'=>'Sostanza[source][]',
'leftList'=>Sostanza::model()->findAllSostanza(),
'rightTitle'=>'DB Exported',
'rightName'=>'SostanzaExport[export][]',
'rightList'=>SostanzaExport::model()->findAllSostanza(),
'size'=>20,
'width'=>'200px',
));
?>
<br />
<?php echo CHtml::submitButton(Yii::t('ui', 'Save'), array('class'=>'btn btn-primary')); ?>
<?php echo CHtml::endForm(); ?>
Il widget carica correttamente le righe del db sorgente a sinistra e quelle del db export a destra. Tuttavia dopo aver spostato voci da sinistra a destra quando seleziono "save" ricevo un errore descritto come "Trying to get property of non-object".
Ho provato a ricercare in rete e nel forum ma non sono riuscito a identificare i miei errori o a trovare una maniera alternativa per ottenere la funzionalità di cui ho bisogno. Potete aiutarmi? Vi ringrazio in anticipo!