2

我有一个扩展 Page(“Thing”)的对象,它与 DataObject(“Tag”)有 many_many 关系。

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

4 回答 4

3

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

$tag_ids = array(1,2,3,4);
$things = Thing::get();
$things->filter('Tags.ID:ExactMatchMulti', $tag_ids);
于 2013-06-16T13:10:28.930 回答
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);
        }
    }
}

虽然没有经过测试,但这应该会给你留下包含所有标签和更多标签的 $things。(假设一个东西只能用相同的标签标记一次)。

于 2013-06-16T08:03:09.180 回答
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
}

希望这可以帮助

于 2013-06-15T22:16:37.720 回答
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 表中添加了一个左连接,因为我想你上面有一些 db 字段,但是如果不是这种情况,请删除该行(以及 SELECT 语句上的 \"Thing\".*)

于 2013-06-17T02:22:53.147 回答