'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 $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()); } } }