在controller /中使用has_one,has_many和many_many来过滤查询

时间:2015-06-05 04:34:30

标签: silverstripe

我在silverstripe.org网站上观看了第7课 - 第10课的视频,已经阅读了本页面上的所有文章:http://docs.silverstripe.org/en/3.1/developer_guides/model/,已经全部在API中,并且已经使用了数小时的谷歌搜索和/或堆栈论坛。我真的很难尝试应用我学到的东西。这就是我想要做的事情。我想扩展Article Holder&文章页面的概念。我正在尝试创建另一个主文章持有者页面,我的网站树将按此组织:

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

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

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

ArticlePage

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;
    }
}

ArticleHolder

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')
    }
}

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

  • ArticlePage是带有ArticleHolder的has_one
  • ArticleHolder是一个带有ArticlePage的has_many
  • ArticleHolder与MasterArticleHolder有很多关系(不知道哪一个是belongs_many_many,但我猜的是物品持有人)

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

  • ArticlePage与MasterArticleHolder
  • 是一个很多人

现在我通常知道has_one,has_many和many_many适用于扩展DataObject的对象但是我认为,因为以圆形方式的页面扩展了DataObject,这些关系可能仍然适用,但我可能完全错了,真的过度思考。

希望我能够很好地解释自己以获得帮助,但不能过多地压倒所有人。我很感激您的反馈!

2 个答案:

答案 0 :(得分:0)

你应该进一步深入研究教程,这个(使用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基本上是相同的(Pages是DataObjects),但是您可以减少对站点树(在CMS中)的污染以及与子项等有关的层次问题。

但另一方面,你放松了自动路由,以及Page给你的各种其他东西。这就是为什么Blog模块是一个更好的解决方案,如果您不只是想学习。

答案 1 :(得分:0)

可悲的是,我没有时间对这些进行测试,但以下情况应该起作用..至少作为指导:

删除

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

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

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

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

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

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

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

我不记得是数据库字段parent_id还是ParentID,或者你可能希望从数据库表中检出什么。