在 controller/to 过滤器查询中使用 has_one、has_many 和 many_many

using has_one, has_many, and many_many in controller/to filter queries

我在 silverstripe.org 网站上观看了第 7 课 - 第 10 课的视频,阅读了此页面上的所有文章:http://docs.silverstripe.org/en/3.1/developer_guides/model/,都在 API 中并且在 silverstripe/Whosebug 论坛上搜索了几个小时。我真的很难尝试应用我学到的东西。这是我正在尝试做的。我想扩展文章持有者和文章页面的概念。我正在尝试制作另一个作为主文章持有者的页面,我的站点树将按如下方式组织:

HomePage
   |
   | _ MasterArticleHolderOne
   |      |
   |      | _ ArticleHolderA
   |      |      |
   |      |      | _ ArticlePageA1
   |      |      |
   |      |      | _ ArticlePageA2
   |      |      |          
   |      |      | _ ArticlePageA3
   |      |
   |      |
   |      | _ ArticleHolderB
   |      |      |
   |      |      | _ ArticlePageB1
   |      |      |
   |      |      | _ ArticlePageB2
   |      |      |          
   |      |      | _ ArticlePageB3
   |      |
   |      |
   |      | _ ArticleHolderB
   |             |
   |             | _ ArticlePageB1
   |             |
   |             | _ ArticlePageB2
   |             |          
   |             | _ ArticlePageB3
   |       
   | _ MasterArticleHolderTwo

我希望 MasterArticleHolder 页面这样做:在 CMS 中,MasterArticleHolder 页面将有一个选项可以 select 任何现有的 ArticleHolder 页面(这意味着即使是上面的 MasterArticleHolderTwo 也可以显示来自 ArticleHolderA 的文章或 B 或 C),然后 MasterArticleHolder 页面将显示所有作为 selected ArticleHolder 页面子级的文章。这些文章需要按 PublicationDate 排序;没有按他们所属的持有人分组。

这是我到目前为止编写的代码。 ArticlePage 和 ArticleHolder 工作完美。这是我正在努力解决的 MasterArticleHolder(尽管我确实设法至少为所有现有的 ArticleHolder 页面创建了出现在 CMS 中的复选框,不知道它是否会在其他所有内容写入后实际运行):

文章页数

class ArticlePage extends Page {

    private static $db = array(
        'PublicationDate' => 'Date',
    );

    public function getCMSFields() {
        $fields = parent::getCMSFields();

        $fields->addFieldToTab('Root.Main', DateField::create('PublicationDate','Publication Date')->setConfig('showcalendar', true));

        return $fields;
    }
}

文章持有人

class ArticleHolder_Controller extends Page_Controller {

    public function LatestArticles() {
        return ArticlePage::get()
            ->filter('PublicationDate:LessThanOrEqual', SS_Datetime::now())
            ->sort('PublicationDate', 'DESC');
    }
}

MasterArticleHolder

class MasterArticleHolder extends Page {

    private static $many_many = array (
        'Categories' => 'ArticleHolder'
    );

    public function getCMSFields() {
        $fields = parent::getCMSFields();

        $fields->addFieldToTab('Root.Main', CheckboxSetField::create(
            'Categories',
            'Articles to Display',
            ArticleHolder::get()->map('ID','MenuTitle')
        ));

        return $fields;
    }

}
class MasterArticleHolder_Controller extends Page_Controller {

    public function LatestArticles() {
        return ArticlePage::get()
            ->filter(array('PublicationDate:LessThanOrEqual' => SS_Datetime::now()))
            ->sort('PublicationDate', 'DESC')
    }
}

在我看来,可能有以下关系,但我不知道需要哪一个,如果有的话

以下关系也可能适用,但对我来说不太可能

现在我通常知道 has_one、has_many 和 many_many 适用于扩展 DataObject 的对象,但我认为由于页面以一种迂回的方式扩展了 DataObject这些关系可能仍然适用,但我可能完全错了,真的想得太多了。

希望我对自己的解释足够好,以便获得帮助,但又不会让所有人不知所措。感谢反馈!

您应该深入学习教程,这(使用 Pages)...并不是最好的解决方案。它可以工作,但非常复杂,并不是一个好主意。

如果您将此作为学习练习,那很好,但如果不是,则只需使用博客模块 http://addons.silverstripe.org/add-ons/silverstripe/blog - 它基本上就是这样做的。

本练习最好使用 DataObjects 而不是 Pages。参见视频教程 9 (http://www.silverstripe.org/learn/lessons/working-with-data-relationships-has-many)

您现在所拥有的一个简单的解决方案是:

ArticlePage::get()
  ->filter([
    'ParentID'=>$this->Categories()->getIDList(),
    'PublicationDate:LessThanOrEqual'=>'now'
  ])
  ->sort('PublicationDate','desc');

基本上:获取每篇文章的父项都是我选择的类别之一(然后是您现有的过滤器、排序等)。

使用 DataObjects 而不是 Pages 基本上是一样的(页面是 DataObjects),但是站点树(在 CMS 中)的污染和与子项有关的层次结构问题等更少。

但另一方面,您失去了自动路由以及佩奇为您提供的各种其他功能。这就是为什么如果您不只是想学习的话,博客模块是更好的解决方案。

遗憾的是,我没有时间测试这些,但以下内容应该有效.. 至少作为指南:

删除

  private static $many_many = array (
        'Categories' => 'ArticleHolder'
    );

并将类别添加为数据库字段

private static $db = array(
    'Categories' => 'Varchar'
);

无需引入新关系,因为它们已经是该持有人的 Children。复选框字段集将数据存储为逗号分隔列表。这是一个松散的关系,所以请注意。

然后在过滤器中使用逗号分隔列表,例如:

public function LatestArticles() {
$ids = explode(",", $this->Categories)

        return ArticlePage::get()
            ->filter(array('ParentID' => $ids))
            ->sort('PublicationDate', 'DESC')
    }

我只是不记得是数据库字段 parent_id 或 ParentID 还是什么,所以您可能想从数据库表中检出。