Виртуальный атрибут Yii2 вне атрибута SqlDataProvider - PullRequest
0 голосов
/ 13 сентября 2018

Мой AddressController:

public function actionIndex() {
    $searchModel = new AddressSearch;
    $dataProvider = $searchModel->search($_GET);

    return $this->render('index', [
        'dataProvider' => $dataProvider,
        'searchModel' => $searchModel,
    ]);
}

Моя модель AddressSearch:

class AddressSearch extends Model {

    public function search($params) {
        $dataProvider = new SqlDataProvider([
            'sql' => '
                SELECT
                    name
                FROM...

Вид:

GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        'name2',

У меня есть атрибут с именем name в этом dataProvider. Я хотел бы создать новый виртуальный атрибут с именем name2 из name путем preg_replace(), который состоит из нескольких его частей. Сама функция работает. Я пробовал много разных вещей, но все еще не могу заполнить атрибут name2 данными. name2 всегда пусто. Можете ли вы указать мне правильное направление? Большое спасибо!

ОБНОВЛЕНИЕ: основываясь на блестящих идеях @Imaginaroom и @ rob006, я сделал следующее:

  • перемещено getName2() и атрибуты, которые я заполняю SqlDataProvider из базовой модели Address в AddressSearch
  • удалил пустую базовую модель Address, потому что она мне все равно не нужна. Меньше значит больше!
  • в search() Я добавил:

    foreach ($dataProvider->getModels() as $row) {
        $model = new AddressSearch;
        $model->setAttributes($row, false);
        $models[] = $model;
    }
    $dataProvider->setModels($models);
    

Это работает! Большое спасибо, ребята! Это здорово, что ты там и помогаешь !!!

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Если вам действительно нужен Address экземпляр модели и одновременно используется SqlDataProvider, вы можете преобразовать массив в экземпляр модели вручную:

$models = [];
foreach ($dataProvider->getModels() as $row) {
    $model = Address::instantiate($row);
    Address::populateRecord($model, $row);
    $models[] = $model;
}
$dataProvider->setModels($models);

Вы можете поместить это в AddressSearch::search() или создать пользовательский SqlDataProvider и переопределить prepareModels().

0 голосов
/ 14 сентября 2018

Проблема в том, что вы используете SqlDataProvider, который возвращает строки из таблицы в виде массива, а не экземпляра модели. Вот почему ваш геттер (виртуальный атрибут) не работает в GridView - GridView не работает на экземпляре модели Address, но на необработанном массиве без поля name2.

Вы должны изменить SearchModel на ActiveQuery:

$dataProvider = ActiveDataProvider([
    'query' => Address::find()->select(['name']) //and whatever your query contains besides this
])
...

ОБНОВЛЕНИЕ: Если вы не хотите делать это так, вы можете добавить свою логику прямо в GridView, например, так:

GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        [
            'header' => 'Name 2',
            'value' => function($model) {
                if (isset($this->_name2)) {
                    return $this->_name2;
                }

                return $this->_name2 = preg_replace([...
            }
        ]
...