2015-04-05 60 views
2

如果我愿意使用子文档,我应该如何声明从ActiveRecord延伸的类(模型)的attributes公共函数?MongoDB和Yii2中的子文档

就拿这个简单的MongoDB的结构:

_id: 'a34tfsert89w734y0tas9dgtuwn034t3', 
name: 'Bob', 
surnames: { 
    'first': 'Foo', 
    'second': 'Bar' 
}, 
age: 27, 
preferences: { 
    lang: 'en', 
    currency: 'EUR' 
} 

应该怎样我attributes功能是什么样子?

public function attributes() { 
    return [ 
     '_id', 
     'name', 
     'surnames', 
     'surnames.first', <--- like this? 
     ..... 
    ] 
} 

回答

1

MongoDB的扩展的Yii 2 does not provide any special way to work with embedded documents (sub-documents)。要做到这一点,你需要首先处理自定义验证。你可以试试下面的办法:一般模式是,首先建立一个custom validator,说\ COMMON \ \验证EmbedDocValidator.php

namespace common\validators; 

use yii\validators\Validator; 

class EmbedDocValidator extends Validator 
{ 
    public $scenario; 
    public $model; 

    /** 
    * Validates a single attribute. 
    * Child classes must implement this method to provide the actual validation logic. 
    * 
    * @param \yii\mongodb\ActiveRecord $object the data object to be validated 
    * @param string $attribute the name of the attribute to be validated. 
    */ 
    public function validateAttribute($object, $attribute) 
    { 
     $attr = $object->{$attribute}; 
     if (is_array($attr)) { 
      $model = new $this->model; 
      if($this->scenario){ 
       $model->scenario = $this->scenario; 
      } 
      $model->attributes = $attr; 
      if (!$model->validate()) { 
       foreach ($model->getErrors() as $errorAttr) { 
        foreach ($errorAttr as $value) { 
         $this->addError($object, $attribute, $value); 
        } 
       } 
      } 
     } else { 
      $this->addError($object, $attribute, 'should be an array'); 
     } 
    } 

} 

和模型嵌入的文档\ COMMON \型号\ Preferences.php

namespace common\models; 

use yii\base\Model; 

class Preferences extends Model 
{ 

    /** 
    * @var string $lang 
    */ 
    public $lang; 

     /** 
    * @var string $currency 
    */ 
    public $currency; 


    public function rules() 
    { 
     return [ 
      [['lang', 'currency'], 'required'],   
     ]; 
    } 

} 

而在顶级机型 在共同\型号setup the validator \ user.php的:

public function rules() 
    { 
     return [ 
      [['preferences', 'name'], 'required'], 
     ['preferences', 'common\validators\EmbedDocValidator', 'scenario' => 'user','model'=>'\common\models\Preferences'], 
     ]; 
    } 

general recommendationavoiding use of embedded documents在文档的顶部水平移动它们的属性。例如:代替

{ 
    name: 'Bob', 
    surnames: { 
     'first': 'Foo', 
     'second': 'Bar' 
    }, 
    age: 27, 
    preferences: { 
     lang: 'en', 
     currency: 'EUR' 
    } 
} 

使用以下结构:

{ 
    name: 'Bob', 
    surnames_first: 'Foo', 
    surnames_second: 'Bar' 
    age: 27, 
    preferences_lang: 'en', 
    preferences_currency: 'EUR'  
} 

,然后可以通过延伸YII \ mongodb的\ ActiveRecord的声明作为ActiveRecord类并实现collectionName'attributes'方法:

use yii\mongodb\ActiveRecord; 

class User extends ActiveRecord 
{ 
    /** 
    * @return string the name of the index associated with this ActiveRecord class. 
    */ 
    public static function collectionName() 
    { 
     return 'user'; 
    } 

    /** 
    * @return array list of attribute names. 
    */ 
    public function attributes() 
    { 
     return ['_id', 'name', 'surnames_first', 'surnames_second', 'age', 'preferences_lang', 'preferences_currency']; 
    } 
} 
+0

对不起,在这里回复。既然你的回答是我在这个问题上与Yii开发者联系的,那么让我们来看看这会促使我们:https://github.com/yiisoft/yii2/issues/4899 – alexandernst 2015-04-08 16:35:36