summaryrefslogtreecommitdiffstats
path: root/library/Director/Data/Db/IcingaObjectQuery.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Director/Data/Db/IcingaObjectQuery.php255
1 files changed, 255 insertions, 0 deletions
diff --git a/library/Director/Data/Db/IcingaObjectQuery.php b/library/Director/Data/Db/IcingaObjectQuery.php
new file mode 100644
index 0000000..4556ba7
--- /dev/null
+++ b/library/Director/Data/Db/IcingaObjectQuery.php
@@ -0,0 +1,255 @@
+<?php
+
+namespace Icinga\Module\Director\Data\Db;
+
+use Icinga\Data\Db\DbQuery;
+use Icinga\Data\Filter\Filter;
+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 = "v_$alias";
+ // 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;
+ }
+
+ // Debug only
+ public function getSql()
+ {
+ return (string) $this->baseQuery;
+ }
+
+ 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)
+ {
+ 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 [$key, null];
+ } else {
+ return [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->connection->renderFilter(Filter::expression($col, $sign, $expression));
+ }
+}