summaryrefslogtreecommitdiffstats
path: root/library/Cube/Web/Controller.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Cube/Web/Controller.php')
-rw-r--r--library/Cube/Web/Controller.php297
1 files changed, 297 insertions, 0 deletions
diff --git a/library/Cube/Web/Controller.php b/library/Cube/Web/Controller.php
new file mode 100644
index 0000000..028a744
--- /dev/null
+++ b/library/Cube/Web/Controller.php
@@ -0,0 +1,297 @@
+<?php
+
+// Icinga Web 2 Cube Module | (c) 2016 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Cube\Web;
+
+use Icinga\Module\Cube\DimensionParams;
+use Icinga\Module\Cube\Forms\DimensionsForm;
+use Icinga\Module\Cube\Hook\IcingaDbActionsHook;
+use Icinga\Module\Cube\IcingaDb\CustomVariableDimension;
+use Icinga\Module\Cube\IcingaDb\IcingaDbCube;
+use Icinga\Module\Icingadb\Common\Auth;
+use Icinga\Module\Icingadb\Common\Database;
+use Icinga\Module\Icingadb\Web\Control\ProblemToggle;
+use ipl\Html\FormElement\CheckboxElement;
+use ipl\Html\HtmlString;
+use ipl\Stdlib\Filter;
+use ipl\Stdlib\Str;
+use ipl\Web\Compat\CompatController;
+use ipl\Web\Compat\SearchControls;
+use ipl\Web\Control\SortControl;
+use ipl\Web\Filter\QueryString;
+use ipl\Web\Url;
+use ipl\Web\Widget\Tabs;
+
+abstract class Controller extends CompatController
+{
+ use SearchControls;
+ use Database;
+ use Auth;
+
+ /** @var string[] Preserved params for searchbar and search editor controls */
+ protected $preserveParams = [
+ 'dimensions',
+ 'showSettings',
+ 'wantNull',
+ 'problems',
+ 'sort'
+ ];
+
+ /** @var Filter\Rule Filter from query string parameters */
+ private $filter;
+
+ /**
+ * Return this controllers' cube
+ *
+ * @return IcingaDbCube
+ */
+ abstract protected function getCube(): IcingaDbCube;
+
+ /**
+ * Get the filter created from query string parameters
+ *
+ * @return Filter\Rule
+ */
+ public function getFilter(): Filter\Rule
+ {
+ if ($this->filter === null) {
+ $this->filter = QueryString::parse((string) $this->params);
+ }
+
+ return $this->filter;
+ }
+
+ public function detailsAction(): void
+ {
+ $cube = $this->prepareCube();
+ $this->getTabs()->add('details', [
+ 'label' => $this->translate('Cube details'),
+ 'url' => $this->getRequest()->getUrl()
+ ])->activate('details');
+
+ $cube->setBaseFilter($this->getFilter());
+
+ $this->setTitle($cube->getSlicesLabel());
+ $this->view->links = IcingaDbActionsHook::renderAll($cube);
+
+ $this->addContent(
+ HtmlString::create($this->view->render('/cube-details.phtml'))
+ );
+ }
+
+ protected function renderCube(): void
+ {
+ $cube = $this->prepareCube();
+ $this->setTitle(sprintf(
+ $this->translate('Cube: %s'),
+ $cube->getPathLabel()
+ ));
+
+ $this->params->shift('format');
+ $showSettings = $this->params->shift('showSettings');
+
+ $query = $cube->innerQuery();
+ $problemsOnly = (bool) $this->params->shift('problems', false);
+ $problemToggle = (new ProblemToggle($problemsOnly ?: null))
+ ->setIdProtector([$this->getRequest(), 'protectId'])
+ ->on(ProblemToggle::ON_SUCCESS, function (ProblemToggle $form) {
+ /** @var CheckboxElement $problems */
+ $problems = $form->getElement('problems');
+ if (! $problems->isChecked()) {
+ $this->redirectNow(Url::fromRequest()->remove('problems'));
+ } else {
+ $this->redirectNow(Url::fromRequest()->setParam('problems'));
+ }
+ })->handleRequest($this->getServerRequest());
+
+ $this->addControl($problemToggle);
+
+ $sortControl = SortControl::create([
+ IcingaDbCube::DIMENSION_VALUE_SORT_PARAM => t('Value'),
+ IcingaDbCube::DIMENSION_SEVERITY_SORT_PARAM . ' desc' => t('Severity'),
+ ]);
+
+ $this->params->shift($sortControl->getSortParam());
+ $cube->sortBy($sortControl->getSort());
+ $this->addControl($sortControl);
+
+ $searchBar = $this->createSearchBar(
+ $query,
+ $this->preserveParams
+ );
+
+ if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) {
+ if ($searchBar->hasBeenSubmitted()) {
+ $filter = $this->getFilter();
+ } else {
+ $this->addControl($searchBar);
+ $this->sendMultipartUpdate();
+ return;
+ }
+ } else {
+ $filter = $searchBar->getFilter();
+ }
+
+ if ($problemsOnly) {
+ $filter = Filter::all($filter, Filter::equal('state.is_problem', true));
+ }
+
+ $cube->setBaseFilter($filter);
+ $cube->problemsOnly($problemsOnly);
+
+ $this->addControl($searchBar);
+
+ if (count($cube->listDimensions()) > 0) {
+ $this->view->cube = $cube;
+ } else {
+ $showSettings = true;
+ }
+
+ $this->view->url = Url::fromRequest()
+ ->onlyWith($this->preserveParams)
+ ->setFilter($searchBar->getFilter());
+
+ if ($showSettings) {
+ $form = (new DimensionsForm())
+ ->setUrl($this->view->url)
+ ->setCube($cube)
+ ->on(DimensionsForm::ON_SUCCESS, function ($form) {
+ $this->redirectNow($form->getRedirectUrl());
+ })
+ ->handleRequest($this->getServerRequest());
+
+ $this->view->form = $form;
+ } else {
+ $this->setAutorefreshInterval(15);
+ }
+
+ $this->addContent(
+ HtmlString::create($this->view->render('/cube-index.phtml'))
+ );
+
+ if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {
+ $this->sendMultipartUpdate();
+ }
+ }
+
+ private function prepareCube(): IcingaDbCube
+ {
+ $cube = $this->getCube();
+ $cube->chooseFacts(array_keys($cube->getAvailableFactColumns()));
+
+ $dimensions = DimensionParams::fromString(
+ $this->params->shift('dimensions', '')
+ )->getDimensions();
+
+ if ($this->hasLegacyDimensionParams($dimensions)) {
+ $this->transformLegacyDimensionParamsAndRedirect($dimensions);
+ }
+
+ $wantNull = $this->params->shift('wantNull');
+ foreach ($dimensions as $dimension) {
+ $cube->addDimensionByName($dimension);
+ if ($wantNull) {
+ $cube->getDimension($dimension)->wantNull();
+ }
+
+ $sliceParamWithPrefix = rawurlencode($cube::SLICE_PREFIX . $dimension);
+
+ if ($this->params->has($sliceParamWithPrefix)) {
+ $this->preserveParams[] = $sliceParamWithPrefix;
+ $cube->slice($dimension, $this->params->shift($sliceParamWithPrefix));
+ }
+ }
+
+ return $cube;
+ }
+
+ /**
+ * Get whether the given dimension param is legacy dimension param
+ *
+ * @param string $dimensionParam
+ *
+ * @return bool
+ */
+ private function isLegacyDimensionParam(string $dimensionParam): bool
+ {
+ return ! Str::startsWith($dimensionParam, CustomVariableDimension::HOST_PREFIX)
+ && ! Str::startsWith($dimensionParam, CustomVariableDimension::SERVICE_PREFIX);
+ }
+
+ /**
+ * Get whether the dimensions contain legacy dimension
+ *
+ * @param array $dimensions
+ *
+ * @return bool
+ */
+ private function hasLegacyDimensionParams(array $dimensions): bool
+ {
+ foreach ($dimensions as $dimension) {
+ if ($this->isLegacyDimensionParam($dimension)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Transform legacy dimension and slice params and redirect
+ *
+ * This adds the new prefix to params and then redirects so that the new URL contains the prefixed params
+ * Slices are prefixed to differ filter and slice params
+ *
+ * @param array $legacyDimensions
+ */
+ private function transformLegacyDimensionParamsAndRedirect(array $legacyDimensions): void
+ {
+ $dimensions = [];
+ $slices = [];
+
+ $dimensionPrefix = CustomVariableDimension::HOST_PREFIX;
+ if ($this->getRequest()->getControllerName() === 'services') {
+ $dimensionPrefix = CustomVariableDimension::SERVICE_PREFIX;
+ }
+
+ foreach ($legacyDimensions as $param) {
+ $newParam = $param;
+ if ($this->isLegacyDimensionParam($param)) {
+ $newParam = $dimensionPrefix . $param;
+ }
+
+ $slice = $this->params->shift($param);
+ if ($slice) {
+ $slices[IcingaDbCube::SLICE_PREFIX . $newParam] = $slice;
+ }
+
+ $dimensions[] = $newParam;
+ }
+
+ $this->redirectNow(
+ Url::fromRequest()
+ ->setParam('dimensions', DimensionParams::fromArray($dimensions)->getParams())
+ ->addParams($slices)
+ ->without($legacyDimensions)
+ );
+ }
+
+ public function createTabs(): Tabs
+ {
+ $params = Url::fromRequest()
+ ->onlyWith($this->preserveParams)
+ ->getParams()
+ ->toString();
+
+ return $this->getTabs()
+ ->add('cube/hosts', [
+ 'label' => $this->translate('Hosts'),
+ 'url' => 'cube/hosts' . ($params === '' ? '' : '?' . $params)
+ ])
+ ->add('cube/services', [
+ 'label' => $this->translate('Services'),
+ 'url' => 'cube/services' . ($params === '' ? '' : '?' . $params)
+ ]);
+ }
+}