Skip to content

Commit bb391af

Browse files
authored
Merge pull request #69 from Icinga/introduce-search-controls-trait
Introduce `ipl\Web\Compat\SearchControls`
2 parents fa4fe19 + 4881c18 commit bb391af

File tree

2 files changed

+218
-2
lines changed

2 files changed

+218
-2
lines changed

src/Compat/SearchControls.php

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<?php
2+
3+
namespace ipl\Web\Compat;
4+
5+
use GuzzleHttp\Psr7\ServerRequest;
6+
use ipl\Orm\Query;
7+
use ipl\Stdlib\Seq;
8+
use ipl\Web\Control\SearchBar;
9+
use ipl\Web\Control\SearchEditor;
10+
use ipl\Web\Filter\QueryString;
11+
use ipl\Web\Url;
12+
use ipl\Stdlib\Filter;
13+
14+
trait SearchControls
15+
{
16+
/**
17+
* Fetch meta-data for the given query
18+
*
19+
* @param Query $query
20+
*
21+
* @return array
22+
*/
23+
abstract public function fetchMetaData(Query $query);
24+
25+
/**
26+
* Get whether {@see SearchControls::createSearchBar()} and {@see SearchControls::createSearchEditor()}
27+
* should handle form submits.
28+
*
29+
* @return bool
30+
*/
31+
private function callHandleRequest()
32+
{
33+
return true;
34+
}
35+
36+
/**
37+
* Create and return the SearchBar
38+
*
39+
* @param Query $query The query being filtered
40+
* @param array $preserveParams Query params to preserve when redirecting
41+
*
42+
* @return SearchBar
43+
*/
44+
public function createSearchBar(Query $query, array $preserveParams = null): SearchBar
45+
{
46+
$requestUrl = Url::fromRequest();
47+
$redirectUrl = $preserveParams !== null
48+
? $requestUrl->onlyWith($preserveParams)
49+
: (clone $requestUrl)->setParams([]);
50+
51+
$filter = QueryString::fromString((string) $this->params)
52+
->on(QueryString::ON_CONDITION, function (Filter\Condition $condition) use ($query) {
53+
$this->enrichFilterCondition($condition, $query);
54+
})
55+
->parse();
56+
57+
$searchBar = new SearchBar();
58+
$searchBar->setFilter($filter);
59+
$searchBar->setAction($redirectUrl->getAbsoluteUrl());
60+
$searchBar->setIdProtector([$this->getRequest(), 'protectId']);
61+
62+
$moduleName = $this->getRequest()->getModuleName();
63+
$controllerName = $this->getRequest()->getControllerName();
64+
65+
if (method_exists($this, 'completeAction')) {
66+
$searchBar->setSuggestionUrl(Url::fromPath(
67+
"$moduleName/$controllerName/complete",
68+
['_disableLayout' => true, 'showCompact' => true]
69+
));
70+
}
71+
72+
if (method_exists($this, 'searchEditorAction')) {
73+
$searchBar->setEditorUrl(Url::fromPath(
74+
"$moduleName/$controllerName/search-editor"
75+
)->setParams($redirectUrl->getParams()));
76+
}
77+
78+
$metaData = $this->fetchMetaData($query);
79+
$columnValidator = function (SearchBar\ValidatedColumn $column) use ($query, $metaData) {
80+
$columnPath = $column->getSearchValue();
81+
if (strpos($columnPath, '.') === false) {
82+
$columnPath = $query->getResolver()->qualifyPath($columnPath, $query->getModel()->getTableName());
83+
}
84+
85+
if (! isset($metaData[$columnPath])) {
86+
list($columnPath, $columnLabel) = Seq::find($metaData, $column->getSearchValue(), false);
87+
if ($columnPath === null) {
88+
$column->setMessage(t('Is not a valid column'));
89+
} else {
90+
$column->setSearchValue($columnPath);
91+
$column->setLabel($columnLabel);
92+
}
93+
} else {
94+
$column->setLabel($metaData[$columnPath]);
95+
}
96+
};
97+
98+
$searchBar->on(SearchBar::ON_ADD, $columnValidator)
99+
->on(SearchBar::ON_INSERT, $columnValidator)
100+
->on(SearchBar::ON_SAVE, $columnValidator)
101+
->on(SearchBar::ON_SENT, function (SearchBar $form) use ($redirectUrl) {
102+
$existingParams = $redirectUrl->getParams();
103+
$redirectUrl->setQueryString(QueryString::render($form->getFilter()));
104+
foreach ($existingParams->toArray(false) as $name => $value) {
105+
if (is_int($name)) {
106+
$name = $value;
107+
$value = true;
108+
}
109+
110+
$redirectUrl->getParams()->addEncoded($name, $value);
111+
}
112+
113+
$form->setRedirectUrl($redirectUrl);
114+
})->on(SearchBar::ON_SUCCESS, function (SearchBar $form) {
115+
$this->getResponse()->redirectAndExit($form->getRedirectUrl());
116+
});
117+
118+
if ($this->callHandleRequest()) {
119+
$searchBar->handleRequest(ServerRequest::fromGlobals());
120+
}
121+
122+
return $searchBar;
123+
}
124+
125+
/**
126+
* Create and return the SearchEditor
127+
*
128+
* @param Query $query The query being filtered
129+
* @param array $preserveParams Query params to preserve when redirecting
130+
*
131+
* @return SearchEditor
132+
*/
133+
public function createSearchEditor(Query $query, array $preserveParams = null): SearchEditor
134+
{
135+
$requestUrl = Url::fromRequest();
136+
$moduleName = $this->getRequest()->getModuleName();
137+
$controllerName = $this->getRequest()->getControllerName();
138+
$redirectUrl = Url::fromPath("$moduleName/$controllerName");
139+
if (! empty($preserveParams)) {
140+
$redirectUrl->setParams($requestUrl->onlyWith($preserveParams)->getParams());
141+
}
142+
143+
$editor = new SearchEditor();
144+
$editor->setQueryString((string) $this->params->without($preserveParams));
145+
$editor->setAction($requestUrl->getAbsoluteUrl());
146+
147+
if (method_exists($this, 'completeAction')) {
148+
$editor->setSuggestionUrl(Url::fromPath(
149+
"$moduleName/$controllerName/complete",
150+
['_disableLayout' => true, 'showCompact' => true]
151+
));
152+
}
153+
154+
$editor->getParser()->on(QueryString::ON_CONDITION, function (Filter\Condition $condition) use ($query) {
155+
if ($condition->getColumn()) {
156+
$this->enrichFilterCondition($condition, $query);
157+
}
158+
});
159+
160+
$metaData = $this->fetchMetaData($query);
161+
$editor->on(SearchEditor::ON_VALIDATE_COLUMN, function (Filter\Condition $condition) use ($query, $metaData) {
162+
$column = $condition->getColumn();
163+
if (! isset($metaData[$column])) {
164+
$path = Seq::findKey($metaData, $condition->metaData()->get('columnLabel', $column), false);
165+
if ($path === null) {
166+
throw new SearchBar\SearchException(t('Is not a valid column'));
167+
} else {
168+
$condition->setColumn($path);
169+
}
170+
}
171+
})->on(SearchEditor::ON_SUCCESS, function (SearchEditor $form) use ($redirectUrl) {
172+
$existingParams = $redirectUrl->getParams();
173+
$redirectUrl->setQueryString(QueryString::render($form->getFilter()));
174+
foreach ($existingParams->toArray(false) as $name => $value) {
175+
if (is_int($name)) {
176+
$name = $value;
177+
$value = true;
178+
}
179+
180+
$redirectUrl->getParams()->addEncoded($name, $value);
181+
}
182+
183+
$this->getResponse()
184+
->setHeader('X-Icinga-Container', '_self')
185+
->redirectAndExit($redirectUrl);
186+
});
187+
188+
if ($this->callHandleRequest()) {
189+
$editor->handleRequest(ServerRequest::fromGlobals());
190+
}
191+
192+
return $editor;
193+
}
194+
195+
/**
196+
* Enrich the filter condition with meta data from the query
197+
*
198+
* @param Filter\Condition $condition
199+
* @param Query $query
200+
*
201+
* @return void
202+
*/
203+
protected function enrichFilterCondition(Filter\Condition $condition, Query $query)
204+
{
205+
$path = $condition->getColumn();
206+
if (strpos($path, '.') === false) {
207+
$path = $query->getResolver()->qualifyPath($path, $query->getModel()->getTableName());
208+
$condition->setColumn($path);
209+
}
210+
211+
$metaData = $this->fetchMetaData($query);
212+
if (isset($metaData[$path])) {
213+
$condition->metaData()->set('columnLabel', $metaData[$path]);
214+
}
215+
}
216+
}

src/Control/SearchBar/ValidatedTerm.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,13 @@ public function getMessage()
131131
/**
132132
* Set the validation message
133133
*
134-
* @param string $message
134+
* @param ?string $message
135135
*
136136
* @return $this
137137
*/
138138
public function setMessage($message)
139139
{
140-
$this->message = (string) $message;
140+
$this->message = $message;
141141

142142
return $this;
143143
}

0 commit comments

Comments
 (0)