1*15929be2SAndreas Gohr<?php 2*15929be2SAndreas Gohr 3*15929be2SAndreas Gohrnamespace plugin\struct\meta; 4*15929be2SAndreas Gohr 5*15929be2SAndreas Gohruse Exception; 6*15929be2SAndreas Gohr 7*15929be2SAndreas Gohrclass Search { 8*15929be2SAndreas Gohr 9*15929be2SAndreas Gohr /** @var Schema[] list of schemas to query */ 10*15929be2SAndreas Gohr protected $schemas = array(); 11*15929be2SAndreas Gohr 12*15929be2SAndreas Gohr /** @var Column[] list of columns to select */ 13*15929be2SAndreas Gohr protected $columns = array(); 14*15929be2SAndreas Gohr 15*15929be2SAndreas Gohr /** @var array the sorting of the result */ 16*15929be2SAndreas Gohr protected $sortby = array(); 17*15929be2SAndreas Gohr 18*15929be2SAndreas Gohr /** @var array the or filters */ 19*15929be2SAndreas Gohr protected $filteror = array(); 20*15929be2SAndreas Gohr 21*15929be2SAndreas Gohr /** @var array the and filters */ 22*15929be2SAndreas Gohr protected $filterand = array(); 23*15929be2SAndreas Gohr 24*15929be2SAndreas Gohr /** @var array list of aliases tables can be referenced by */ 25*15929be2SAndreas Gohr protected $aliases = array(); 26*15929be2SAndreas Gohr 27*15929be2SAndreas Gohr /** 28*15929be2SAndreas Gohr * Add a schema to be searched 29*15929be2SAndreas Gohr * 30*15929be2SAndreas Gohr * Call multiple times for multiple schemas. 31*15929be2SAndreas Gohr * 32*15929be2SAndreas Gohr * @param string $table 33*15929be2SAndreas Gohr * @param string $alias 34*15929be2SAndreas Gohr */ 35*15929be2SAndreas Gohr public function addSchema($table, $alias = '') { 36*15929be2SAndreas Gohr $this->schemas[$table] = new Schema($table); 37*15929be2SAndreas Gohr if($alias) $this->aliases[$alias] = $table; 38*15929be2SAndreas Gohr } 39*15929be2SAndreas Gohr 40*15929be2SAndreas Gohr /** 41*15929be2SAndreas Gohr * Add a column to be returned by the search 42*15929be2SAndreas Gohr * 43*15929be2SAndreas Gohr * Call multiple times for multiple columns. Be sure the referenced tables have been 44*15929be2SAndreas Gohr * added before 45*15929be2SAndreas Gohr * 46*15929be2SAndreas Gohr * @param string $colname may contain an alias 47*15929be2SAndreas Gohr */ 48*15929be2SAndreas Gohr public function addColumn($colname) { 49*15929be2SAndreas Gohr $col = $this->findColumn($colname); 50*15929be2SAndreas Gohr if(!$col) return; //FIXME do we really want to ignore missing columns? 51*15929be2SAndreas Gohr $this->columns[] = $col; 52*15929be2SAndreas Gohr } 53*15929be2SAndreas Gohr 54*15929be2SAndreas Gohr /** 55*15929be2SAndreas Gohr * Add sorting options 56*15929be2SAndreas Gohr * 57*15929be2SAndreas Gohr * Call multiple times for multiple columns. Be sure the referenced tables have been 58*15929be2SAndreas Gohr * added before 59*15929be2SAndreas Gohr * 60*15929be2SAndreas Gohr * @param string $colname may contain an alias 61*15929be2SAndreas Gohr * @param bool $asc sort direction (ASC = true, DESC = false) 62*15929be2SAndreas Gohr */ 63*15929be2SAndreas Gohr public function addSort($colname, $asc = true) { 64*15929be2SAndreas Gohr $col = $this->findColumn($colname); 65*15929be2SAndreas Gohr if(!$col) return; //FIXME do we really want to ignore missing columns? 66*15929be2SAndreas Gohr 67*15929be2SAndreas Gohr $this->sortby[] = array($col, $asc); 68*15929be2SAndreas Gohr } 69*15929be2SAndreas Gohr 70*15929be2SAndreas Gohr /** 71*15929be2SAndreas Gohr * Adds an ORed filter 72*15929be2SAndreas Gohr * 73*15929be2SAndreas Gohr * @param string $colname may contain an alias 74*15929be2SAndreas Gohr * @param string $value 75*15929be2SAndreas Gohr * @param string $comp 76*15929be2SAndreas Gohr */ 77*15929be2SAndreas Gohr public function addFilterOr($colname, $value, $comp) { 78*15929be2SAndreas Gohr $col = $this->findColumn($colname); 79*15929be2SAndreas Gohr if(!$col) return; //FIXME do we really want to ignore missing columns? 80*15929be2SAndreas Gohr 81*15929be2SAndreas Gohr $this->filteror[] = array($col, $value, $comp); 82*15929be2SAndreas Gohr } 83*15929be2SAndreas Gohr 84*15929be2SAndreas Gohr /** 85*15929be2SAndreas Gohr * Adds an ANDed filter 86*15929be2SAndreas Gohr * 87*15929be2SAndreas Gohr * @param string $colname may contain an alias 88*15929be2SAndreas Gohr * @param string $value 89*15929be2SAndreas Gohr * @param string $comp 90*15929be2SAndreas Gohr */ 91*15929be2SAndreas Gohr public function addFilterAnd($colname, $value, $comp) { 92*15929be2SAndreas Gohr $col = $this->findColumn($colname); 93*15929be2SAndreas Gohr if(!$col) return; //FIXME do we really want to ignore missing columns? 94*15929be2SAndreas Gohr 95*15929be2SAndreas Gohr $this->filterand[] = array($col, $value, $comp); 96*15929be2SAndreas Gohr } 97*15929be2SAndreas Gohr 98*15929be2SAndreas Gohr /** 99*15929be2SAndreas Gohr * Transform the set search parameters into a statement 100*15929be2SAndreas Gohr * 101*15929be2SAndreas Gohr * @todo limit to the newest data! 102*15929be2SAndreas Gohr * @return string 103*15929be2SAndreas Gohr */ 104*15929be2SAndreas Gohr public function getSQL() { 105*15929be2SAndreas Gohr if(!$this->columns) throw new SearchException('nocolname'); 106*15929be2SAndreas Gohr 107*15929be2SAndreas Gohr // basic tables 108*15929be2SAndreas Gohr $from = ''; 109*15929be2SAndreas Gohr foreach($this->schemas as $schema) { 110*15929be2SAndreas Gohr $from .= 'data_' . $schema->getTable() . ', '; 111*15929be2SAndreas Gohr 112*15929be2SAndreas Gohr // fixme join the multiple tables together by pid 113*15929be2SAndreas Gohr } 114*15929be2SAndreas Gohr $from = rtrim($from, ', '); 115*15929be2SAndreas Gohr 116*15929be2SAndreas Gohr // columns to select, handling multis 117*15929be2SAndreas Gohr $select = ''; 118*15929be2SAndreas Gohr $n = 0; 119*15929be2SAndreas Gohr foreach($this->columns as $col) { 120*15929be2SAndreas Gohr $CN = 'C'.$n++; 121*15929be2SAndreas Gohr 122*15929be2SAndreas Gohr if($col->isMulti()) { 123*15929be2SAndreas Gohr $tn = 'M' . $col->getColref(); 124*15929be2SAndreas Gohr $select .= "$tn.value AS $CN, "; 125*15929be2SAndreas Gohr $from .= "\nLEFT OUTER JOIN multivals $tn"; 126*15929be2SAndreas Gohr $from .= " ON DATA.pid = $tn.pid AND DATA.rev = $tn.rev"; 127*15929be2SAndreas Gohr $from .= " AND $tn.tbl = '{$col->getTable()}' AND $tn.colref = {$col->getColref()}\n"; 128*15929be2SAndreas Gohr } else { 129*15929be2SAndreas Gohr $select .= 'data_'.$col->getTable().'.col' . $col->getColref() . " AS $CN, "; 130*15929be2SAndreas Gohr } 131*15929be2SAndreas Gohr } 132*15929be2SAndreas Gohr $select = rtrim($select, ', '); 133*15929be2SAndreas Gohr 134*15929be2SAndreas Gohr 135*15929be2SAndreas Gohr $sql = "SELECT $select\n FROM $from"; 136*15929be2SAndreas Gohr return $sql; 137*15929be2SAndreas Gohr } 138*15929be2SAndreas Gohr 139*15929be2SAndreas Gohr /** 140*15929be2SAndreas Gohr * Find a column to be used in the search 141*15929be2SAndreas Gohr * 142*15929be2SAndreas Gohr * @param string $colname may contain an alias 143*15929be2SAndreas Gohr * @return bool|Column 144*15929be2SAndreas Gohr */ 145*15929be2SAndreas Gohr protected function findColumn($colname) { 146*15929be2SAndreas Gohr if(!$this->schemas) throw new SearchException('noschemas'); 147*15929be2SAndreas Gohr 148*15929be2SAndreas Gohr // resolve the alias or table name 149*15929be2SAndreas Gohr list($table, $colname) = explode('.', $colname, 2); 150*15929be2SAndreas Gohr if(!$colname) { 151*15929be2SAndreas Gohr $colname = $table; 152*15929be2SAndreas Gohr $table = ''; 153*15929be2SAndreas Gohr } 154*15929be2SAndreas Gohr if($table && isset($this->aliases[$table])) { 155*15929be2SAndreas Gohr $table = $this->aliases[$table]; 156*15929be2SAndreas Gohr } 157*15929be2SAndreas Gohr 158*15929be2SAndreas Gohr if(!$colname) throw new SearchException('nocolname'); 159*15929be2SAndreas Gohr 160*15929be2SAndreas Gohr // if table name given search only that, otherwiese try all for matching column name 161*15929be2SAndreas Gohr if($table) { 162*15929be2SAndreas Gohr $schemas = array($table => $this->schemas[$table]); 163*15929be2SAndreas Gohr } else { 164*15929be2SAndreas Gohr $schemas = $this->schemas; 165*15929be2SAndreas Gohr } 166*15929be2SAndreas Gohr 167*15929be2SAndreas Gohr // find it 168*15929be2SAndreas Gohr $col = false; 169*15929be2SAndreas Gohr foreach($schemas as $schema) { 170*15929be2SAndreas Gohr $col = $schema->findColumn($colname); 171*15929be2SAndreas Gohr if($col) break; 172*15929be2SAndreas Gohr } 173*15929be2SAndreas Gohr 174*15929be2SAndreas Gohr return $col; 175*15929be2SAndreas Gohr } 176*15929be2SAndreas Gohr 177*15929be2SAndreas Gohr} 178*15929be2SAndreas Gohr 179*15929be2SAndreas Gohr/** 180*15929be2SAndreas Gohr * Class SearchException 181*15929be2SAndreas Gohr * 182*15929be2SAndreas Gohr * A translatable exception 183*15929be2SAndreas Gohr * 184*15929be2SAndreas Gohr * @package plugin\struct\meta 185*15929be2SAndreas Gohr */ 186*15929be2SAndreas Gohrclass SearchException extends \RuntimeException { 187*15929be2SAndreas Gohr public function __construct($message, $code = -1, Exception $previous = null) { 188*15929be2SAndreas Gohr /** @var \action_plugin_struct_autoloader $plugin */ 189*15929be2SAndreas Gohr $plugin = plugin_load('action', 'struct_autoloader'); 190*15929be2SAndreas Gohr $trans = $plugin->getLang('searchex_' . $message); 191*15929be2SAndreas Gohr if(!$trans) $trans = $message; 192*15929be2SAndreas Gohr parent::__construct($trans, $code, $previous); 193*15929be2SAndreas Gohr } 194*15929be2SAndreas Gohr} 195