Skip to content

Commit

Permalink
Make Grid Filters extendable
Browse files Browse the repository at this point in the history
  • Loading branch information
Vinai committed Dec 4, 2020
1 parent c87466b commit 7fb8894
Show file tree
Hide file tree
Showing 22 changed files with 537 additions and 255 deletions.
20 changes: 20 additions & 0 deletions Api/GridFilterTypeInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Api;

use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilter;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\View\Element\Template;

interface GridFilterTypeInterface
{
public function getRenderer(ColumnDefinitionInterface $columnDefinition): Template;

public function apply(
SearchCriteriaBuilder $searchCriteriaBuilder,
GridFilterInterface $gridFilter,
$filterValue
): void;
}
12 changes: 6 additions & 6 deletions Model/Config/GridXmlToArrayConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@ private function convertNavigationConfig(\DOMElement $root): array
* <defaultSortDirection>asc</defaultSortDirection>
* </sorting>
* <filters>
* <filter column="sku" input="text" enabled="true" template="Foo_Bar::filter.phtml"/>
* <filter column="color" input="select">
* <filter column="sku" enabled="true" template="Foo_Bar::filter.phtml"/>
* <filter column="color">
* <option label="reddish">
* <value>16</value>
* <value>17</value>
Expand Down Expand Up @@ -422,8 +422,8 @@ private function getFiltersConfig(\DOMElement $navigationElement): ?array
{
/*
* <filters>
* <filter column="sku" input="text" enabled="true" template="Foo_Bar::filter.phtml"/>
* <filter column="color" input="select">
* <filter column="sku" enabled="true" template="Foo_Bar::filter.phtml"/>
* <filter column="color">
* <option label="reddish">
* <value>16</value>
* <value>17</value>
Expand All @@ -445,17 +445,17 @@ private function getFilterConfig(\DOMElement $filterElement): ?array
{
return merge(
['key' => $this->getAttributeConfig($filterElement, 'column')['column'] ?? null],
$this->getAttributeConfig($filterElement, 'input'),
$this->getAttributeConfig($filterElement, 'enabled'),
$this->getAttributeConfig($filterElement, 'template'),
$this->getAttributeConfig($filterElement, 'filterType'),
$this->getFilterOptionsConfig($filterElement)
);
}

private function getFilterOptionsConfig(\DOMElement $filterElement): array
{
/*
* <filter column="color" input="select">
* <filter column="color">
* <option label="reddish">
* <value>16</value>
* <value>17</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Hyva\Admin\Api\DataTypeInterface;
use Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface;

class DateTimeDataTypeConverter implements DataTypeInterface
class DateTimeDataType implements DataTypeInterface
{
const TYPE_DATETIME = 'datetime';

Expand Down
36 changes: 36 additions & 0 deletions Model/DataType/IntDataType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\DataType;

use Hyva\Admin\Api\DataTypeInterface;

class IntDataType implements DataTypeInterface
{
const TYPE_INT = 'int';

public function valueToTypeCode($value): ?string
{
return is_int($value) || (is_string($value) && preg_match('/^\d+$/', $value))
? self::TYPE_INT
: null;
}

public function typeToTypeCode(string $type): ?string
{
return $type === self::TYPE_INT
? self::TYPE_INT
: null;
}

public function toString($value): ?string
{
return $this->valueToTypeCode($value)
? (string) $value
: null;
}

public function toHtmlRecursive($value, $maxRecursionDepth = self::UNLIMITED_RECURSION): ?string
{
return $this->toString($value);
}
}
50 changes: 50 additions & 0 deletions Model/GridFilter/BooleanFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\Model\DataType\BooleanDataType;
use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutInterface;

class BooleanFilter implements ColumnDefinitionMatchingFilterInterface
{
private LayoutInterface $layout;

public function __construct(LayoutInterface $layout)
{
$this->layout = $layout;
}

public function isMatchingFilter(GridFilterInterface $filter): bool
{
return $filter->getColumnDefinition()->getType() === BooleanDataType::TYPE_BOOL;
}

public function getRenderer(ColumnDefinitionInterface $columnDefinition): Template
{
/** @var Template $templateBlock */
$templateBlock = $this->layout->createBlock(Template::class);
$templateBlock->setTemplate('Hyva_Admin::filter/bool.phtml');

return $templateBlock;
}

public function apply(
SearchCriteriaBuilder $searchCriteriaBuilder,
GridFilterInterface $gridFilter,
$filterValue
): void {
if ($this->isValue($filterValue)) {
$key = $gridFilter->getColumnDefinition()->getKey();
$searchCriteriaBuilder->addFilter($key, (int) $filterValue, 'eq');
}
}

private function isValue($value): bool
{
return isset($value) && '' !== $value;
}
}
12 changes: 12 additions & 0 deletions Model/GridFilter/ColumnDefinitionMatchingFilterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\Api\GridFilterTypeInterface;
use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;

interface ColumnDefinitionMatchingFilterInterface extends GridFilterTypeInterface
{
public function isMatchingFilter(GridFilterInterface $filter): bool;
}
53 changes: 53 additions & 0 deletions Model/GridFilter/DateRangeFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\Model\DataType\DateTimeDataType;
use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutInterface;

class DateRangeFilter implements ColumnDefinitionMatchingFilterInterface
{
private LayoutInterface $layout;

public function __construct(LayoutInterface $layout)
{
$this->layout = $layout;
}

public function isMatchingFilter(GridFilterInterface $filter): bool
{
return $filter->getColumnDefinition()->getType() === DateTimeDataType::TYPE_DATETIME;
}

public function getRenderer(ColumnDefinitionInterface $columnDefinition): Template
{
/** @var Template $templateBlock */
$templateBlock = $this->layout->createBlock(Template::class);
$templateBlock->setTemplate('Hyva_Admin::filter/date-range.phtml');

return $templateBlock;
}

public function apply(
SearchCriteriaBuilder $searchCriteriaBuilder,
GridFilterInterface $gridFilter,
$filterValue
): void {
$key = $gridFilter->getColumnDefinition()->getKey();
if ($this->isValue($from = $filterValue['from'] ?? '')) {
$searchCriteriaBuilder->addFilter($key, $from, 'from');
}
if ($this->isValue($to = $filterValue['to'] ?? '')) {
$searchCriteriaBuilder->addFilter($key, $to, 'to');
}
}

private function isValue($value): bool
{
return isset($value) && '' !== $value;
}
}
46 changes: 46 additions & 0 deletions Model/GridFilter/GridFilterTypeLocator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\Api\GridFilterTypeInterface;
use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\ObjectManagerInterface;

class GridFilterTypeLocator
{
private ObjectManagerInterface $objectManager;

private array $columnTypeMatchingFilterTypeMap;

public function __construct(ObjectManagerInterface $objectManager, array $columnTypeMatchingFilterMap)
{
$this->objectManager = $objectManager;
$this->columnTypeMatchingFilterTypeMap = $columnTypeMatchingFilterMap;
}

public function findFilterForColumn(
GridFilterInterface $gridFilter,
ColumnDefinitionInterface $columnDefinition
): GridFilterTypeInterface {
foreach ($this->columnTypeMatchingFilterTypeMap as $type) {
$filterType = $this->get($type);
if ($this->canMatchColumn($filterType) && $filterType->isMatchingFilter($gridFilter, $columnDefinition)) {
return $filterType;
}
}

$msg = sprintf('Unable to determine filter type for column "%s"', $columnDefinition->getKey());
throw new \OutOfBoundsException($msg);
}

private function canMatchColumn(GridFilterTypeInterface $filterType): bool
{
return $filterType instanceof ColumnDefinitionMatchingFilterInterface;
}

public function get(string $filterType): GridFilterTypeInterface
{
return $this->objectManager->get($filterType);
}
}
55 changes: 55 additions & 0 deletions Model/GridFilter/SelectFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\FilterOptionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutInterface;

use function array_filter as filter;
use function array_values as values;

class SelectFilter implements ColumnDefinitionMatchingFilterInterface
{
private LayoutInterface $layout;

public function __construct(LayoutInterface $layout)
{
$this->layout = $layout;
}

public function isMatchingFilter(GridFilterInterface $filter): bool
{
return (bool) $filter->getOptions();
}

public function getRenderer(ColumnDefinitionInterface $columnDefinition): Template
{
/** @var Template $templateBlock */
$templateBlock = $this->layout->createBlock(Template::class);
$templateBlock->setTemplate('Hyva_Admin::filter/select.phtml');

return $templateBlock;
}

public function apply(
SearchCriteriaBuilder $searchCriteriaBuilder,
GridFilterInterface $gridFilter,
$filterValue
): void {
if ($option = $this->getSelectedOption($gridFilter->getOptions(), $filterValue)) {
$key = $gridFilter->getColumnDefinition()->getKey();
$searchCriteriaBuilder->addFilter($key, $option->getValues(), 'finset');
}
}

private function getSelectedOption(array $options, $value): ?FilterOptionInterface
{
return values(filter($options, function (FilterOptionInterface $option) use ($value): bool {
return $option->getValueId() === $value;
}))[0] ?? null;
}
}
50 changes: 50 additions & 0 deletions Model/GridFilter/TextFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types=1);

namespace Hyva\Admin\Model\GridFilter;

use Hyva\Admin\ViewModel\HyvaGrid\ColumnDefinitionInterface;
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutInterface;

class TextFilter implements ColumnDefinitionMatchingFilterInterface
{
private LayoutInterface $layout;

public function __construct(LayoutInterface $layout)
{
$this->layout = $layout;
}

public function isMatchingFilter(GridFilterInterface $filter): bool
{
// default filter type
return true;
}

public function getRenderer(ColumnDefinitionInterface $columnDefinition): Template
{
/** @var Template $templateBlock */
$templateBlock = $this->layout->createBlock(Template::class);
$templateBlock->setTemplate('Hyva_Admin::filter/text.phtml');

return $templateBlock;
}

public function apply(
SearchCriteriaBuilder $searchCriteriaBuilder,
GridFilterInterface $gridFilter,
$filterValue
): void {
if ($this->isValue($filterValue)) {
$key = $gridFilter->getColumnDefinition()->getKey();
$searchCriteriaBuilder->addFilter($key, '%' . $filterValue . '%', 'like');
}
}

private function isValue($value): bool
{
return isset($value) && '' !== $value;
}
}
Loading

0 comments on commit 7fb8894

Please sign in to comment.