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