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