【问题标题】:SilverStripe - Filter DataList results to remove duplicates and group by valueSilverStripe - 过滤 DataList 结果以删除重复项并按值分组
【发布时间】:2017-04-03 20:28:15
【问题描述】:

我正在用 SilverStripe 中的 DataLists 尝试一些不同的东西。目标是以这种格式返回按状态排序的商店列表。

创建了一个名为 StoreLocation.php 的管理模型,其中包含商店数据:

class StoreLocation extends DataObject {

    private static $db = array(
        'Address'   => 'Varchar(250)',
        'City'      => 'varchar(100)',
        'State'     => 'varchar(2)',
        'Zip'       => 'varchar(10)'
    );

    private static $has_one = array(
        'Store' => 'Store'
    );

    private static $summary_fields = array(
        'getStoreSummaryLabel' => 'Store Info'
    );

    private static $field_labels = array(
        'Address',
        'City',
        'State',
        'Zip'
    );

    public function getStoreSummaryLabel() {
        $storeName = $this->Store()->Name;
        return sprintf("%s (%s)", $storeName, $this->addressPretty());
    }

    // tidy up the CMS by not showing these fields
    public function getCMSFields() {
        $fields = parent::getCMSFields();

        $siteConfig = SiteConfig::current_site_config();

        $statesDropdown = DropdownField::create("State", "State", $siteConfig->stateList())
            ->setEmptyString('Select State');

        if ($siteConfig->GoogleAPIKey == "") {
            $fields->addFieldToTab("Root.Main", new HeaderField("error","Error: No Google API Key Defined!",2));
        }

        $fields->removeFieldsFromTab('Root.Main', [
            'State',
        ]);

        return $fields;
    }

    public function addressPretty() {
        return sprintf("%s %s, %s %s", $this->data()->Address, $this->data()->City, $this->data()->State, $this->data()->Zip);
    }
}

Store DataObjectStoreLocation 引用:

class Store extends DataObject {
    private static $db = array(
        'Name' => 'Varchar(100)'
    );

    private static $has_one = array(
        'Logo' => 'Image'
    );

    private static $has_many = array(
        'Locations' => 'StoreLocation'
    );

    private static $summary_fields = array(
        'Name' => 'Name'
    );

    private static $field_labels = array(
        'Name',
        'Logo'
    );

    // tidy up the CMS by not showing these fields
    public function getCMSFields() {
        $fields = parent::getCMSFields();
        return $fields;
    }

    static $default_sort = "Name ASC";
}

问题是我需要按州返回商店列表,但删除所有重复的商店名称,因为我没有显示商店地址。我只需要显示名称(我不知道为什么。这就是必须的)。因此,例如,Store ABC in Alabama 可能有 5 个结果,因为它有 5 个位置,但我只想为 Alabama 返回 Store ABC 一次。

只需以这种格式返回 StoreLocation 数据列表即可返回正确的结果,但会出现大量重复,并且每个商店上方都会重复状态名称:

更新:在发现包含自定义嵌套分组列表类文件的此链接后,我找到了一个可能的解决方案:https://www.silverstripe.org/community/forums/general-questions/show/24195

通过使用该类,我能够创建一个 GroupedList,我可以在其中按数据对象的 2 个不同方面进行排序:

public function GroupedEntries() {
    return NestedGroupedList::create(
        StoreLocation::get()->sort('State ASC, StoreID ASC')
    );
}

然后,在模板中,我设置了这个:

<div class="col-md-12" style="padding-bottom:40px;">
    <div class="retailer-listing" style="text-align: left;">
        <% loop $GroupedEntries.GroupedBy('State,StoreID') %>
            <strong>$State</strong><br />
                <% loop $Children %>
                        <% loop $Children.First %>
                            $Store.Name<br />
                        <% end_loop %>
                <% end_loop %>
        <% end_loop %>
     </div>
</div>

这似乎返回了正确的结果组织,按状态按字母顺序对每个商店名称的第一个实例进行排序。我进行了一些猜测和检查测试,直到我得到了正确的循环。

【问题讨论】:

  • 请分享getAllRetailersByState函数的内容
  • 目前,这是我在帖子底部的内容:$counter =GroupedList::created(StoreLocation::get())->GroupedBy('State')

标签: php silverstripe


【解决方案1】:

首先,我们创建一个函数以在我们的页面控制器中返回 StoreLocation 项中的 GroupedList

public function getGroupedStoreLocations() {
    return GroupedList::create(StoreLocation::get()->sort('State'));
}

然后,在我们的页面模板中,我们在 GroupedStoreLocations 函数上调用 GroupedBy(State) 来对列表进行分组。这将返回组项的ArrayList,其中包含索引(舞台名称)和属于该组的子项列表。在 GroupedStoreLocations 循环中,我们可以遍历 $Children 以遍历 GroupedList 中的每个项目:

<% loop $GroupedStoreLocations.GroupedBy(State) %>
    <h4>$State</h4>
    <ul>
    <% loop $Children %>
        <li>$Store.Name</li>
    <% end_loop %>
    </ul>
<% end_loop %>

GroupedList Documentation 页面上查看更多信息。

【讨论】:

  • 这非常接近我的需要,但一个问题是 $Children 循环返回与状态关联的每个商店的名称——这意味着会发生重复,因为可能有多个位置一个州的一家商店(即俄亥俄州可能有很多沃尔格林和一堆沃尔玛)。
  • 我会调查一下,看看有什么我们可以做的。
  • 我想我可能有东西。希望明天我会在这里发布。这不是有史以来最伟大的事情,但它似乎有效。
  • 好的,我在初始条目中添加了可能的解决方案
  • 太棒了@DejsaCocan。将您的解决方案作为答案发布,而不是对您的问题进行编辑。
【解决方案2】:

在发现这个包含自定义嵌套分组列表类文件的链接后,我找到了一个解决方案:https://www.silverstripe.org/community/forums/general-questions/show/24195

通过使用该类,我能够创建一个 GroupedList,我可以在其中按数据对象的 2 个不同方面进行排序:

public function GroupedEntries() {
    return NestedGroupedList::create(
        StoreLocation::get()->sort('State ASC, StoreID ASC')
    );
}

然后,在模板中,我设置了这个:

  <div class="col-md-12" style="padding-bottom:40px;">
        <div class="retailer-listing" style="text-align: left;">
            <% loop $GroupedEntries.GroupedBy('State,StoreID') %>
                <strong>$State</strong><br />
                    <% loop $Children %>
                            <% loop $Children.First %>
                                $Store.Name<br />
                            <% end_loop %>
                    <% end_loop %>
            <% end_loop %>
         </div>
    </div>

这似乎返回了正确的结果组织,按状态按字母顺序对每个商店名称的第一个实例进行排序。我进行了一些猜测和检查测试,直到我得到了正确的循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2010-12-25
    相关资源
    最近更新 更多