summaryrefslogtreecommitdiffstats
path: root/library/Director/Web/Table/ObjectsTable.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Director/Web/Table/ObjectsTable.php315
1 files changed, 315 insertions, 0 deletions
diff --git a/library/Director/Web/Table/ObjectsTable.php b/library/Director/Web/Table/ObjectsTable.php
new file mode 100644
index 0000000..792cb6d
--- /dev/null
+++ b/library/Director/Web/Table/ObjectsTable.php
@@ -0,0 +1,315 @@
+<?php
+
+namespace Icinga\Module\Director\Web\Table;
+
+use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Db\DbSelectParenthesis;
+use Icinga\Module\Director\Db\IcingaObjectFilterHelper;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Restriction\FilterByNameRestriction;
+use Icinga\Module\Director\Restriction\HostgroupRestriction;
+use Icinga\Module\Director\Restriction\ObjectRestriction;
+use gipfl\IcingaWeb2\Link;
+use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
+use gipfl\IcingaWeb2\Url;
+use Ramsey\Uuid\Uuid;
+use Zend_Db_Select as ZfSelect;
+
+class ObjectsTable extends ZfQueryBasedTable
+{
+ use TableWithBranchSupport;
+
+ /** @var ObjectRestriction[] */
+ protected $objectRestrictions;
+
+ protected $columns = [
+ 'object_name' => 'o.object_name',
+ 'object_type' => 'o.object_type',
+ 'disabled' => 'o.disabled',
+ 'uuid' => 'o.uuid',
+ ];
+
+ protected $searchColumns = ['o.object_name'];
+
+ protected $showColumns = ['object_name' => 'Name'];
+
+ protected $filterObjectType = 'object';
+
+ protected $type;
+
+ protected $baseObjectUrl;
+
+ /** @var IcingaObject */
+ protected $dummyObject;
+
+ protected $leftSubQuery;
+
+ protected $rightSubQuery;
+
+ /** @var Auth */
+ private $auth;
+
+ /**
+ * @param $type
+ * @param Db $db
+ * @return static
+ */
+ public static function create($type, Db $db)
+ {
+ $class = __NAMESPACE__ . '\\ObjectsTable' . ucfirst($type);
+ if (! class_exists($class)) {
+ $class = __CLASS__;
+ }
+
+ /** @var static $table */
+ $table = new $class($db);
+ $table->type = $type;
+ return $table;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @param string $url
+ * @return $this
+ */
+ public function setBaseObjectUrl($url)
+ {
+ $this->baseObjectUrl = $url;
+
+ return $this;
+ }
+
+ /**
+ * @return Auth
+ */
+ public function getAuth()
+ {
+ return $this->auth;
+ }
+
+ public function setAuth(Auth $auth)
+ {
+ $this->auth = $auth;
+ return $this;
+ }
+
+ public function filterObjectType($type)
+ {
+ $this->filterObjectType = $type;
+ return $this;
+ }
+
+ public function addObjectRestriction(ObjectRestriction $restriction)
+ {
+ $this->objectRestrictions[$restriction->getName()] = $restriction;
+ return $this;
+ }
+
+ public function getColumns()
+ {
+ return $this->columns;
+ }
+
+ public function getColumnsToBeRendered()
+ {
+ return $this->showColumns;
+ }
+
+ public function filterTemplate(
+ IcingaObject $template,
+ $inheritance = Db\IcingaObjectFilterHelper::INHERIT_DIRECT
+ ) {
+ IcingaObjectFilterHelper::filterByTemplate(
+ $this->getQuery(),
+ $template,
+ 'o',
+ $inheritance
+ );
+
+ return $this;
+ }
+
+ protected function getMainLinkLabel($row)
+ {
+ return $row->object_name;
+ }
+
+ protected function renderObjectNameColumn($row)
+ {
+ $type = $this->baseObjectUrl;
+ $url = Url::fromPath("director/${type}", [
+ 'uuid' => Uuid::fromBytes($row->uuid)->toString()
+ ]);
+
+ return static::td(Link::create($this->getMainLinkLabel($row), $url));
+ }
+
+ protected function renderExtraColumns($row)
+ {
+ $columns = $this->getColumnsToBeRendered();
+ unset($columns['object_name']);
+ $cols = [];
+ foreach ($columns as $key => & $label) {
+ $cols[] = static::td($row->$key);
+ }
+
+ return $cols;
+ }
+
+ public function renderRow($row)
+ {
+ if (isset($row->uuid) && is_resource($row->uuid)) {
+ $row->uuid = stream_get_contents($row->uuid);
+ }
+ $tr = static::tr([
+ $this->renderObjectNameColumn($row),
+ $this->renderExtraColumns($row)
+ ]);
+
+ $classes = $this->getRowClasses($row);
+ if ($row->disabled === 'y') {
+ $classes[] = 'disabled';
+ }
+ if (! empty($classes)) {
+ $tr->getAttributes()->add('class', $classes);
+ }
+
+ return $tr;
+ }
+
+ protected function getRowClasses($row)
+ {
+ // TODO: remove isset, to figure out where it is missing
+ if (isset($row->branch_uuid) && $row->branch_uuid !== null) {
+ return ['branch_modified'];
+ }
+ return [];
+ }
+
+ protected function applyObjectTypeFilter(ZfSelect $query, ZfSelect $right = null)
+ {
+ if ($right) {
+ $right->where(
+ 'bo.object_type = ?',
+ $this->filterObjectType
+ );
+ }
+ return $query->where(
+ 'o.object_type = ?',
+ $this->filterObjectType
+ );
+ }
+
+ protected function applyRestrictions(ZfSelect $query)
+ {
+ foreach ($this->getRestrictions() as $restriction) {
+ $restriction->applyToQuery($query);
+ }
+
+ return $query;
+ }
+
+ protected function getRestrictions()
+ {
+ if ($this->objectRestrictions === null) {
+ $this->objectRestrictions = $this->loadRestrictions();
+ }
+
+ return $this->objectRestrictions;
+ }
+
+ protected function loadRestrictions()
+ {
+ /** @var Db $db */
+ $db = $this->connection();
+ $auth = $this->getAuth();
+
+ return [
+ new HostgroupRestriction($db, $auth),
+ new FilterByNameRestriction($db, $auth, $this->getDummyObject()->getShortTableName())
+ ];
+ }
+
+ /**
+ * @return IcingaObject
+ */
+ protected function getDummyObject()
+ {
+ if ($this->dummyObject === null) {
+ $type = $this->getType();
+ $this->dummyObject = IcingaObject::createByType($type);
+ }
+ return $this->dummyObject;
+ }
+
+ protected function prepareQuery()
+ {
+ $table = $this->getDummyObject()->getTableName();
+ if ($this->branchUuid) {
+ $this->columns['branch_uuid'] = 'bo.branch_uuid';
+ }
+
+ $columns = $this->getColumns();
+ if ($this->branchUuid) {
+ $columns = $this->branchifyColumns($columns);
+ $this->stripSearchColumnAliases();
+ }
+ $query = $this->db()->select()->from(['o' => $table], $columns);
+
+ if ($this->branchUuid) {
+ $right = clone($query);
+ // Hint: Right part has only those with object = null
+ // This means that restrictions on $right would hide all
+ // new rows. Dedicated restriction logic for the branch-only
+ // part of thw union are not required, we assume that restrictions
+ // for new objects have been checked once they have been created
+ $query = $this->applyRestrictions($query);
+ /** @var Db $conn */
+ $conn = $this->connection();
+ $query->joinLeft(
+ ['bo' => "branched_$table"],
+ // TODO: PgHexFunc
+ $this->db()->quoteInto(
+ 'bo.uuid = o.uuid AND bo.branch_uuid = ?',
+ $conn->quoteBinary($this->branchUuid->getBytes())
+ ),
+ []
+ )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')");
+ $this->applyObjectTypeFilter($query, $right);
+ $right->joinRight(
+ ['bo' => "branched_$table"],
+ 'bo.uuid = o.uuid',
+ []
+ )
+ ->where('o.uuid IS NULL')
+ ->where('bo.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes()));
+ $this->leftSubQuery = $query;
+ $this->rightSubQuery = $right;
+ $query = $this->db()->select()->union([
+ 'l' => new DbSelectParenthesis($query),
+ 'r' => new DbSelectParenthesis($right),
+ ]);
+ $query = $this->db()->select()->from(['u' => $query]);
+ $query->order('object_name')->limit(100);
+ } else {
+ $this->applyObjectTypeFilter($query);
+ $query->order('o.object_name')->limit(100);
+ }
+
+ return $query;
+ }
+
+ public function removeQueryLimit()
+ {
+ $query = $this->getQuery();
+ $query->reset($query::LIMIT_OFFSET);
+ $query->reset($query::LIMIT_COUNT);
+
+ return $this;
+ }
+}