【问题标题】:Yii2 virtual attribute out of an attribute of a SqlDataProviderYii2虚拟属性出SqlDataProvider的一个属性
【发布时间】:2018-09-13 14:33:50
【问题描述】:

我的地址控制器:

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

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

我的模特地址搜索:

class AddressSearch extends Model {

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

查看:

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

我在这个dataProvider 中有一个名为name 的属性。我想通过preg_replace()创建一个名为name2 的新虚拟属性name 中的几个部分。 该功能本身正在运行。我尝试了很多不同的东西,但我仍然无法用数据填充属性name2name2 始终为空。你能指出我正确的方向吗?非常感谢!

更新:基于@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);
    

有效!非常感谢你们!有你在场并提供帮助真是太棒了!!!

【问题讨论】:

  • 如何检查 name2 ? ..显示代码..
  • 嗨,我已经添加了视图来显示它。

标签: yii2 virtual-attribute csqldataprovider


【解决方案1】:

问题在于您使用的是SqlDataProvider,它将表中的行作为数组而不是模型实例返回。这就是为什么您的 getter(虚拟属性)在 GridView 中不起作用的原因 - GridViewAddress 模型实例上不起作用,但在没有 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([...
            }
        ]

【讨论】:

  • 我也是这么想的,可能是因为model和dataProvider之间其实没有联系。没有其他方法可以实现吗?该模型未映射到 db 表。事实上,选择非常复杂,有很多连接,我不想创建所有连接,因为只有一个小页面,只显示一些简单的数据。
  • 我不确定你之后是否可以建立连接,我会在几分钟内更新答案,你如何可以直接在 GridView 中进行。
  • @user2511599 现在检查我更新的答案,看看它是否适合你。
  • 有没有办法以某种方式将其移动到模型中?至少在与基本模型没有连接时搜索模型?
  • 不管怎样,谢谢你,这对我有很大帮助,我现在可以让它工作了。
【解决方案2】:

如果您确实需要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()

【讨论】:

  • 那么不能在数组上使用函数吗?我的意思是你基本上是对的,但我正在寻找一种方法来尽可能地保持我的代码紧凑。我现在已经摆脱了模型地址,所以我只有地址搜索。我正在将函数name2 移动到地址搜索。我正在寻找一种让它像这样工作的方法。
  • 我真的不明白你的问题,但你可以尝试用AddressSearch 替换我的回答中的Address,看看它是否有效 - 这可能取决于你的AddressSearch 模型的样子.
  • AddressSearch 是一个标准的 gii 生成的 SearchModel,带有一个返回 $dataProvidersearch() 函数。
  • 它仍然没有解释你现在想要做什么以及你为什么放弃Address 模型。但无论如何,$dataProvider->getModels() 从数据提供者返回数据——你可以在简单的 foreach 中做任何你想做的事情。您只需将 name2 添加到此数组并使用 $dataProvider->setModels($models) 将其设置为数据提供者。
  • 调用未定义的方法 app\models\AddressSearch::instantiate()
猜你喜欢
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多