Виртуальный атрибут Yii2 вне атрибута SqlDataProvider

Мой 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 ответа

Решение

Проблема в том, что вы используете 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([...
            }
        ]

Если вам действительно нужно 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(),

Другие вопросы по тегам