ShortCodeRelationFinder::getList()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
/**
3
 * Finds {@link DataObject} instances using certain shortcodes
4
 * by fulltext-querying only fields which are capable of parsing shortcodes.
5
 * Effectively the reverse of "link tracking",
6
 * which updates this relation on write rather than fetching it on demand.
7
 *
8
 * Doesn't scale to millions of pages due to triggering a potentially unindexed LIKE
9
 * search across dozens of columns and tables - but for a couple of hundred pages
10
 * and occasionally use its a feasible solution.
11
 */
12
class ShortCodeRelationFinder
13
{
14
15
    /**
16
     * @var String Regex matching a {@link DBField} class name which is shortcode capable.
17
     *
18
     * This should really look for implementors of a ShortCodeParseable interface,
19
     * but we can't extend the core Text and HTMLText class
20
     * on existing like SiteTree.Content for this.
21
     */
22
    protected $fieldSpecRegex = '/^(HTMLText)/';
23
24
    /**
25
     * @param String Shortcode index number to find
26
     * @return array IDs
27
     */
28
    public function findPageIDs($number)
29
    {
30
        $list = $this->getList($number);
31
        $found = $list->column();
32
        return $found;
33
    }
34
35
    public function findPageCount($number)
36
    {
37
        $list = $this->getList($number);
38
        return $list->count();
39
    }
40
41
    /**
42
     * @param int $number
43
     * @return DataList
44
     */
45
    public function getList($number)
46
    {
47
        $number = (int) $number;
48
        $list = DataList::create('SiteTree');
49
        $where = array();
50
        $fields = $this->getShortCodeFields('SiteTree');
51
        $shortcode = DMS::inst()->getShortcodeHandlerKey();
52
        foreach ($fields as $ancClass => $ancFields) {
53
            foreach ($ancFields as $ancFieldName => $ancFieldSpec) {
54
                if ($ancClass != "SiteTree") {
55
                    $list = $list->leftJoin($ancClass, '"'.$ancClass.'"."ID" = "SiteTree"."ID"');
56
                }
57
                $where[] = "\"$ancClass\".\"$ancFieldName\" LIKE '%[{$shortcode},id=$number]%'"; //."%s" LIKE ""',
58
            }
59
        }
60
61
        $list = $list->where(implode(' OR ', $where));
62
        return $list;
63
    }
64
65
    /**
66
     * Returns a filtered list of fields which could contain shortcodes.
67
     *
68
     * @param String
69
     * @return Array Map of class names to an array of field names on these classes.
70
     */
71
    public function getShortcodeFields($class)
72
    {
73
        $fields = array();
74
        $ancestry = array_values(ClassInfo::dataClassesFor($class));
75
76
        foreach ($ancestry as $ancestor) {
77
            if (ClassInfo::classImplements($ancestor, 'TestOnly')) {
78
                continue;
79
            }
80
81
            $ancFields = DataObject::custom_database_fields($ancestor);
82
            if ($ancFields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ancFields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
83
                foreach ($ancFields as $ancFieldName => $ancFieldSpec) {
84
                    if (preg_match($this->fieldSpecRegex, $ancFieldSpec)) {
85
                        if (!@$fields[$ancestor]) {
86
                            $fields[$ancestor] = array();
87
                        }
88
                        $fields[$ancestor][$ancFieldName] = $ancFieldSpec;
89
                    }
90
                }
91
            }
92
        }
93
94
        return $fields;
95
    }
96
}
97