2015-04-05 2 views
2

Как объявить публичную функцию attributes класса (модели), который простирается от ActiveRecord, если я готов использовать поддокументы?Поддокументы в 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'); 
     } 
    } 

} 

и модель для встроенного документа \ общие \ модели \ 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'], 
     ]; 
    } 

The general recommendation является avoiding 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'  
} 

который затем можно объявить как ActiveRecord класса путем расширения YII \ MongoDB \ 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

Смежные вопросы