diff options
Diffstat (limited to 'modules-available/statistics/inc/hardwarequerycolumn.inc.php')
-rw-r--r-- | modules-available/statistics/inc/hardwarequerycolumn.inc.php | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/modules-available/statistics/inc/hardwarequerycolumn.inc.php b/modules-available/statistics/inc/hardwarequerycolumn.inc.php new file mode 100644 index 00000000..01e32978 --- /dev/null +++ b/modules-available/statistics/inc/hardwarequerycolumn.inc.php @@ -0,0 +1,94 @@ +<?php + +class HardwareQueryColumn +{ + /** @var int For unique table names in join */ + private static $id = 0; + + private $global; + private $tableAlias; + private $virtualColumnName; + private $alias; + private $conditions = []; + private $params = []; + private $classId; + + private static function getId(): string + { + return 't' . ++self::$id; + } + + public function __construct(bool $global, string $column, string $alias = null) + { + $this->classId = ++self::$id; + $this->global = $global; + $this->tableAlias = self::getId(); + $this->virtualColumnName = $column; + $this->alias = '`' . ($alias ?? $column) . '`'; + } + + /** + * Add necessary conditions, joins, columns to final SQL arrays. To be called + * from HardwareQuery::buildQuery(). + * @param string[] $groupConcat if column name is NOT in this array, add as distinct GROUP_CONCAT to column. + */ + public function generate(array &$joins, array &$columns, array &$params, array $groupConcat = [], string $globalSrcTableAlias = null) + { + if ($this->global) { + $srcTable = $globalSrcTableAlias ?? 'shw'; + $table = 'statistic_hw_prop'; + $column = 'hwid'; + } else { + $srcTable = 'mxhw'; + $table = 'machine_x_hw_prop'; + $column = 'machinehwid'; + } + $tid = $this->tableAlias; + $pid = self::getId(); + $this->conditions[] = "$srcTable.$column = $tid.$column AND $tid.prop = :$pid"; + $params[$pid] = $this->virtualColumnName; // value of property column is our virtual column + // If we have just one condition, it's the join condition itself. Since we pretend we're just adding + // a column to the query, do a left join, so the "column" is NULL if the join doesn't match. + // If however any conditions were added to this class via the addCondition() method, do a regular + // INNER JOIN, so the result will be empty if the condition doesn't match. + $type = count($this->conditions) === 1 ? 'LEFT' : 'INNER'; + $joins[] = "$type JOIN $table $tid ON (" . implode(' AND ', $this->conditions) . ")"; + if (!empty($groupConcat) && !in_array($this->alias, $groupConcat)) { + $columns[] = "Group_Concat(DISTINCT $tid.`value` SEPARATOR ', ') AS {$this->alias}"; + } else { + $columns[] = "$tid.`value` AS {$this->alias}"; + } + $params += $this->params; + } + + /** + * @param string $op Operator (<>=, IN, LIKE) + * @param string|string[]|HardwareQueryColumn $other value to compare with. + * Can be a literal, an array (if opererator is IN), or another Column + * @return void + */ + public function addCondition(string $op, $other) + { + $valueCol = ($op === '<' || $op === '>' || $op === '<=' || $op === '>=') ? 'numeric' : 'value'; + if ($other instanceof HardwareQueryColumn) { + $cond = "{$this->tableAlias}.`$valueCol` $op {$other->tableAlias}.`$valueCol`"; + // Don't reference a column of a table that hasn't been joined yet + if ($this->classId > $other->classId) { + $this->conditions[] = $cond; + } else { + $other->conditions[] = $cond; + } + } elseif ($op === '~' || $op === '!~') { + $op = $op === '~' ? 'LIKE' : 'NOT LIKE'; + $other = str_replace(array('=', '_', '%', '*', '?'), array('==', '=_', '=%', '%', '_'), $other); + $pid = self::getId(); + $this->conditions[] = "{$this->tableAlias}.`$valueCol` $op (:$pid) ESCAPE '='"; + $this->params[$pid] = $other; + } else { + $pid = self::getId(); + $this->conditions[] = "{$this->tableAlias}.`$valueCol` $op (:$pid)"; + $this->params[$pid] = $other; + } + } + +} |