Silverstripe - 通过许多关系过滤DataObject列表

时间:2013-06-15 20:11:11

标签: silverstripe

我有一个扩展页面的对象(“Thing”),它与DataObject(“Tag”)有很多关系。

class Thing extends Page
{
    static $many_many = array(
        'Tags' => 'Tag'
    );
}

class Tag extends DataObject
{
    static $belongs_many_many = array(
        'Things' => 'Thing'
    );
}

我有一系列标签ID,我想获得附有所有这些标签的物品清单。

以下应该是可能的......

$tag_ids = array(1,2,3,4);
$things = Thing::get();
$things->filter('Tags.ID', array($tag_ids));

...但这只会返回一个未经过滤的列表。显然,这尚未实现关系。那我怎么能这样做呢?

4 个答案:

答案 0 :(得分:3)

我认为如果您使用SilverStripe 3的旧版本,则需要使用ExactMatchMulti SearchFilter。

$tag_ids = array(1,2,3,4);
$things = Thing::get();
$things->filter('Tags.ID:ExactMatchMulti', $tag_ids);

答案 1 :(得分:2)

我没有看到一个简单的解决方案直接用ORM做到这一点。但是你应该能够通过一些循环和过滤来解决这个问题。

$tag_ids = array(1,2,3,4);
$things = Thing::get();
$results = new ArrayList();

$tags_count = count($tag_ids);
$matches = 0;

foreach ($things as $thing)
{
    foreach ($thing->Tags() as $tags)
    {
        $matches = 0;
        foreach ($tags as $tag)
        {
             if ( in_array($tag->ID, $tag_ids) )
            {
                 $matches++;
            }
        }
        if ( $matches === $tags_count )
        {
            $results->push($thing);
        }
    }
}

虽然没有经过测试,但这应该会为您留下包含所有标签及其他内容的商品。 (假设一个东西只能用相同的标签标记一次)。

答案 2 :(得分:1)

您可以尝试执行以下操作:

Tag::get()->byIds($tag_ids)->relation('Things')

将返回可以迭代的ManyManyList,即

foreach(Tag::get()->byIds($tag_ids)->relation('Things') as $thing){
    Debug::Dump($thing); // A 'Thing' object
}

希望这有帮助

答案 3 :(得分:1)

出于性能原因,您可能最好尽可能多地依赖SQL查询。

$tag_ids = array(1,2,3);
$objects = new ArrayList();
if (count($tag_ids)) {
    $sql = "SELECT \"SiteTree\".*, \"Page\".*, \"Thing\".*,count(\"ThingID\") AS ThingIDCount FROM \"SiteTree\" ";
    $sql.= "LEFT JOIN \"Page\" ON \"Page\".\"ID\" = \"SiteTree\".\"ID\" ";
    $sql.= "LEFT JOIN \"Thing\" ON \"Thing\".\"ID\" = \"SiteTree\".\"ID\" ";
    $sql.= "LEFT JOIN \"Thing_Tags\" ON \"Thing_Tags\".\"ThingID\" = \"SiteTree\".\"ID\" ";
    $sql.= "LEFT JOIN \"Tag\" ON \"Thing_Tags\".\"TagID\" = \"Tag\".\"ID\" ";
    $sql.= "WHERE \"TagID\" IN (" . implode(',', $tag_ids) . ") GROUP BY \"ThingID\" HAVING ThingIDCount >= " . count($tag_ids);

    // Get records
    $records = DB::query($sql);
    foreach($records as $record) {
        $objects->push(new Thing($record));
    }
}



// Display the Things for demo purposes
foreach($objects as $thing){
    Debug::Dump($thing);
}

注意我已经在Thing表中添加了一个左连接,因为我想你上面有一些数据库字段,但是如果不是这种情况则删除该行(以及SELECT语句中的“Thing \”。*)