xref: /plugin/struct/meta/SearchCloud.php (revision d6d97f6064c3b0f90310be8341edc9585520ee54)
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
15    protected $limit = '';
16
17
18    /**
19     * Transform the set search parameters into a statement
20     *
21     * @param string $idColumn Column on which to join tables
22     * @return array ($sql, $opts) The SQL and parameters to execute
23     */
24    public function getSQL($idColumn)
25    {
26        if (!$this->columns) throw new StructException('nocolname');
27
28        $QB = new QueryBuilder();
29        reset($this->schemas);
30        $schema = current($this->schemas);
31        $datatable = 'data_' . $schema->getTable();
32        if ($idColumn === 'pid') {
33            $QB->addTable('schema_assignments');
34            $QB->filters()->whereAnd("$datatable.pid = schema_assignments.pid");
35            $QB->filters()->whereAnd("schema_assignments.tbl = '{$schema->getTable()}'");
36            $QB->filters()->whereAnd("schema_assignments.assigned = 1");
37            $QB->filters()->whereAnd("GETACCESSLEVEL($datatable.pid) > 0");
38            $QB->filters()->whereAnd("PAGEEXISTS($datatable.pid) = 1");
39        }
40        $QB->addTable($datatable);
41        $QB->filters()->whereAnd("$datatable.latest = 1");
42        $QB->filters()->where('AND', 'tag IS NOT \'\'');
43
44        $col = $this->columns[0];
45        if ($col->isMulti()) {
46            $multitable = "multi_{$col->getTable()}";
47            $MN = $QB->generateTableAlias('M');
48
49            $QB->addLeftJoin(
50                $datatable,
51                $multitable,
52                $MN,
53                "$datatable.$idColumn = $MN.$idColumn AND
54                     $datatable.rev = $MN.rev AND
55                     $MN.colref = {$col->getColref()}"
56            );
57
58            $col->getType()->select($QB, $MN, 'value', 'tag');
59            $colname = $MN . '.value';
60        } else {
61            $col->getType()->select($QB, $datatable, $col->getColName(), 'tag');
62            $colname = $datatable . '.' . $col->getColName();
63        }
64        $QB->addSelectStatement("COUNT($colname)", 'count');
65        $QB->addGroupByStatement('tag');
66        $QB->addOrderBy('count DESC');
67
68        list($sql, $opts) = $QB->getSQL();
69        return [$sql . $this->limit, $opts];
70    }
71
72    /**
73     * We do not have pagination in clouds, so we can work with a limit within SQL
74     *
75     * @param int $limit
76     */
77    public function setLimit($limit)
78    {
79        $this->limit = " LIMIT $limit";
80    }
81
82    /**
83     * Execute this search and return the result
84     *
85     * The result is a two dimensional array of Value()s.
86     *
87     * @param string $idColumn Column on which to join tables
88     * @return Value[][]
89     */
90    public function execute($idColumn)
91    {
92        list($sql, $opts) = $this->getSQL($idColumn);
93
94        /** @var \PDOStatement $res */
95        $res = $this->sqlite->query($sql, $opts);
96        if ($res === false) throw new StructException("SQL execution failed for\n\n$sql");
97
98        $result = [];
99        $rows = $this->sqlite->res2arr($res);
100
101        foreach ($rows as $row) {
102            if (!empty($this->config['min']) && $this->config['min'] > $row['count']) {
103                break;
104            }
105
106            $row['tag'] = new Value($this->columns[0], $row['tag']);
107            $result[] = $row;
108        }
109
110        $this->sqlite->res_close($res);
111        $this->count = count($result);
112        return $result;
113    }
114}
115