2016-07-19 25 views
1

実際に私はすべてのDBテーブルをモデルとして使用したいプロジェクトに取り組んでいます。しかし、今は1つのポイントにこだわっています。 多くの異なる関係が以下のように定義されている「マスター」 - テーブルがあるとしましょう(簡単な例)Yii2 //モデルのモデルの属性

人間はハートを1つ持っています。人間は1つの脳を持っています...など... マスターモデルを他のモデルで埋めることは可能ですか? PHPで それはですが、以下のようになります。

$human-save(TRUE); 

すべてのリレーショナル・モデルを検証し、すべてのリレーショナルデータとDBにおける人間のオブジェクトを保存する:

$human = new Human(); 
$human->heart = new Heart(); 
$human->brain = new Brain(); 

最後に、私は言いたいです。

これは可能ですか?私は全体のインターネットO_oでそのような何かを見つけることができません。

ありがとうございました!

+0

DBテーブルのモデルの関係は、通常、すべての書き込みの試行時にも適用されるため、何を検証するかはわかりません。サポートされている場合、DBレベルでは、TRANSACTIONブロック(失敗または成功)が表示されます。あなたはYiフレームワークからメソッドを探していますか?ありがとう。 – Dilettant

+0

ねえ、私はあなたにそれを明確にしようとします。 "true"パラメータで$ human-> save(true)を呼び出すと、モデル検証が強制されます。だから私の最初の質問です:私は1つのモデル(上記の例のような)で異なるモデルを持っている場合、 "サブモデル"も検証されていますか? 2番目の質問: モデルにモデルを入れるという目標には、どうすればアクセスできますか?これを達成するために私のメインモデルと私のサブモデルで何をしなければならないのですか? – jiGL

+0

@jiGL yii2のModelクラスには 'save()'メソッドがありません。 ActiveRecordやその他のORM実装を使用していますか? – oakymax

答えて

1

を私はあなたがアプローチを、以下のお勧め:

  1. はあなたがネストされたオブジェクトのプロパティ名と同じ関係名(いくつかのルールがあるとしましょう$model->link()メソッドを呼び出す必要があります)
  2. ネストされたモデルを持つモデルの共通クラスを宣言します(例:ActiveRecordWithNestedモデル)リフレクションを使用して(これらの操作のためのカスケードを実行するための一般的なクラスメソッドsavevalidate
  3. オーバーライド)
  4. あなたのモデルがvalidateを上書きする代替手段として、

それともこの共通のクラスを継承しますしてみましょうメソッドでは、共通クラスのrulesメソッドの適切な実装をいくつか構築できます。

次のように、この一般的なクラス缶が見えます(これは単純な案、テストされていない、ただ概念を示すためである):

class Heart extends ActiveRecordWithNestedModels 
{ 

} 

class Human extends ActiveRecordWithNestedModels 
{ 
    /* @var Heart $heart */ 
    public $heart = null; 

    /** 
    * The relation name will be 'heart', same as property `heart' 
    * 
    * @return \yii\db\ActiveQuery 
    */ 
    public function getHeart() 
    { 
     return $this->hasOne(Heart::className(), ['id', 'heart_id']); 
    } 
} 
:次に

<?php 

namespace app\models; 

use yii\db\ActiveRecord; 

class ActiveRecordWithNestedModels extends ActiveRecord 
{ 

    public function save($runValidation = true, $attributeNames = null) 
    { 
     $saveResult = parent::save($runValidation, $attributeNames); 

     $class = new \ReflectionClass($this); 

     foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { 
      $propertyValue = $property->getValue($this); 
      if (!empty($propertyValue) && is_subclass_of($propertyValue, ActiveRecord::className())) { 
       /* @var ActiveRecord $nestedModel */ 
       $nestedModel = $propertyValue; 
       $nestedModel->save($runValidation); 
       $relation = $property->name; 
       $this->link($relation, $nestedModel); 
      } 
     } 

     return $saveResult; 
    } 

    public function validate($attributeNames = null, $clearErrors = true) 
    { 
     $class = new \ReflectionClass($this); 

     foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { 
      $propertyValue = $property->getValue($this); 
      if (!empty($propertyValue) && is_subclass_of($propertyValue, ActiveRecord::className())) { 
       /* @var ActiveRecord $nestedModel */ 
       $nestedModel = $propertyValue; 

       if (!$nestedModel->validate(null, $clearErrors)) { 
        array_push($this->errors, [ 
         $property->name => $nestedModel->errors 
        ]); 
       } 
      } 
     } 

     parent::validate($attributeNames, $clearErrors); 

     if ($this->hasErrors()) return false; 

     return true; 
    } 

} 

あなたのモデルにすることができますが、このようになります。あなたが行うことができます

そして、(理論的に):

$human = new Human(); 
$human->heart = new Heart(); 
$human->save(); 

P.ここは、例えば、さらなる実装では多くの複雑な詳細については、することができ、いくつかの子オブジェクトが

  • オーバーライドdelete
  • 場合カスケードをスキップone-to-manymany-to-many関係を提供し、保存に失敗した場合saveをロールバックするトランザクションを使用して

    • プロパティには対応する関係はありません
    • $attributeNamesをカスケード演算で実行
    • など
  • +0

    うん!これはまさに私が探していたものです...ありがとうございました! これはちょっと簡単かもしれないし、yii2の箱の中に似たようなものがあると思った。とにかくありがとう! – jiGL

    +0

    @jiGLようこそ。お役に立てれば – oakymax

    1

    あなたはdocsによると、ActiveModelSaveメソッドをオーバーライドすることができます。

    public function save($runValidation = true, $attributeNames = null) 
    { 
        if ($this->getIsNewRecord()) { 
         $save = $this->insert($runValidation, $attributeNames); 
        } else { 
         $save = $this->update($runValidation, $attributeNames) !== false; 
        } 
    
        /* Condition Work if heart and brain is also ActiveModel then 
         you can trigger save method on these models as well 
         or you can add your custom logic as well. 
        */ 
    
        if($this->heart && $this->brain) { 
         return $this->heart->save() && $this->brain->save(); 
        } 
    
        return $save; 
    
    }