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