【问题标题】:SilverStripe - Custom Faceted Search NavigationSilverStripe - 自定义分面搜索导航
【发布时间】:2016-10-01 01:53:04
【问题描述】:

我正在开发一个 SilverStripe 页面,该页面将允许用户根据所选方面对作品集进行排序。

以下是关键点/要求:

  • 我有 2 个方面类别可供他们搜索:媒体类型(即广告、 海报、电视、网络)和行业(娱乐、金融、医疗保健、 运动等)。

  • 应该允许用户一次搜索多个方面,并且 一次跨媒体类型和行业。

  • 在 SilverStripe 管理员中,因为内容管理员需要能够 为了维护媒体类型和行业的方面名称,我这样做了 有 2 个管理员模型可以输入名称: MediaTypeTagAdmin 和 IndustryTagAdmin。这是数据对象 管理员使用的 MediaTypeTag 和 IndustryTag 类 型号:

MediaTypeTag 类

<?php
class MediaTypeTag extends DataObject {

    private static $db = array(
        'Name' => 'varchar(250)',
    );

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

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

    private static $belongs_many_many = array(
        'PortfolioItemPages' => 'PortfolioItemPage'
    );

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

        return $fields;
    }

    static $default_sort = "Name ASC";
}

行业标签类

<?php
class IndustryTag extends DataObject {

    private static $db = array(
        'Name' => 'varchar(250)',
    );

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

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

    private static $belongs_many_many = array(
        'PortfolioItemPages' => 'PortfolioItemPage'
    );

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

        return $fields;
    }


    static $default_sort = "Name ASC";
}
  • 每个投资组合项目都需要一个页面,所以我制作了一个 PortfolioItemPage 类型,它有 2 个选项卡:一个用于媒体类型,一个用于行业类型。这样内容管理员就可以通过选中相应的框将他们想要的任何标签与每个投资组合项关联起来:

PortfolioItemPage.php 文件:

    private static $db = array(
        'Excerpt' => 'Text',
    );

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

    private static $has_many = array(
        'PortfolioChildItems' => 'PortfolioChildItem'
    );

    private static $many_many = array(
        'MediaTypeTags' => 'MediaTypeTag',
        'IndustryTags' => 'IndustryTag'
    );

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

        if ($this->ID) {
            $fields->addFieldToTab('Root.Media Type Tags', CheckboxSetField::create(
                'MediaTypeTags',
                'Media Type Tags',
                MediaTypeTag::get()->map()
            ));
        }

        if ($this->ID) {
            $fields->addFieldToTab('Root.Industry Tags', CheckboxSetField::create(
                'IndustryTags',
                'Industry Tags',
                IndustryTag::get()->map()
            ));
        }


        $gridFieldConfig = GridFieldConfig_RecordEditor::create();

        $gridFieldConfig->addComponent(new GridFieldBulkImageUpload());

        $gridFieldConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(array(
            'EmbedURL' => 'YouTube or SoundCloud Embed Code',
            'Thumb' => 'Thumb (135px x 135px)',
        ));

        $gridfield = new GridField(
            "ChildItems",
            "Child Items",
            $this->PortfolioChildItems(),
            $gridFieldConfig
        );

        $fields->addFieldToTab('Root.Child Items', $gridfield);

        $fields->addFieldToTab("Root.Main", new TextareaField("Excerpt"), "Content");
        $fields->addFieldToTab("Root.Main", new UploadField('Thumbnail', "Thumbnail (400x x 400px)"), "Content");
        $fields->addFieldToTab("Root.Main", new UploadField('Logo', "Logo"), "Content");

        return $fields;
    }

}
class PortfolioItemPage_Controller extends Page_Controller {

    private static $allowed_actions = array (
    );

    public function init() {
        parent::init();
    }
}

我认为可能是一个好方法是使用 jQuery 和 AJAX 将所选方面的 id 发送到服务器:

(function($) {

    $(document).ready(function() {
        var industry = $('.industry');
        var media = $('.media');
        var tag = $('.tag');
        var selectedTags = "";

        tag.each(function(e) {
            $(this).bind('click', function(e) {
                e.preventDefault();

                $(this).addClass('selectedTag');

                if(selectedTags.indexOf($(this).text()) < 0){
                    if($(this).hasClass('media')){
                        selectedTags += + $(this).attr("id") + "," +"media;";
                    }
                    else{
                        selectedTags += + $(this).attr("id") + "," +"industry;";
                    }
                }
                sendTag(selectedTags);

            }.bind($(this)));
        });

        function sendTag(TagList){
            $.ajax({
                type: "POST",
                url: "/home/getPortfolioItemsByTags/",
                data: { tags: TagList },
                dataType: "json"
            }).done(function(response) {
                var div = $('.portfolioItems');
                div.empty();
                for (var i=0; i<response.length; i++){
                    div.append(response[i].name + "<br />");
                    //return portfolio data here
                }

            })
            .fail(function() {
                alert("There was a problem processing the request.");
           });
        }
    });

}(jQuery));

然后在Page.php上循环遍历ids,根据facet ids得到对应的PortfolioItemPage信息:

    public function getPortfolioItemsByTags(){
    //remove the last comma from the list of tag ids

    $IDs = $this->getRequest()->postVar('tags');
    $IDSplit = substr($IDs, 0, -1);

    //put the tag ids and their tag names (media or industry) into an array
    $IDListPartial = explode(";",$IDSplit);

    //This will hold the associative array of ids to types (i.e. 34 => media)
    $IDListFinal = array();
    array_walk($IDListPartial, function($val, $key) use(&$IDListFinal){
        list($key, $value) = explode(',', $val);
        $IDListFinal[$key] = $value;
    });

    //get Portfolio Items based on the tag ids and tag type
    foreach($IDListFinal as $x => $x_value) {
        if($x_value=='media'){
            $tag = MediaTypeTag::get()->byId($x);
            $portfolioItems = $tag->PortfolioItemPages();
        }
        else{
            $tag = IndustryTag::get()->byId($x);
            $portfolioItems = $tag->PortfolioItemPages();
        }

        $return = array();

        foreach($portfolioItems as $portfolioItem){
            $return[] = array(
                'thumbnail' => $portfolioItem->Thumbnail()->Link(),
                'name' => $portfolioItem->H1,
                'logo' => $portfolioItem->Logo()->Link(),
                'excerpt' => $portfolioItem->Excerpt,
                'id' => $portfolioItem->ID
            );
        }
        return json_encode($return);
    }
}

但是,这就是我卡住的地方。虽然我找到了一些在 CMS 之外构建 PHP/MySQL 分面搜索的不错示例,但我不确定我可以修改什么以使搜索在 CMS 内工作。那,示例将方面放在 MySQL 数据库中的一个表中,而我有 2 个(尽管我只想为媒体类型和行业方面提供一个 MySQL 表,但我不确定这是否是个好主意因为内容管理员希望自己维护构面名称)。

是否有任何教程可以提供进一步的帮助,或者可能是我还没有找到的插件?如果有更好的方法来设置这个多面搜索,请务必提出建议。这对我来说很新鲜。

【问题讨论】:

    标签: php jquery mysql ajax silverstripe


    【解决方案1】:

    最有效的方法是在一个查询中根据标签/媒体类型 ID 进行过滤(您的示例是对每个标签/类型进行一次数据库查询,然后附加结果)。

    你应该可以做这样的事情:

    <?php
    
    public function getPortfolioItemsByTags(){
        $tagString = $this->getRequest()->postVar('tags');
    
        // remove the last comma from the list of tag ids
        $tagString = substr($tagString, 0, -1);
    
        //put the tag ids and their tag names (media or industry) into an array
        $tags = explode(";", $tagString);
    
        //This will hold the associative array of ids to types (i.e. 34 => media)
        $filters = array(
            'media' => array(),
            'industry' => array()
        );
        array_walk($tags, function($val, $key) use(&$filters) {
            list($id, $type) = explode(',', $val);
            $filters[$type][] = $id;
        });
    
        $portfolioItems = PortfolioItemPage::get()->filterAny(array(
            'MediaTypeTags.ID' => $filters['media'],
            'IndustryTags.ID' => $filters['industry']
        ));
    
        $return = array();
        foreach($portfolioItems as $portfolioItem){
            $return[] = array(
                'thumbnail' => $portfolioItem->Thumbnail()->Link(),
                'name' => $portfolioItem->H1,
                'logo' => $portfolioItem->Logo()->Link(),
                'excerpt' => $portfolioItem->Excerpt,
                'id' => $portfolioItem->ID
            );
        }
    
        return json_encode($return);
    }
    

    【讨论】:

    • 我想这就是我需要的。我试了一下,它看起来像我需要的那样工作。谢谢! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    • 2012-10-12
    • 2018-02-10
    相关资源
    最近更新 更多