summaryrefslogtreecommitdiffstats
path: root/vendor/ipl/web/src/Control/SortControl.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ipl/web/src/Control/SortControl.php')
-rw-r--r--vendor/ipl/web/src/Control/SortControl.php293
1 files changed, 293 insertions, 0 deletions
diff --git a/vendor/ipl/web/src/Control/SortControl.php b/vendor/ipl/web/src/Control/SortControl.php
new file mode 100644
index 0000000..65c2c3d
--- /dev/null
+++ b/vendor/ipl/web/src/Control/SortControl.php
@@ -0,0 +1,293 @@
+<?php
+
+namespace ipl\Web\Control;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use ipl\Html\Form;
+use ipl\Html\FormDecorator\DivDecorator;
+use ipl\Html\FormElement\ButtonElement;
+use ipl\Html\HtmlElement;
+use ipl\Orm\Common\SortUtil;
+use ipl\Orm\Query;
+use ipl\Stdlib\Str;
+use ipl\Web\Common\FormUid;
+use ipl\Web\Url;
+use ipl\Web\Widget\Icon;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Allows to adjust the order of the items to display
+ */
+class SortControl extends Form
+{
+ use FormUid;
+
+ /** @var string Default sort param */
+ public const DEFAULT_SORT_PARAM = 'sort';
+
+ protected $defaultAttributes = ['class' => 'sort-control'];
+
+ /** @var string Name of the URL parameter which stores the sort column */
+ protected $sortParam = self::DEFAULT_SORT_PARAM;
+
+ /**
+ * @var Url Request URL
+ * @deprecated Access {@see self::getRequest()} instead.
+ * @todo Remove once cube calls {@see self::handleRequest()}.
+ */
+ protected $url;
+
+ /** @var array Possible sort columns as sort string-value pairs */
+ private $columns;
+
+ /** @var ?string Default sort string */
+ private $default;
+
+ protected $method = 'GET';
+
+ /**
+ * Create a new sort control
+ *
+ * @param array $columns Possible sort columns
+ * @param Url $url Request URL
+ *
+ * @internal Use {@see self::create()} instead.
+ */
+ private function __construct(array $columns, Url $url)
+ {
+ $this->setColumns($columns);
+ $this->url = $url;
+ }
+
+ /**
+ * Create a new sort control with the given options
+ *
+ * @param array<string,string> $options A sort spec to label map
+ *
+ * @return static
+ */
+ public static function create(array $options)
+ {
+ $normalized = [];
+ foreach ($options as $spec => $label) {
+ $normalized[SortUtil::normalizeSortSpec($spec)] = $label;
+ }
+
+ $self = new static($normalized, Url::fromRequest());
+
+ $self->on(self::ON_REQUEST, function (ServerRequestInterface $request) use ($self) {
+ if (! $self->hasBeenSent()) {
+ // If the form is submitted by POST, handleRequest() won't access the URL, so we have to
+ if (($sort = $request->getQueryParams()[$self->getSortParam()] ?? null)) {
+ $self->populate([$self->getSortParam() => $sort]);
+ }
+ }
+ });
+
+ return $self;
+ }
+
+ /**
+ * Get the possible sort columns
+ *
+ * @return array Sort string-value pairs
+ */
+ public function getColumns(): array
+ {
+ return $this->columns;
+ }
+
+ /**
+ * Set the possible sort columns
+ *
+ * @param array $columns Sort string-value pairs
+ *
+ * @return $this
+ */
+ public function setColumns(array $columns): self
+ {
+ // We're working with lowercase keys throughout the sort control
+ $this->columns = array_change_key_case($columns, CASE_LOWER);
+
+ return $this;
+ }
+
+ /**
+ * Get the default sort string
+ *
+ * @return ?string
+ */
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ /**
+ * Set the default sort string
+ *
+ * @param string $default
+ *
+ * @return $this
+ */
+ public function setDefault(string $default): self
+ {
+ // We're working with lowercase keys throughout the sort control
+ $this->default = strtolower($default);
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the URL parameter which stores the sort
+ *
+ * @return string
+ */
+ public function getSortParam(): string
+ {
+ return $this->sortParam;
+ }
+
+ /**
+ * Set the name of the URL parameter which stores the sort
+ *
+ * @param string $sortParam
+ *
+ * @return $this
+ */
+ public function setSortParam(string $sortParam): self
+ {
+ $this->sortParam = $sortParam;
+
+ return $this;
+ }
+
+ /**
+ * Get the sort string
+ *
+ * @return ?string
+ */
+ public function getSort(): ?string
+ {
+ if ($this->getRequest() === null) {
+ $sort = $this->url->getParam($this->getSortParam(), $this->getDefault());
+ } else {
+ $sort = $this->getPopulatedValue($this->getSortParam(), $this->getDefault());
+ }
+
+ if (! empty($sort)) {
+ $columns = $this->getColumns();
+
+ if (! isset($columns[$sort])) {
+ // Choose sort string based on the first closest match
+ foreach (array_keys($columns) as $key) {
+ if (Str::startsWith($key, $sort)) {
+ $this->populate([$this->getSortParam() => $key]);
+ $sort = $key;
+
+ break;
+ }
+ }
+ }
+ }
+
+ return $sort;
+ }
+
+ /**
+ * Sort the given query according to the request
+ *
+ * @param Query $query
+ * @param ?array|string $defaultSort
+ *
+ * @return $this
+ */
+ public function apply(Query $query, $defaultSort = null): self
+ {
+ if ($this->getRequest() === null) {
+ // handleRequest() has not been called yet
+ // TODO: Remove this once everything using this requires ipl v0.12.0
+ $this->handleRequest(ServerRequest::fromGlobals());
+ }
+
+ $default = $defaultSort ?? (array) $query->getModel()->getDefaultSort();
+ if (! empty($default)) {
+ $this->setDefault(SortUtil::normalizeSortSpec($default));
+ }
+
+ $sort = $this->getSort();
+ if (! empty($sort)) {
+ $query->orderBy(SortUtil::createOrderBy($sort));
+ }
+
+ return $this;
+ }
+
+ protected function assemble()
+ {
+ $columns = $this->getColumns();
+ $sort = $this->getSort();
+
+ if (empty($sort)) {
+ reset($columns);
+ $sort = key($columns);
+ }
+
+ $sort = explode(',', $sort, 2);
+ list($column, $direction) = Str::symmetricSplit(array_shift($sort), ' ', 2);
+
+ if (! $direction || strtolower($direction) === 'asc') {
+ $toggleIcon = 'sort-alpha-down';
+ $toggleDirection = 'desc';
+ } else {
+ $toggleIcon = 'sort-alpha-down-alt';
+ $toggleDirection = 'asc';
+ }
+
+ if ($direction !== null) {
+ $value = implode(',', array_merge(["{$column} {$direction}"], $sort));
+ if (! isset($columns[$value])) {
+ foreach ([$column, "{$column} {$toggleDirection}"] as $key) {
+ $key = implode(',', array_merge([$key], $sort));
+ if (isset($columns[$key])) {
+ $columns[$value] = $columns[$key];
+ unset($columns[$key]);
+
+ break;
+ }
+ }
+ }
+ } else {
+ $value = implode(',', array_merge([$column], $sort));
+ }
+
+ if (! isset($columns[$value])) {
+ $columns[$value] = 'Custom';
+ }
+
+ $this->addElement('select', $this->getSortParam(), [
+ 'class' => 'autosubmit',
+ 'label' => 'Sort By',
+ 'options' => $columns,
+ 'value' => $value
+ ]);
+ $select = $this->getElement($this->getSortParam());
+ (new DivDecorator())->decorate($select);
+
+ // Apply Icinga Web 2 style, for now
+ $select->prependWrapper(HtmlElement::create('div', ['class' => 'icinga-controls']));
+
+ $toggleButton = new ButtonElement($this->getSortParam(), [
+ 'class' => 'control-button spinner',
+ 'title' => t('Change sort direction'),
+ 'type' => 'submit',
+ 'value' => implode(',', array_merge(["{$column} {$toggleDirection}"], $sort))
+ ]);
+ $toggleButton->add(new Icon($toggleIcon));
+
+ $this->addHtml($toggleButton);
+
+ if ($this->getMethod() === 'POST' && $this->hasAttribute('name')) {
+ $this->addElement($this->createUidElement());
+ }
+ }
+}