yii2 使用来自同一模型的下拉列表过滤网格

yii2 Filtering grid with dropdown list from same model

我在我的 Contact 模型中使用了以下函数

public static function getParents()
{
    return $this->hasMany(Contact::className(), ['parent_id' => 'id']); 
}

我想在我视图的过滤属性中得到这个数组的return:

        [
        'attribute' => 'parent_id',
        'value' => function ($model) {
            return $model->parent ? $model->parent->name : null;
        },
        'hAlign' => 'left',
        'vAlign' => 'middle',
        //'filter' => ArrayHelper::map(Contact::find()->where(['<>', 'parent_id', 0])->orderBy('name')->asArray()->all(), 'id', 'name'),
        'filter' => ArrayHelper::map(Contact::parents()->asArray()->all(), 'id', 'name'),
        'filterWidgetOptions' => [
            'pluginOptions' => ['allowClear' => true],
        ],
        'filterInputOptions' => ['placeholder' => 'Parent'],
        'format' => 'raw'
    ],

但我收到以下错误:调用未定义的方法 common\models\Contact::parents()

其余关系工作正常,例如属性 $model->parent

我使用的是以下代码,但它是错误的,因为没有在同一个 table 中引入 parent_id 的名称,而是使用 parent_id

'filter' => ArrayHelper::map(Contact::find()->where(['<>', 'parent_id', 0])->orderBy('name')->asArray()->all(), 'id', 'name'),

我设法使用表单中的 2 个查询修复了我的过滤器,但不是很优雅:

$subQuery = Contact::find()->select('parent_id')->where(['<>', 'parent_id', 0]);
$parents = ArrayHelper::map(Contact::find()->where(['in', 'id', $subQuery])->orderBy('name')->asArray()->all(), 'id', 'name')

正确答案后更新

我将逻辑放在模块中以在其他地方重用它并使用 getParentsArray 而不是 parentsArray

public static function getParentsArray() {
    $subQuery = Contact::find()->select('parent_id')->where(['<>', 'parent_id', 0]);
    $parents = ArrayHelper::map(Contact::find()->where(['in', 'id', $subQuery])->orderBy('name')->asArray()->all(), 'id', 'name');
    return $parents;
}

在视图或控制器中

$parents = Contact::getParentsArray();

我认为你的问题是这样的;您正在使用 Contact::parents() 方法,但您的模型中不存在此方法。你已经声明了一个方法 getParents(),它允许 Yii 使用神奇的 getter 方法访问 parents 作为 Contact::parents.

Yii 使用这两个函数的方式有一个细微但重要的区别,这将影响您如何使用它们来生成适合在下拉列表中使用的数组: 首先,Contact::parents() 使用您声明的关系来获取所有父记录。正如您在方法中声明的那样,它 returns class Contact 的模型数组。

第二种方式是直接调用静态方法getParents()。这样做的好处是它 returns 是 ActiveQuery 的一个实例,然后允许您使用与 ActiveQuery.[=23 关联的 asArray()all() 方法=]

因此,对于您的用例,我会在模型中添加一些代码来生成您的下拉菜单。这样做的好处是它将模型逻辑(这是)保留在模型内部,然后它也可以在其他情况下重用。

因此,在您的模型中创建此方法;

public static function getParentsArray(){
return ArrayHelper::map(self::getParents()->asArray()->all(), 'id', 'name');
}

然后您可以像这样在您的视图文件中使用它;

'filter' => Contact::parentsArray()

Contact::parents() 表达式正在调用您的代码中不存在的静态方法 parents()。它这个上下文 parents() 不是关系。没有使用此表达式初始化的QueryInterface。

对于您的任务,使用 $dataProvider 作为基础来关联 parents。

'filter' => ArrayHelper::map($dataProvider->getModels()[0]->parents->find()->all(),'id','name'),

可能在这里您已经验证了 $dataProvider 的大小以进入第一级。