Yii接続多対多

多対多



エントリー



こんにちは、Habr! 多くの場合、Yiiで多対多の通信機能を実装する必要に直面しました。 複雑なことは何もないように思われ、おそらくフレームワークの開発者はすでに必要な通信機能を実装しようとしており、必要な接続のみをモデルに登録し、通常の方法を使用してデータを保存できます。



しかし、Yiiはそのような機能を提供していません。明らかに、後のバージョンに登場するか、追加の拡張機能によってのみ拡張される可能性があります。 その結果、私たち自身でコミュニケーションを実装する必要があります。

もちろん、誰もがベストを尽くして出てきます。誰かが戦闘でうまく機能している拡張機能を使用しています。 例:with-related-behavior プロジェクトリポジトリ

データを保存または更新するときに、誰かがメソッドに直接リンクを書き込みます。 しかし、このアプローチには大きなマイナス点があります。 プロジェクト内のエンティティ間に多くの関係がある場合、メソッド内でコードを複製する必要があります。これは、その後、読みやすさとそのサポートの低下に影響します。

しかし、エンティティが多数あり、大量のデータをバインドする必要がある場合はどうでしょうか?

単純な実装を作成して、必要に応じて簡単に書き換えて、プロジェクトでさらにサポートできるようにします。



理論のビット



多対多の関係タイプでは、1つのテーブルのエントリは別のテーブルの複数のレコードに関連付けられ、2番目のテーブルのエントリは最初のテーブルの複数のレコードに関連付けられます。

このタイプの関係では、ピボットテーブルと呼ばれる3番目のテーブルを作成する必要があります。 ピボットテーブルには、最初の2つのテーブルの主キーが外部キーとして含まれています。



実装



例として、製品をいくつかの材料で作成できるタスクを考えてみましょう。



多対多

ProductMaterialサマリーエンティティの移行は次のようになります。ProductおよびMaterialエンティティの外部キーが追加されます。



#protected/migrations/m140314_091505_addProductMaterialTable.php class m140314_091505_addProductMaterialTable extends CDbMigration { public function safeUp() { $prefix = $this->getDbConnection()->tablePrefix; $this->createTable('{{productMaterial}}', array( 'id' => 'int(10) unsigned NOT NULL AUTO_INCREMENT', 'productId' => 'int(10) unsigned NOT NULL', 'materialId' => 'int(10) unsigned NOT NULL', 'PRIMARY KEY (`id`)', ), 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'style (to which productMaterial should belong)\';'); $this->addForeignKey($prefix.'productMaterial_product_fk_constraint', '{{productMaterial}}', 'productId', '{{product}}', 'id', 'RESTRICT', 'CASCADE'); $this->addForeignKey($prefix.'productMaterial_material_fk_constraint', '{{productMaterial}}', 'materialId', '{{material}}', 'id', 'RESTRICT', 'CASCADE'); } }
      
      





次に、関係を保存、追加、変更する動作を説明します。



 #protected/extensions/ManyToManyRelationBehavior.php class ManyToManyRelationBehavior extends CBehavior{ /** * @var string name model Relation */ public $modelNameRelation; /** * @var string field name for the relationship with the current models */ public $fieldNameModelCurrent = null; /** * @var string field name for the relationship with the external models */ public $fieldNameModelRelation = null; /** * @var array list of values ​​of the current model */ public $relationList = array(); public function events() { return array_merge(parent::events(), array( 'onAfterSave' => 'afterSave', )); } public function afterSave($event){ if (is_array($this->relationList)){ $model = $this->modelNameRelation; $delete = $model::model()->deleteAll("{$this->fieldNameModelCurrent} =:param", array( ":param" => $this->owner->id, )); foreach ($this->relationList as $value){ $model = new $this->modelNameRelation; $model->{$this->fieldNameModelRelation} = intval($value); $model->{$this->fieldNameModelCurrent} = $this->owner->id; if (!$model->save()){ Yii::log('Unable to save relation: '.serialize($model->getErrors()), 'warning'); return false; } } } return true; } }
      
      





新しい製品を作成するときに動作を使用する例:



 public function actionCreate() { $model=new Product; $materialList = $_POST['Product']['materialId']; $model->attachBehavior('ManyToManyRelationBehavior', array( 'class' => 'ext.ManyToManyRelationBehavior', 'modelNameRelation' => 'ProductMaterial', //     'fieldNameModelCurrent' => 'productId',//      Product 'fieldNameModelRelation' => 'materialId', //      Material 'relationList' => $materialList, // array id material ));
      
      





モデルを介して商品素材を迅速に受け取るには、throughパラメーターを介してそれらをリンクすることにより、必要なリレーションを製品モデルに追加します。



  #protected/models/Product.php public function relations() { return $this->moderationRelations(array( 'materialAll' => array(self::HAS_MANY, 'ProductMaterial', 'productId'), 'materialRelation' => array(self::HAS_MANY, 'Material', 'materialId', 'through' => 'materialAll'), )); }
      
      





これで、商品素材を簡単に入手できます。



 $model = Material::model()->findByPk($pk); $model->materialAll;
      
      





おわりに



Yii開発者がフレームワークに必要なすべての機能を含めることができないことは明らかです。 しかし、それらは透過的にアクセスできる拡張機能を簡単に作成する絶好の機会を与えてくれました。拡張機能はプロジェクト間で転送できます。 また、既存の拡張機能を使用することは必ずしも便利ではありません。 それらの研究と機能の完成に多くの時間を費やすことができます。 この間、独自の実装を記述できます。これは、将来の保守と調整が容易です。



行動リポジトリ



All Articles