icingaweb2-module-director/library/Director/Data/Db/IcingaObjectQuery.php

262 lines
6.5 KiB
PHP

<?php
namespace Icinga\Module\Director\Data\Db;
use Icinga\Data\Db\DbQuery;
use Icinga\Exception\NotFoundError;
use Icinga\Exception\NotImplementedError;
use Icinga\Module\Director\Db;
use Zend_Db_Expr as ZfDbExpr;
use Zend_Db_Select as ZfDbSelect;
class IcingaObjectQuery
{
const BASE_ALIAS = 'o';
/** @var Db */
protected $connection;
/** @var string */
protected $type;
/** @var \Zend_Db_Adapter_Abstract */
protected $db;
/** @var ZfDbSelect */
protected $query;
/** @var bool */
protected $resolved;
/** @var array joined tables, alias => table */
protected $requiredTables;
/** @var array maps table aliases, alias => table*/
protected $aliases;
/** @var DbQuery */
protected $dummyQuery;
/** @var array varname => alias */
protected $joinedVars = array();
protected $customVarTable;
protected $baseQuery;
/**
* IcingaObjectQuery constructor.
*
* @param string $type
* @param Db $connection
* @param bool $resolved
*/
public function __construct($type, Db $connection, $resolved = true)
{
$this->type = $type;
$this->connection = $connection;
$this->db = $connection->getDbAdapter();
$this->resolved = $resolved;
$baseTable = 'icinga_' . $type;
$this->baseQuery = $this->db->select()
->from(
array(self::BASE_ALIAS => $baseTable),
array('name' => 'object_name')
)->order(self::BASE_ALIAS . '.object_name');
}
public function joinVar($name)
{
if (! $this->hasJoinedVar($name)) {
$type = $this->type;
$alias = $this->safeVarAlias($name);
$varAlias = $alias . '_v';
// TODO: optionally $varRelation = sprintf('icinga_%s_resolved_var', $type);
$varRelation = sprintf('icinga_%s_var', $type);
$idCol = sprintf('%s.%s_id', $alias, $type);
$joinOn = sprintf('%s = %s.id', $idCol, self::BASE_ALIAS);
$joinVarOn = $this->db->quoteInto(
sprintf('%s.checksum = %s.checksum AND %s.varname = ?', $alias, $varAlias, $alias),
$name
);
$this->baseQuery->join(
array($alias => $varRelation),
$joinOn,
array()
)->join(
array($varAlias => 'icinga_var'),
$joinVarOn,
array($alias => $varAlias . '.varvalue')
);
$this->joinedVars[$name] = $varAlias . '.varvalue';
}
return $this;
}
public function listNames()
{
return $this->db->fetchCol(
$this->baseQuery
);
}
protected function hasJoinedVar($name)
{
return array_key_exists($name, $this->joinedVars);
}
public function getJoinedVarAlias($name)
{
return $this->joinedVars[$name];
}
// TODO: recheck this
protected function safeVarAlias($name)
{
$alias = preg_replace('/[^a-zA-Z0-9_]/', '', (string) $name);
$cnt = 1;
$checkAlias = $alias;
while (in_array($checkAlias, $this->joinedVars)) {
$cnt++;
$checkAlias = $alias . '_' . $cnt;
}
return $checkAlias;
}
public function escapedWhere($where)
{
$this->baseQuery->where(new ZfDbExpr($where));
}
/**
* @param $column
* @return string
* @throws NotFoundError
* @throws NotImplementedError
*/
public function getAliasForRequiredFilterColumn($column)
{
$dot = strpos($column, '.');
list($key, $sub) = $this->splitFilterKey($column);
if ($sub === null) {
return $key;
} else {
$objectType = $key;
}
if ($objectType === $this->type) {
list($key, $sub) = $this->splitFilterKey($sub);
if ($sub === null) {
return $key;
}
if ($key === 'vars') {
return $this->joinVar($sub)->getJoinedVarAlias($sub);
} else {
throw new NotFoundError('Not yet, my type: %s - %s', $objectType, $key);
}
} else {
throw new NotImplementedError('Not yet: %s - %s', $objectType, $sub);
}
}
protected function splitFilterKey($key)
{
$dot = strpos($key, '.');
if ($dot === false) {
return array($key, null);
} else {
return array(substr($key, 0, $dot), substr($key, $dot + 1));
}
}
protected function requireTable($name)
{
if ($alias = $this->getTableAliasFromQuery($name)) {
return $alias;
}
$this->joinTable($name);
}
protected function joinTable($name)
{
if (!array_key_exists($name, $this->requiredTables)) {
$alias = $this->makeAlias($name);
}
return $this->tableAliases($name);
}
protected function hasAlias($name)
{
return array_key_exists($name, $this->aliases);
}
protected function makeAlias($name)
{
if (substr($name, 0, 7) === 'icinga_') {
$shortName = substr($name, 7);
} else {
$shortName = $name;
}
$parts = preg_split('/_/', $shortName, -1);
$alias = '';
foreach ($parts as $part) {
$alias .= $part[0];
if (! $this->hasAlias($alias)) {
return $alias;
}
}
$cnt = 1;
do {
$cnt++;
if (! $this->hasAlias($alias . $cnt)) {
return $alias . $cnt;
}
} while (! $this->hasAlias($alias));
return $alias;
}
protected function getTableAliasFromQuery($table)
{
$tables = $this->query->getPart('from');
$key = array_search($table, $tables);
if ($key === null || $key === false) {
return false;
}
/*
'joinType' => $type,
'schema' => $schema,
'tableName' => $tableName,
'joinCondition' => $cond
*/
return $key;
}
public function whereToSql($col, $sign, $expression)
{
return $this->dummyQuery()->whereToSql($col, $sign, $expression);
}
/**
* @return DbQuery
*/
protected function dummyQuery()
{
if ($this->dummyQuery === null) {
$this->dummyQuery = $this->connection->select();
}
return $this->dummyQuery;
}
}