icingadb-web/library/Icingadb/Web/Controller.php
Johannes Meyer 07dae00410 Controller: Add showCompact to a search bar's suggestion url
Otherwise controls will appear in the suggestion dropdown.
2021-01-14 11:08:53 +01:00

357 lines
10 KiB
PHP

<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Web;
use Generator;
use GuzzleHttp\Psr7\ServerRequest;
use Icinga\Application\Icinga;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Compat\MonitoringRestrictions;
use Icinga\Module\Icingadb\Compat\UrlMigrator;
use Icinga\Module\Icingadb\Widget\BaseItemList;
use Icinga\Module\Icingadb\Widget\FilterControl;
use Icinga\Module\Icingadb\Widget\ViewModeSwitcher;
use ipl\Html\Html;
use ipl\Html\ValidHtml;
use ipl\Orm\Common\SortUtil;
use ipl\Orm\Compat\FilterProcessor;
use ipl\Orm\Query;
use ipl\Stdlib\Contract\Paginatable;
use ipl\Web\Compat\CompatController;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\PaginationControl;
use ipl\Web\Control\SearchBar;
use ipl\Web\Control\SortControl;
use ipl\Web\Url;
class Controller extends CompatController
{
use Database;
/** @var Filter Filter from query string parameters */
private $filter;
/** @var string|null */
private $format;
/**
* Get the filter created from query string parameters
*
* @return Filter
*/
public function getFilter()
{
if ($this->filter === null) {
$this->filter = Filter::fromQueryString((string) $this->params);
}
return $this->filter;
}
/**
* Create and return the LimitControl
*
* This automatically shifts the limit URL parameter from {@link $params}.
*
* @return LimitControl
*/
public function createLimitControl()
{
$limitControl = new LimitControl(Url::fromRequest());
$this->params->shift($limitControl->getLimitParam());
return $limitControl;
}
/**
* Create and return the PaginationControl
*
* This automatically shifts the pagination URL parameters from {@link $params}.
*
* @return PaginationControl
*/
public function createPaginationControl(Paginatable $paginatable)
{
$paginationControl = new PaginationControl($paginatable, Url::fromRequest());
$this->params->shift($paginationControl->getPageParam());
$this->params->shift($paginationControl->getPageSizeParam());
return $paginationControl;
}
/**
* Create and return the SortControl
*
* This automatically shifts the sort URL parameter from {@link $params}.
*
* @param Query $query
* @param array $columns Possible sort columns as sort string-label pairs
*
* @return SortControl
*/
public function createSortControl(Query $query, array $columns)
{
$default = (array) $query->getModel()->getDefaultSort();
$normalized = [];
foreach ($columns as $key => $value) {
$normalized[SortUtil::normalizeSortSpec($key)] = $value;
}
$sortControl = (new SortControl(Url::fromRequest()))
->setColumns($normalized);
if (! empty($default)) {
$sortControl->setDefault(SortUtil::normalizeSortSpec($default));
}
$sort = $sortControl->getSort();
if (! empty($sort)) {
$query->orderBy(SortUtil::createOrderBy($sort));
}
$this->params->shift($sortControl->getSortParam());
return $sortControl;
}
/**
* Create and return the SearchBar
*
* @param array $preserveParams Query params to preserve when redirecting
*
* @return SearchBar
*/
public function createSearchBar(array $preserveParams = null)
{
$requestUrl = Url::fromRequest();
if ($preserveParams !== null) {
$requestUrl = $requestUrl->onlyWith($preserveParams);
}
$searchBar = new SearchBar();
$searchBar->setSubmitLabel(t('Search'));
$searchBar->setFilter($this->getFilter());
$searchBar->setAction($requestUrl->getAbsoluteUrl());
$searchBar->setIdProtector([$this->getRequest(), 'protectId']);
if (method_exists($this, 'completeAction')) {
$searchBar->setSuggestionUrl(Url::fromPath(
'icingadb/' . $this->getRequest()->getControllerName() . '/complete',
['_disableLayout' => true, 'showCompact' => true]
));
}
$searchBar->on(SearchBar::ON_SUCCESS, function (SearchBar $form) use ($requestUrl) {
$existingParams = $requestUrl->getParams();
$requestUrl->setQueryString($form->getFilter()->toQueryString());
foreach ($existingParams->toArray(false) as $name => $value) {
$requestUrl->getParams()->addEncoded($name, $value);
}
$this->getResponse()->redirectAndExit($requestUrl);
})->handleRequest(ServerRequest::fromGlobals());
Html::tag('div', ['class' => 'filter'])->wrap($searchBar);
return $searchBar;
}
/**
* Create and return the FilterControl
*
* @param Query $query
* @param array $preserveParams
*
* @return FilterControl
*/
public function createFilterControl(Query $query, array $preserveParams = null)
{
$request = clone $this->getRequest();
$params = clone $this->params;
if (! empty($preserveParams)) {
foreach ($preserveParams as $param) {
if (! $params->has($param) && ($value = $request->getUrl()->getParam($param)) !== null) {
$params->set($param, $value);
}
}
}
$request->getUrl()->setParams($params);
$filterControl = new FilterControl($query, $preserveParams);
$filterControl->handleRequest($request);
// We're cloning the params, the editor does it, so we have to shift these ourselves
$this->params->shift('addFilter');
$this->params->shift('removeFilter');
$this->params->shift('stripFilter');
$this->params->shift('modifyFilter');
$this->params->shift('q');
return $filterControl;
}
/**
* Create and return the ViewModeSwitcher
*
* This automatically shifts the view mode URL parameter from {@link $params}.
*
* @return ViewModeSwitcher
*/
public function createViewModeSwitcher()
{
$viewModeSwitcher = new ViewModeSwitcher(Url::fromRequest());
$this->params->shift($viewModeSwitcher->getViewModeParam());
return $viewModeSwitcher;
}
/**
* Process a search request
*
* @param Query $query
*/
public function handleSearchRequest(Query $query)
{
$q = trim($this->params->shift('q', ''), ' *');
if (! $q) {
return;
}
$filter = Filter::matchAny();
foreach ($query->getModel()->getSearchColumns() as $column) {
$filter->addFilter(Filter::where($column, "*$q*"));
}
$requestUrl = Url::fromRequest();
$existingParams = $requestUrl->getParams()->without('q');
$requestUrl->setQueryString($filter->toQueryString());
foreach ($existingParams->toArray(false) as $name => $value) {
$requestUrl->getParams()->addEncoded($name, $value);
}
$this->getResponse()->redirectAndExit($requestUrl);
}
public function export(Query ...$queries)
{
if ($this->format === 'sql') {
foreach ($queries as $query) {
list($sql, $values) = $query->getDb()->getQueryBuilder()->assembleSelect($query->assembleSelect());
$unused = [];
foreach ($values as $value) {
$pos = strpos($sql, '?');
if ($pos !== false) {
if (is_string($value)) {
$value = "'" . $value . "'";
}
$sql = substr_replace($sql, $value, $pos, 1);
} else {
$unused[] = $value;
}
}
if (!empty($unused)) {
$sql .= ' /* Unused values: "' . join('", "', $unused) . '" */';
}
$this->content->add(Html::tag('pre', $sql));
}
return true;
}
$this->getTabs()->enableDataExports();
}
public function dispatch($action)
{
// Notify helpers of action preDispatch state
$this->_helper->notifyPreDispatch();
$this->preDispatch();
if ($this->getRequest()->isDispatched()) {
// If pre-dispatch hooks introduced a redirect then stop dispatch
// @see ZF-7496
if (! $this->getResponse()->isRedirect()) {
$interceptable = $this->$action();
if ($interceptable instanceof Generator) {
foreach ($interceptable as $stopSignal) {
if ($stopSignal === true) {
break;
}
}
}
}
$this->postDispatch();
}
// whats actually important here is that this action controller is
// shutting down, regardless of dispatching; notify the helpers of this
// state
$this->_helper->notifyPostDispatch();
}
protected function addContent(ValidHtml $content)
{
if ($content instanceof BaseItemList) {
$this->content->getAttributes()->add('class', 'full-width');
}
return parent::addContent($content);
}
public function filter(Query $query)
{
$this->applyMonitoringRestriction($query);
FilterProcessor::apply(
$this->getFilter(),
$query
);
return $this;
}
public function applyMonitoringRestriction(Query $query, $queryTransformer = null)
{
if ($queryTransformer === null || UrlMigrator::hasQueryTransformer($queryTransformer)) {
$restriction = UrlMigrator::transformFilter(
MonitoringRestrictions::getRestriction('monitoring/filter/objects'),
$queryTransformer
);
if ($restriction) {
FilterProcessor::apply($restriction, $query);
}
}
return $this;
}
public function preDispatch()
{
parent::preDispatch();
$this->format = $this->params->shift('format');
}
protected function moduleInit()
{
Icinga::app()->getModuleManager()->loadModule('monitoring');
Icinga::app()->getFrontController()
->getPlugin('Zend_Controller_Plugin_ErrorHandler')
->setErrorHandlerModule('icingadb');
}
}