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