Add RecordList FilterMappers

- Refactor LegacyFilterMapper to allow adding mappers per type
- Add date and date time mappers to convert to proper format
-- Api should receive fields in internal format
-- Legacy search expects user format
-- Convert to user format when calling legacy search

- Add multienum to correctly process criteria
-- Api search criteria receive an array of values
-- For other fields legacy expects just one value not an array
-- For multienum legacy expects an array of values
-- Add mapper to send array of values to legacy for multienums
This commit is contained in:
Clemente Raposo 2021-01-02 20:28:52 +00:00 committed by Dillon-Brown
parent 805c751a99
commit af186a7013
13 changed files with 345 additions and 13 deletions

View file

@ -58,6 +58,8 @@ services:
tags: [ 'system.config.mapper' ] tags: [ 'system.config.mapper' ]
App\Legacy\Data\PresetListDataHandlerInterface: App\Legacy\Data\PresetListDataHandlerInterface:
tags: [ 'app.data.preset.handler' ] tags: [ 'app.data.preset.handler' ]
App\Legacy\Data\FilterMapper\FilterMapperInterface:
tags: [ 'app.data.filter.mapper' ]
App\Service\StatisticsProviderInterface: App\Service\StatisticsProviderInterface:
tags: [ 'app.data.statistics.handler' ] tags: [ 'app.data.statistics.handler' ]
@ -149,3 +151,9 @@ services:
# and use the value of the 'getKey' method to index the services # and use the value of the 'getKey' method to index the services
arguments: arguments:
- !tagged { tag: 'app.data.statistics.handler', default_index_method: 'getKey' } - !tagged { tag: 'app.data.statistics.handler', default_index_method: 'getKey' }
App\Legacy\Data\FilterMapper\FilterMappers:
# inject all services tagged with app.data.filter.mapper as first argument
# and use the value of the 'getType' method to index the services
arguments:
- !tagged { tag: 'app.data.filter.mapper', default_index_method: 'getType' }

View file

@ -2,7 +2,7 @@
namespace App\Legacy\Data; namespace App\Legacy\Data;
use App\Service\LegacyFilterMapper; use App\Legacy\Data\FilterMapper\LegacyFilterMapper;
use BeanFactory; use BeanFactory;
use InvalidArgumentException; use InvalidArgumentException;
use ListViewDataPort; use ListViewDataPort;

View file

@ -0,0 +1,20 @@
<?php
namespace App\Legacy\Data\FilterMapper;
interface FilterMapperInterface
{
/**
* Get the field type it applies to
* @return string
*/
public function getType(): string;
/**
* Map value
* @param string $mappedValue
* @param array $criteriaItem
* @return mixed|string|string[]
*/
public function mapValue(string $mappedValue, array $criteriaItem);
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Legacy\Data\FilterMapper;
use ApiPlatform\Core\Exception\ItemNotFoundException;
class FilterMappers
{
protected const MSG_HANDLER_NOT_FOUND = 'Filter mapper is not defined';
/**
* @var FilterMapperInterface[]
*/
protected $registry = [];
/**
* FilterMappers constructor.
* @param iterable $handlers
*/
public function __construct(iterable $handlers)
{
/**
* @var FilterMapperInterface[]
*/
$handlers = iterator_to_array($handlers);
foreach ($handlers as $handler) {
$type = $handler->getType();
$this->registry[$type] = $handler;
}
}
/**
* Get the mapper for field type
* @param string $type
* @return FilterMapperInterface
* @throws ItemNotFoundException
*/
public function get(string $type): FilterMapperInterface
{
if (empty($this->registry[$type])) {
throw new ItemNotFoundException(self::MSG_HANDLER_NOT_FOUND);
}
return $this->registry[$type];
}
/**
* Has mapper for the given type
* @param string $type
* @return bool
*/
public function hasMapper(string $type): bool
{
return !(empty($this->registry[$type]));
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
namespace App\Service; namespace App\Legacy\Data\FilterMapper;
class LegacyFilterMapper class LegacyFilterMapper
{ {
@ -8,14 +8,20 @@ class LegacyFilterMapper
* @var array * @var array
*/ */
private $filterOperatorMap; private $filterOperatorMap;
/**
* @var FilterMappers
*/
private $mappers;
/** /**
* LegacyFilterMapper constructor. * LegacyFilterMapper constructor.
* @param array $filterOperatorMap * @param array $filterOperatorMap
* @param FilterMappers $mappers
*/ */
public function __construct(array $filterOperatorMap) public function __construct(array $filterOperatorMap, FilterMappers $mappers)
{ {
$this->filterOperatorMap = $filterOperatorMap; $this->filterOperatorMap = $filterOperatorMap;
$this->mappers = $mappers;
} }
/** /**
@ -74,15 +80,16 @@ class LegacyFilterMapper
*/ */
protected function mapFilterValue(string $mappedValue, array $item) protected function mapFilterValue(string $mappedValue, array $item)
{ {
$fieldType = $item['fieldType'] ?? '';
if ($mappedValue === 'values') { if ($mappedValue === 'values') {
if (count($item['values']) === 1) { if ($this->mappers->hasMapper($fieldType)) {
$legacyValue = $item['values'][0]; return $this->mappers->get($fieldType)->mapValue($mappedValue, $item);
} else {
$legacyValue = $item['values'];
} }
return $legacyValue; return $this->mappers->get('default')->mapValue($mappedValue, $item);
} }
$operator = $item['operator'] ?? ''; $operator = $item['operator'] ?? '';

View file

@ -0,0 +1,60 @@
<?php
namespace App\Legacy\Data\FilterMapper\Mappers;
use App\Legacy\Data\FilterMapper\FilterMapperInterface;
use App\Legacy\DateTimeHandler;
class DateFilterMapper implements FilterMapperInterface
{
/**
* @var DateTimeHandler
*/
private $dateTimeHandler;
/**
* DateFilterMapper constructor.
* @param DateTimeHandler $dateTimeHandler
*/
public function __construct(DateTimeHandler $dateTimeHandler)
{
$this->dateTimeHandler = $dateTimeHandler;
}
/**
* @inheritDoc
*/
public function getType(): string
{
return 'date';
}
/**
* @inheritDoc
*/
public function mapValue(string $mappedValue, array $criteriaItem)
{
/** @var array */
$values = $criteriaItem['values'] ?? [];
if (empty($values)) {
return [];
}
$mapped = [];
foreach ($values as $value) {
if (empty($value)) {
continue;
}
$mapped[] = $this->dateTimeHandler->toUserDate($value);
}
$legacyValue = $mapped;
if (count($mapped) === 1) {
$legacyValue = $mapped[0];
}
return $legacyValue;
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace App\Legacy\Data\FilterMapper\Mappers;
use App\Legacy\Data\FilterMapper\FilterMapperInterface;
use App\Legacy\DateTimeHandler;
class DateTimeFilterMapper implements FilterMapperInterface
{
/**
* @var DateTimeHandler
*/
private $dateTimeHandler;
/**
* DateFilterMapper constructor.
* @param DateTimeHandler $dateTimeHandler
*/
public function __construct(DateTimeHandler $dateTimeHandler)
{
$this->dateTimeHandler = $dateTimeHandler;
}
/**
* @inheritDoc
*/
public function getType(): string
{
return 'datetime';
}
/**
* @inheritDoc
*/
public function mapValue(string $mappedValue, array $criteriaItem)
{
/** @var array */
$values = $criteriaItem['values'] ?? [];
if (empty($values)) {
return [];
}
$mapped = [];
foreach ($values as $value) {
if (empty($value)) {
continue;
}
$mapped[] = $this->dateTimeHandler->toUserDateTime($value);
}
$legacyValue = $mapped;
if (count($mapped) === 1) {
$legacyValue = $mapped[0];
}
return $legacyValue;
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Legacy\Data\FilterMapper\Mappers;
use App\Legacy\Data\FilterMapper\FilterMapperInterface;
class DefaultFilterMapper implements FilterMapperInterface
{
/**
* @inheritDoc
*/
public function getType(): string
{
return 'default';
}
/**
* @inheritDoc
*/
public function mapValue(string $mappedValue, array $criteriaItem)
{
/** @var array */
$values = $criteriaItem['values'] ?? [];
if (empty($values)) {
return [];
}
$legacyValue = $values;
if (count($values) === 1) {
$legacyValue = $values[0];
}
return $legacyValue;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Legacy\Data\FilterMapper\Mappers;
use App\Legacy\Data\FilterMapper\FilterMapperInterface;
class MultiEnumFilterMapper implements FilterMapperInterface
{
/**
* @inheritDoc
*/
public function getType(): string
{
return 'multienum';
}
/**
* @inheritDoc
*/
public function mapValue(string $mappedValue, array $criteriaItem)
{
/** @var array */
$values = $criteriaItem['values'] ?? [];
if (empty($values)) {
return [];
}
return $criteriaItem['values'];
}
}

View file

@ -2,6 +2,8 @@
namespace App\Legacy; namespace App\Legacy;
use DateFormatService;
class DateTimeHandler extends LegacyHandler class DateTimeHandler extends LegacyHandler
{ {
public const HANDLER_KEY = 'date-time'; public const HANDLER_KEY = 'date-time';
@ -10,6 +12,10 @@ class DateTimeHandler extends LegacyHandler
*/ */
private $datetimeFormatMap; private $datetimeFormatMap;
/**
* @var DateFormatService
*/
private $formatter;
/** /**
* SystemConfigHandler constructor. * SystemConfigHandler constructor.
@ -49,4 +55,40 @@ class DateTimeHandler extends LegacyHandler
{ {
return strtr($format, $this->datetimeFormatMap); return strtr($format, $this->datetimeFormatMap);
} }
/**
* To user date format
* @param string $dateString
* @return string
*/
public function toUserDate(string $dateString): string
{
return $this->getFormatter()->toUserDate($dateString);
}
/**
* To user date format
* @param string $dateString
* @return string
*/
public function toUserDateTime(string $dateString): string
{
return $this->getFormatter()->toUserDateTime($dateString);
}
/**
* @return DateFormatService
*/
protected function getFormatter(): DateFormatService
{
if ($this->formatter !== null) {
return $this->formatter;
}
/* @noinspection PhpIncludeInspection */
require_once 'include/portability/Services/DateTime/DateFormatService.php';
$this->formatter = new DateFormatService();
return $this->formatter;
}
} }

View file

@ -4,7 +4,7 @@ namespace App\Service\BulkActions;
use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Exception\InvalidArgumentException;
use App\Entity\Process; use App\Entity\Process;
use App\Service\LegacyFilterMapper; use App\Legacy\Data\FilterMapper\LegacyFilterMapper;
use App\Service\ModuleNameMapperInterface; use App\Service\ModuleNameMapperInterface;
use App\Service\ProcessHandlerInterface; use App\Service\ProcessHandlerInterface;

View file

@ -2,16 +2,20 @@
namespace App\Tests\unit\core\legacy\Statistics; namespace App\Tests\unit\core\legacy\Statistics;
use App\Legacy\Data\FilterMapper\FilterMappers;
use App\Legacy\Data\FilterMapper\LegacyFilterMapper;
use App\Legacy\Data\RecordMapper; use App\Legacy\Data\RecordMapper;
use App\Legacy\ModuleNameMapperHandler; use App\Legacy\ModuleNameMapperHandler;
use App\Service\LegacyFilterMapper;
use App\Tests\_mock\Mock\core\legacy\Data\ListDataQueryHandlerMock; use App\Tests\_mock\Mock\core\legacy\Data\ListDataQueryHandlerMock;
use App\Tests\_mock\Mock\core\legacy\Statistics\Series\LeadsByStatusCountMock; use App\Tests\_mock\Mock\core\legacy\Statistics\Series\LeadsByStatusCountMock;
use App\Tests\UnitTester; use App\Tests\UnitTester;
use BeanFactory; use BeanFactory;
use Codeception\Test\Unit; use Codeception\Test\Unit;
use EmptyIterator;
use Exception; use Exception;
;
/** /**
* Class LeadByStatusCountTest * Class LeadByStatusCountTest
* @package App\Tests * @package App\Tests
@ -124,7 +128,9 @@ class LeadByStatusCountTest extends Unit
$legacyScope $legacyScope
); );
$legacyFilterMapper = new LegacyFilterMapper([]); $filterMappers = new FilterMappers(new EmptyIterator());
$legacyFilterMapper = new LegacyFilterMapper([], $filterMappers);
$recordMapper = new RecordMapper($moduleNameMapper); $recordMapper = new RecordMapper($moduleNameMapper);
$queryHandler = new ListDataQueryHandlerMock($legacyFilterMapper, $recordMapper); $queryHandler = new ListDataQueryHandlerMock($legacyFilterMapper, $recordMapper);

View file

@ -2,14 +2,16 @@
namespace App\Tests\unit\core\legacy\Statistics; namespace App\Tests\unit\core\legacy\Statistics;
use App\Legacy\Data\FilterMapper\FilterMappers;
use App\Legacy\Data\FilterMapper\LegacyFilterMapper;
use App\Legacy\Data\RecordMapper; use App\Legacy\Data\RecordMapper;
use App\Legacy\ModuleNameMapperHandler; use App\Legacy\ModuleNameMapperHandler;
use App\Service\LegacyFilterMapper;
use App\Tests\_mock\Mock\core\legacy\Data\ListDataQueryHandlerMock; use App\Tests\_mock\Mock\core\legacy\Data\ListDataQueryHandlerMock;
use App\Tests\_mock\Mock\core\legacy\Statistics\Series\OpportunitiesBySalesStagePipelineMock; use App\Tests\_mock\Mock\core\legacy\Statistics\Series\OpportunitiesBySalesStagePipelineMock;
use App\Tests\UnitTester; use App\Tests\UnitTester;
use BeanFactory; use BeanFactory;
use Codeception\Test\Unit; use Codeception\Test\Unit;
use EmptyIterator;
use Exception; use Exception;
/** /**
@ -48,7 +50,8 @@ class OpportunitiesBySalesStagePipelineTest extends Unit
$legacyScope $legacyScope
); );
$legacyFilterMapper = new LegacyFilterMapper([]); $filterMappers = new FilterMappers(new EmptyIterator());
$legacyFilterMapper = new LegacyFilterMapper([], $filterMappers);
$recordMapper = new RecordMapper($moduleNameMapper); $recordMapper = new RecordMapper($moduleNameMapper);
$queryHandler = new ListDataQueryHandlerMock($legacyFilterMapper, $recordMapper); $queryHandler = new ListDataQueryHandlerMock($legacyFilterMapper, $recordMapper);