1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5/**
6 * Class SearchCloud
7 *
8 * The same as @see SearchConfig, but executed a search that is not pid-focused
9 *
10 * @package dokuwiki\plugin\struct\meta
11 */
12class SearchCloud extends SearchConfig
13{
14    protected $limit = '';
15
16    /**
17     * Transform the set search parameters into a statement
18     *
19     * @return array ($sql, $opts) The SQL and parameters to execute
20     */
21    public function getSQL()
22    {
23        if (!$this->columns) throw new StructException('nocolname');
24
25        $QB = new QueryBuilder();
26        reset($this->schemas);
27        $schema = current($this->schemas);
28        $datatable = 'data_' . $schema->getTable();
29
30        $QB->addTable($datatable);
31
32        // add conditional page clauses if pid has a value
33        $subAnd = $QB->filters()->whereSubAnd();
34        $subAnd->whereAnd("$datatable.pid = ''");
35        $subOr = $subAnd->whereSubOr();
36        $subOr->whereAnd("GETACCESSLEVEL($datatable.pid) > 0");
37        $subOr->whereAnd("PAGEEXISTS($datatable.pid) = 1");
38        $subOr->whereSubOr()
39            ->whereAnd('ASSIGNED == 1')
40            ->whereSubOr()
41                ->whereAnd("$datatable.rid > 0")
42                ->whereAnd("ASSIGNED IS NULL");
43
44        // add conditional schema assignment check
45        $QB->addLeftJoin(
46            $datatable,
47            'schema_assignments',
48            '',
49            "$datatable.pid != ''
50                    AND $datatable.pid = schema_assignments.pid
51                    AND schema_assignments.tbl = '{$schema->getTable()}'"
52        );
53
54        $QB->filters()->whereAnd("$datatable.latest = 1");
55        $QB->filters()->where('AND', 'tag IS NOT \'\'');
56
57        $col = $this->columns[0];
58        if ($col->isMulti()) {
59            $multitable = "multi_{$col->getTable()}";
60            $MN = $QB->generateTableAlias('M');
61
62            $QB->addLeftJoin(
63                $datatable,
64                $multitable,
65                $MN,
66                "$datatable.pid = $MN.pid AND
67                     $datatable.rid = $MN.rid AND
68                     $datatable.rev = $MN.rev AND
69                     $MN.colref = {$col->getColref()}"
70            );
71
72            $col->getType()->select($QB, $MN, 'value', 'tag');
73            $colname = $MN . '.value';
74        } else {
75            $col->getType()->select($QB, $datatable, $col->getColName(), 'tag');
76            $colname = $datatable . '.' . $col->getColName();
77        }
78        $QB->addSelectStatement("COUNT($colname)", 'count');
79        $QB->addSelectColumn('schema_assignments', 'assigned', 'ASSIGNED');
80        $QB->addGroupByStatement('tag');
81        $QB->addOrderBy('count DESC');
82
83        list($sql, $opts) = $QB->getSQL();
84        return [$sql . $this->limit, $opts];
85    }
86
87    /**
88     * We do not have pagination in clouds, so we can work with a limit within SQL
89     *
90     * @param int $limit
91     */
92    public function setLimit($limit)
93    {
94        $this->limit = " LIMIT $limit";
95    }
96
97    /**
98     * Execute this search and return the result
99     *
100     * The result is a two dimensional array of Value()s.
101     *
102     * @return Value[][]
103     */
104    public function execute()
105    {
106        list($sql, $opts) = $this->getSQL();
107
108        /** @var \PDOStatement $res */
109        $res = $this->sqlite->query($sql, $opts);
110        if ($res === false) throw new StructException("SQL execution failed for\n\n$sql");
111
112        $result = [];
113        $rows = $this->sqlite->res2arr($res);
114
115        foreach ($rows as $row) {
116            if (!empty($this->config['min']) && $this->config['min'] > $row['count']) {
117                break;
118            }
119
120            $row['tag'] = new Value($this->columns[0], $row['tag']);
121            $result[] = $row;
122        }
123
124        $this->sqlite->res_close($res);
125        $this->count = count($result);
126        return $result;
127    }
128}
129