1<?php 2 3namespace dokuwiki\plugin\struct\meta; 4 5 6/** 7 * Class SearchCloud 8 * 9 * The same as @see SearchConfig, but executed a search that is not pid-focused 10 * 11 * @package dokuwiki\plugin\struct\meta 12 */ 13class SearchCloud extends SearchConfig { 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 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 if($idColumn === 'pid') { 32 $QB->addTable('schema_assignments'); 33 $QB->filters()->whereAnd("$datatable.pid = schema_assignments.pid"); 34 $QB->filters()->whereAnd("schema_assignments.tbl = '{$schema->getTable()}'"); 35 $QB->filters()->whereAnd("schema_assignments.assigned = 1"); 36 $QB->filters()->whereAnd("GETACCESSLEVEL($datatable.pid) > 0"); 37 $QB->filters()->whereAnd("PAGEEXISTS($datatable.pid) = 1"); 38 } 39 $QB->addTable($datatable); 40 $QB->filters()->whereAnd("$datatable.latest = 1"); 41 $QB->filters()->where('AND', 'tag IS NOT \'\''); 42 43 $col = $this->columns[0]; 44 if($col->isMulti()) { 45 $multitable = "multi_{$col->getTable()}"; 46 $MN = $QB->generateTableAlias('M'); 47 48 $QB->addLeftJoin( 49 $datatable, 50 $multitable, 51 $MN, 52 "$datatable.$idColumn = $MN.$idColumn AND 53 $datatable.rev = $MN.rev AND 54 $MN.colref = {$col->getColref()}" 55 ); 56 57 $col->getType()->select($QB, $MN, 'value', 'tag'); 58 $colname = $MN . '.value'; 59 } else { 60 $col->getType()->select($QB, $datatable, $col->getColName(), 'tag'); 61 $colname = $datatable . '.' . $col->getColName(); 62 } 63 $QB->addSelectStatement("COUNT($colname)", 'count'); 64 $QB->addGroupByStatement('tag'); 65 $QB->addOrderBy('count DESC'); 66 67 list($sql, $opts) = $QB->getSQL(); 68 return [$sql . $this->limit, $opts]; 69 } 70 71 /** 72 * We do not have pagination in clouds, so we can work with a limit within SQL 73 * 74 * @param int $limit 75 */ 76 public function setLimit($limit) { 77 $this->limit = " LIMIT $limit"; 78 } 79 80 /** 81 * Execute this search and return the result 82 * 83 * The result is a two dimensional array of Value()s. 84 * 85 * @param string $idColumn Column on which to join tables 86 * @return Value[][] 87 */ 88 public function execute($idColumn) { 89 list($sql, $opts) = $this->getSQL($idColumn); 90 91 /** @var \PDOStatement $res */ 92 $res = $this->sqlite->query($sql, $opts); 93 if($res === false) throw new StructException("SQL execution failed for\n\n$sql"); 94 95 $result = []; 96 $rows = $this->sqlite->res2arr($res); 97 98 foreach ($rows as $row) { 99 if (!empty($this->config['min']) && $this->config['min'] > $row['count']) { 100 break; 101 } 102 103 $row['tag'] = new Value($this->columns[0], $row['tag']); 104 $result[] = $row; 105 } 106 107 $this->sqlite->res_close($res); 108 $this->count = count($result); 109 return $result; 110 } 111} 112