按相关实体字段排序 Sonata Admin 中的列表视图

Posted

技术标签:

【中文标题】按相关实体字段排序 Sonata Admin 中的列表视图【英文标题】:Sort list view in Sonata Admin by related entity fields 【发布时间】:2016-07-09 06:44:11 【问题描述】:

使用 Sonata Admin Bundle,它是 Symfony 的一个很好的附加组件,我遇到了如下描述的问题。

假设我们有 3 个实体:City、State 和 Country。它们都具有属性idname。 City 与 State 是多对一的关系,State 与 Country 是多对一的关系。它们都有__toString 方法显示属性名称的值。

我们可以像这样在 Sonata Admin 中为实体 City 创建一个列表视图:

protected function configureListFields(ListMapper $listMapper)

    $listMapper
        ->addIdentifier('id')
        ->add('name')
        ->add('state')
        ->add('state.country')
    ;

为了说明,视图可能如下所示:

|-----||--------------------||--------------------||--------------------|
| Id ^|| Name ^             || State              || State Country      |
|-----||--------------------||--------------------||--------------------|    
| 1   || New York           || New York           || USA                |
| 2   || Acapulco           || Guerrero           || Mexico             |
| 3   || Calgary            || Alberta            || Canada             |
| 4   || Tijuana            || Baja California    || Mexico             |
| 5   || Vancouver          || British Columbia   || Canada             |
| 6   || Los Angeles        || California         || USA                |
|-----||--------------------||--------------------||--------------------|

默认情况下,该列表可按 IdName 列排序,符号 ^ 应说明这一点。我希望能够按相关实体字段对列表进行排序,并有一个指向相关实体的显示操作的链接。

这是我如何实现按状态排序的:

//...
->add('state', null, array(
    'route' => array('name' => 'show'),
    'sortable' => true,
    'sort_field_mapping' => array('fieldName' => 'name'), // property name of entity State
    'sort_parent_association_mappings' => array(array('fieldName' => 'state')) // property state of entity City
))
//...

现在列表视图可以按实体 State 的属性 name 排序,并且 State 列中的所有字段都指向显示页面对于当前状态:

|-----||--------------------||--------------------||--------------------|
| Id ^|| Name ^             || State ^            || State Country      |
|-----||--------------------||--------------------||--------------------|    
| 3   || Calgary            || Alberta            || Canada             |
| 4   || Tijuana            || Baja California    || Mexico             |
| 5   || Vancouver          || British Columbia   || Canada             |
| 6   || Los Angeles        || California         || USA                |
| 2   || Acapulco           || Guerrero           || Mexico             |
| 1   || New York           || New York           || USA                |
|-----||--------------------||--------------------||--------------------|

如何按Country(City->State->Country)对列表视图进行排序?像这样的:

|-----||--------------------||--------------------||--------------------|
| Id ^|| Name ^             || State ^            || State Country      |
|-----||--------------------||--------------------||--------------------|    
| 3   || Calgary            || Alberta            || Canada             |
| 5   || Vancouver          || British Columbia   || Canada             |
| 2   || Acapulco           || Guerrero           || Mexico             |
| 4   || Tijuana            || Baja California    || Mexico             |
| 6   || Los Angeles        || California         || USA                |
| 1   || New York           || New York           || USA                |
|-----||--------------------||--------------------||--------------------|

当我尝试类似上面的代码 sn-p:

//...
->add('state.country', null, array(
    'route' => array('name' => 'show'),
    'sortable' => true,
    'sort_field_mapping' => array('fieldName' => 'country.name'), // property name of entity Country
    'sort_parent_association_mappings' => array(array('fieldName' => 'state.country')) // property country of entity State
))
//...

然后抛出异常错误。我尝试了不同的组合,但都没有成功。

我能做到:

  protected function configureListFields(ListMapper $listMapper)

    $listMapper
        ->addIdentifier('id')
        ->add('name')
        ->add('state.name')
        ->add('state.country.name')
    ;

并解决了排序问题,但没有指向实体的链接。

官方文档很好,但是缺少这个话题。那么,如何按层次实体对列表视图进行排序呢?

【问题讨论】:

【参考方案1】:

发布问题后的第二天,我正在挖掘 SonataAdminBundle 和 Symfony 的源代码并找到了解决方案。这实际上很容易。就是这样:

//...
->add(
    'state.country',
    null,
    array(
        'associated_property' => 'name', // property name of entity Country
        'sortable' => true, // IMPORTANT! make the column sortable
        'sort_field_mapping' => array(
            'fieldName' => 'name' // property name of entity Country
        ),
        'sort_parent_association_mappings' => array(
            array('fieldName' => 'state'), // property state of entity City
            array('fieldName' => 'country') // property country of entity State
        )
    )
)
//...

使用associated_property,我们设置了应该显示的属性。如果我们在实体中定义了__toString 方法,则可以省略它。在这种情况下,这意味着国家名称将显示在列中。

选项sort_field_mapping 需要一个带有键fieldName 的数组,该数组包含我们排序所依据的属性。在这里,我们按国家名称排序。然而,我们可以按人口排序,假设我们在实体 Country 中拥有该属性,尽管我们正在显示名称的值。

sort_parent_association_mappings 是最有趣的部分。这里我们定义了应该用来创建连接查询的属性: City 有一个属性 state,它是实体 State,它本身的属性 country 是实体 Country。

我希望我的解释是可以理解的,也可以帮助其他人。

【讨论】:

嗨!您愿意将其作为食谱文章贡献给 Sonata 文档吗? 这真的很棒! 非常感谢您的报价。这样做对我来说是一种荣幸。 你是个巫师!谢谢! 优秀的答案。官方文档仍然没有涵盖这个

以上是关于按相关实体字段排序 Sonata Admin 中的列表视图的主要内容,如果未能解决你的问题,请参考以下文章

Sonata Admin - 按关系字段排序

Sonata Admin 中的多个嵌套集合字段

Sonata Admin,内联编辑实体

Sonata Admin - 布尔字段类型,标签不显示

configureListFields 中的 Sonata Admin 自定义查询

Sonata Admin - 按计算值排列的订单列表