【问题标题】:Sorting list of VirtualPages on a field from its Page从其页面中对字段上的 VirtualPages 列表进行排序
【发布时间】:2016-08-04 13:21:49
【问题描述】:

我有一个AreaPage$many_many VirtualPages:

class AreaPage extends Page {

    /**
     * @var array
     */
    private static $many_many = [
        'RelatedVirtualPages'  => 'VirtualPage'
    ];

    // ...

}

RelatedVirtualPages 正在从ContentPages 复制内容:

class ContentPage extends Page {

    /**
     * @var array
     */
    private static $db = [
        'Highlighted' => 'Boolean'
    ];

    // ...

}

在它正在复制的ContentPageHighlighted db 字段上对RelatedVirtualPages 进行排序的最佳方法是什么?

【问题讨论】:

  • 不应该'RelatedVirtualPages' => 'VirtualPages' 是'RelatedVirtualPages' => 'VirtualPage' ?
  • 是的,你是对的 :-) 更新问题

标签: silverstripe


【解决方案1】:

虚拟页面可以指向不同类型的页面,并且没有强制要求所有这些页面都是ContentPages,或者至少是具有Hightlighted db 字段的页面。您可以在创建 SiteTree 时手动确保这一点,但用户可能会来搞砸,所以请记住这一点。

这里有一些伪代码可以帮助您入门。它假定所有虚拟页面都是ContentPages。如果AreaPage 引用了多种类型的VirtualPages,那么这可能还不够。

$virtualPages = $myAreaPage->RelatedVirtualPages();
$contentSourcePages = ContentPage::get()->byIDs($virtualPage->column('CopyContentFromID'));
$sortedSourcePages = $contentSourcePages->sort('Highlighted','ASC');

您也可以使用innerJoin,但是您必须处理_Live 表和可能的多个页表(同样,如果不只是将ContentPage 用作VirtualPage),这可能会导致一些复杂的情况。

更新

因此,用我自己的话总结一下,您需要一个链接到特定 AreaPageVirtualContentPages 列表,该列表按每个 VirtualContentPage 链接到的 ContentPage 字段中的 Highlighted 字段排序。如果这个总结是准确的,这是否可行:

$sortedVirtualPages = $myAreaPage->RelatedVirtualPages()
 ->innerJoin('ContentPage', '"ContentPage"."ID" = "VirtualContentPage"."CopyContentFromID"')
 ->sort('Highlighted DESC');

【讨论】:

  • 感谢您的回答并为我指明方向。伪代码给了我一个ContentPages 的排序列表,但我需要一个实际VirtualPages 的列表。我正在考虑做一些事情,比如获取VirtualPages,然后遍历它们,为每个对象添加一个Highlighted 属性(不写入,从被复制的页面复制值),然后将它们添加到一个 ArrayList,然后在Highlighted 上对 ArrayList 进行排序。想法?
  • 至于强制页面类型为ContentPage - 我省略了这些部分以提供问题的简单演示。在实际代码中,这是通过我扩展 VirtualPage(VirtualContentPage[VCP])这一事实来处理的,而VCP 只能存在于AreaPage 下,它只能托管VCPContentPage。如果编辑器更改VCP 以从AreaPage 复制内容,则会引发验证错误(~AreaPage 不允许作为AreaPage 的子级)。
  • 谢谢!您的总结是准确的,内连接解决方​​案绝对是最有效和最干净的解决方案。
【解决方案2】:

我找不到一个非常干净的方法,但确实找到了两种方法来实现这一点。该函数进入类 AreaPage
First

public function getRelatedVirtualPages()
{

    $items = $this->getManyManyComponents('RelatedVirtualPages');

    $highlighted = $items->filterByCallback(function($record, $list) {
        if($record->CopyContentFrom() instanceOf ContentPage) {
            //return ! $record->CopyContentFrom()->Highlighted; // ASC
            return $record->CopyContentFrom()->Highlighted; // DESC
        }
    });

    $highlighted->merge($items);
    $highlighted->removeDuplicates();

    return $highlighted;
}

第二种(你在cmets中描述的方法)

public function getRelatedVirtualPages()
{
    $items = $this->getManyManyComponents('RelatedVirtualPages');

    $arrayList = new ArrayList();

    foreach($items as $virtualPage) 
    {
        if($virtualPage->CopyContentFrom() instanceOf ContentPage) {
            $virtualPage->Highlighted = $virtualPage->CopyContentFrom()->Highlighted;
            $arrayList->push($virtualPage);
        }
    }

    $arrayList = $arrayList->sort('Highlighted DESC');

    return $arrayList;
}

我对这些解决方案中的任何一个都不是很自豪,但我相信它们确实符合您的标准。

【讨论】:

  • 谢谢!有趣的解决方案 1. 如果不是因为我还需要对另一个字段进行排序,那就是Date 而不是Boolean,我会选择它。解决方案 2. 是我首先选择的,但觉得它在性能方面很昂贵 - 为每次迭代查询数据库(?)。我在 AlphaCactus 的启发下对其进行了一些修改,只运行两个查询并保存结果。看我的回答
【解决方案3】:

这是我最终做的,我认为可行:

/**
 * @return ArrayList
 */
public function VirtualPages()
{

    $result       = [];
    $virtualPages = $this->RelatedVirtualPages();
    $contentPages = ContentPage::get()
        ->byIDs($virtualPages->column('CopyContentFromID'))
        ->map('ID', 'Highlighted')
        ->toArray();

    foreach($virtualPages as $virtualPage) {
        $highlighted = $contentPages[$virtualPage->CopyContentFromID];
        $virtualPage->Highlighted =  $highlighted;
        $result[] = $virtualPage;
    }

    return ArrayList::create(
        $result
    );

}

然后它可以像这样排序:

$areaPage->VirtualPages()->sort('Highlighted DESC');

感谢您的所有回答和指点。在标记任何答案之前,我会稍等片刻。

【讨论】:

    【解决方案4】:

    你就不能这样做

    //just get one areapage
    $AreaPageItem = AreaPage::get()->First();
    
    //now get the RelatedVirtualPages sorted
    $related_pages = $AreaPageItem->RelatedVirtualPages()->sort("Highlighted","ASC");
    

    【讨论】:

    • 很遗憾,这不起作用,因为 Highlighted 列在 VirtualPage 上不存在,并且会导致 MySQL 错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多