[Legacy] Add api to bean mapping handling to ApiBeanMapper

- Add default blank implementation for existing mappers
- Add specific implementation to FilterContent mapper
- Add specific implementation to AssignedUser mapper
This commit is contained in:
Clemente Raposo 2021-05-03 18:10:56 +01:00 committed by Dillon-Brown
parent bda25c6d2f
commit ff28a5bf8e
16 changed files with 363 additions and 91 deletions

View file

@ -25,15 +25,14 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/FieldMappers/AssignedUserMapper.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/FullNameMapper.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/DateMapper.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/DateTimeMapper.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/MultiEnumMapper.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/BooleanMapper.php';
require_once 'include/portability/ApiBeanMapper/ApiBeanModuleMappers.php';
require_once 'include/portability/ApiBeanMapper/ModuleMappers/SavedSearch/SavedSearchMappers.php';
require_once __DIR__ . '/FieldMappers/AssignedUserMapper.php';
require_once __DIR__ . '/TypeMappers/FullNameMapper.php';
require_once __DIR__ . '/TypeMappers/DateMapper.php';
require_once __DIR__ . '/TypeMappers/DateTimeMapper.php';
require_once __DIR__ . '/TypeMappers/MultiEnumMapper.php';
require_once __DIR__ . '/TypeMappers/BooleanMapper.php';
require_once __DIR__ . '/ApiBeanModuleMappers.php';
require_once __DIR__ . '/ModuleMappers/SavedSearch/SavedSearchMappers.php';

class ApiBeanMapper
{
@ -69,7 +68,7 @@ class ApiBeanMapper
* @param SugarBean $bean
* @return array
*/
public function toArray(SugarBean $bean): array
public function toApi(SugarBean $bean): array
{
$arr = [];

@ -77,7 +76,6 @@ class ApiBeanMapper
$arr['object_name'] = $bean->object_name ?? '';

foreach ($bean->field_defs as $field => $definition) {

if ($this->isSensitiveField($definition)) {
continue;
}
@ -101,6 +99,59 @@ class ApiBeanMapper
return $arr;
}

/**
* @param SugarBean $bean
* @return array
*/
public function toBean(SugarBean $bean, array $values): void
{
require_once __DIR__ . '/../../../include/SugarFields/SugarFieldHandler.php';

foreach ($bean->field_defs as $field => $properties) {
if (!isset($values[$field])) {
continue;
}

$type = $properties['type'] ?? '';

if ($type === 'relate' && isset($bean->field_defs[$field])) {
$idName = $bean->field_defs[$field]['id_name'] ?? '';

if ($idName !== $field) {
$rName = $bean->field_defs[$field]['rname'] ?? '';
$value = $values[$field][$rName] ?? '';
$values[$field] = $value;
}
}

if (!empty($properties['isMultiSelect']) || $type === 'multienum') {
$multiSelectValue = $values[$field];
if (!is_array($values[$field])) {
$multiSelectValue = [];
}
$values[$field] = encodeMultienumValue($multiSelectValue);
}

$fieldMapper = $this->getFieldMapper($bean->module_name, $field);
if (null !== $fieldMapper) {
$fieldMapper->toBean($bean, $values, $field);
}

$typeMapper = $this->getTypeMappers($bean->module_name, $type);
if (null !== $typeMapper) {
$typeMapper->toBean($bean, $values, $field, $field);
}

$bean->$field = $values[$field];
}

foreach ($bean->relationship_fields as $field => $link) {
if (!empty($values[$field])) {
$bean->$field = $values[$field];
}
}
}

/**
* @param $definition
* @return bool
@ -253,7 +304,7 @@ class ApiBeanMapper

$fieldMapper = $this->getFieldMapper($bean->module_name, $field);
if (null !== $fieldMapper) {
$fieldMapper->run($bean, $arr, $name);
$fieldMapper->toApi($bean, $arr, $name);

return;
}
@ -261,7 +312,7 @@ class ApiBeanMapper
$type = $definition['type'] ?? '';
$typeMapper = $this->getTypeMappers($bean->module_name, $type);
if (null !== $typeMapper) {
$typeMapper->run($bean, $arr, $field, $name);
$typeMapper->toApi($bean, $arr, $field, $name);

return;
}

View file

@ -25,9 +25,8 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once 'include/portability/ApiBeanMapper/FieldMappers/FieldMapperInterface.php';
require_once __DIR__. '/TypeMappers/TypeMapperInterface.php';
require_once __DIR__. '/FieldMappers/FieldMapperInterface.php';

class ApiBeanModuleMappers
{

View file

@ -25,9 +25,7 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/FieldMappers/FieldMapperInterface.php';

require_once __DIR__ .'/FieldMapperInterface.php';

class AssignedUserMapper implements FieldMapperInterface
{
@ -44,7 +42,7 @@ class AssignedUserMapper implements FieldMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$name = self::FIELD_NAME;

@ -60,4 +58,26 @@ class AssignedUserMapper implements FieldMapperInterface

$container[$name] = get_assigned_user_name($bean->assigned_user_id);
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
if (empty($container)) {
return;
}

$fieldName = self::getField();
if (!empty($alternativeName)) {
$fieldName = $alternativeName;
}

$assignedUserName = $container[$fieldName] ?? [];
if (is_string($assignedUserName)) {
$container[$alternativeName] = $assignedUserName;
}

$container[$alternativeName] = $assignedUserName['user_name'] ?? '';
}
}

View file

@ -33,7 +33,6 @@ interface FieldMapperInterface
*/
public static function getField(): string;


/**
* Map the field and add it to the container
* @param SugarBean $bean
@ -41,5 +40,14 @@ interface FieldMapperInterface
* @param string $alternativeName
* @return mixed
*/
public function run(SugarBean $bean, array &$container, string $alternativeName = ''): void;
public function toApi(SugarBean $bean, array &$container, string $alternativeName = ''): void;

/**
* Map the field to bean format and add it to the container
* @param SugarBean $bean
* @param array $container
* @param string $alternativeName
* @return mixed
*/
public function toBean(SugarBean $bean, array &$container, string $alternativeName = ''): void;
}

View file

@ -25,13 +25,26 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/FieldMappers/FieldMapperInterface.php';
require_once __DIR__ .'/../../../ApiBeanMapper/FieldMappers/FieldMapperInterface.php';
require_once __DIR__ .'/../../../ModuleNameMapper.php';

class FilterContentMapper implements FieldMapperInterface
{
public const FIELD_NAME = 'contents';

/**
* @var ModuleNameMapper
*/
protected $moduleNameMapper;

/**
* RouteConverter constructor.
*/
public function __construct()
{
$this->moduleNameMapper = new ModuleNameMapper();
}

/**
* {@inheritDoc}
*/
@ -43,7 +56,7 @@ class FilterContentMapper implements FieldMapperInterface
/**
* {@inheritDoc}
*/
public function run(SugarBean $bean, array &$container, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$name = self::FIELD_NAME;

@ -63,7 +76,63 @@ class FilterContentMapper implements FieldMapperInterface
return;
}

$container[$name] = $this->parseContent($bean->name, $bean->contents);
$contents = $this->parseContent($bean->name, $bean->contents);
$container[$name] = $contents;
$container['orderBy'] = $contents['orderBy'] ?? '';
$container['sortOrder'] = $contents['sortOrder'] ?? '';
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$contents = $container[self::getField()] ?? [];

$legacyContents = [
'searchFormTab' => 'advanced',
'query' => '',
'search_module' => '',
'saved_search_action' => '',
'displayColumns' => '',
'hideTabs' => '',
'orderBy' => '',
'sortOrder' => '',
'advanced' => ''
];

if (!empty($bean->contents)) {
$legacyContents = unserialize(base64_decode($bean->contents), ['allowed_classes' => true]);
}

if (empty($contents) || empty($contents['filters'])) {
$container[self::getField()] = $this->encode($legacyContents);

return;
}

foreach ($contents['filters'] as $filter) {
$key = $filter['field'];
$legacyContents[$key . '_advanced'] = '';

if (!empty($filter['values']) && is_array($filter['values']) && count($filter['values']) === 1) {
$legacyContents[$key . '_advanced'] = array_pop($filter['values']);
}

if (!empty($filter['values']) && is_array($filter['values'])) {
$legacyContents[$key . '_advanced'] = $filter['values'];
}
}

$legacyContents['orderBy'] = strtoupper($contents['orderBy'] ?? '');
$legacyContents['sortOrder'] = strtoupper($contents['sortOrder'] ?? '');

$module = $contents['searchModule'] ?? ($container['search_module'] ?? '');
if (!empty($module)) {
$legacyContents['search_module'] = $this->moduleNameMapper->toLegacy($module);
}

$container[self::getField()] = $this->encode($legacyContents);
}

/**
@ -75,6 +144,19 @@ class FilterContentMapper implements FieldMapperInterface
public function parseContent(string $filterName, string $serializedContents): array
{
$contents = unserialize(base64_decode($serializedContents), ['allowed_classes' => true]);

$newContents = [
'name' => $filterName,
'filters' => [],
'searchModule' => '',
'orderBy' => strtolower($contents['orderBy'] ?? ''),
'sortOrder' => strtolower($contents['sortOrder'] ?? '')
];

if (!empty($contents['search_module'])) {
$newContents['searchModule'] = $this->moduleNameMapper->toFrontEnd($contents['search_module']);
}

unset(
$contents['searchFormTab'],
$contents['query'],
@ -87,10 +169,7 @@ class FilterContentMapper implements FieldMapperInterface
$contents['advanced']
);

$newContents = [
'name' => $filterName,
'filters' => []
];

foreach ($contents as $key => $item) {
if (empty($contents[$key])) {
continue;
@ -112,4 +191,18 @@ class FilterContentMapper implements FieldMapperInterface

return $newContents;
}

/**
* Encode criteria
* @param array $content
* @return string
*/
public function encode(array $content): string
{
if (empty($content)) {
return '';
}

return base64_encode(serialize($content));
}
}

View file

@ -25,9 +25,9 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/ModuleMappers/SavedSearch/FilterContentMapper.php';
require_once 'include/portability/ApiBeanMapper/ApiBeanModuleMappers.php';
require_once __DIR__ . '/FilterContentMapper.php';
require_once __DIR__ . '/SearchModuleMapper.php';
require_once __DIR__ . '/../../ApiBeanModuleMappers.php';

class SavedSearchMappers extends ApiBeanModuleMappers
{
@ -39,6 +39,7 @@ class SavedSearchMappers extends ApiBeanModuleMappers
public function __construct()
{
$this->fieldMappers[FilterContentMapper::getField()] = new FilterContentMapper();
$this->fieldMappers[SearchModuleMapper::getField()] = new SearchModuleMapper();
}

/**

View file

@ -0,0 +1,93 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/

require_once __DIR__ . '/../../../ApiBeanMapper/FieldMappers/FieldMapperInterface.php';
require_once __DIR__ . '/../../../ModuleNameMapper.php';

class SearchModuleMapper implements FieldMapperInterface
{
public const FIELD_NAME = 'search_module';

/**
* @var ModuleNameMapper
*/
protected $moduleNameMapper;

/**
* RouteConverter constructor.
*/
public function __construct()
{
$this->moduleNameMapper = new ModuleNameMapper();
}


/**
* @inheritDoc
*/
public static function getField(): string
{
return self::FIELD_NAME;
}

/**
* @inheritDoc
*/
public function toApi(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$name = self::FIELD_NAME;

if (!empty($alternativeName)) {
$name = $alternativeName;
}

if (empty($bean->search_module)) {
$container[$name] = '';

return;
}

$container[$name] = $this->moduleNameMapper->toFrontEnd($bean->search_module);
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$name = self::getField();
if (!empty($alternativeName)) {
$name = $alternativeName;
}

if (empty($container[$name])) {
return;
}

$container[self::getField()] = $this->moduleNameMapper->toLegacy($container[$name]);
}
}

View file

@ -25,8 +25,7 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once __DIR__ .'/TypeMapperInterface.php';

class BooleanMapper implements TypeMapperInterface
{
@ -41,7 +40,7 @@ class BooleanMapper implements TypeMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
$newName = $name;

@ -65,6 +64,13 @@ class BooleanMapper implements TypeMapperInterface
$container[$newName] = $value;
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
}

/**
* @param $value
* @return bool

View file

@ -25,9 +25,8 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/Services/DateTime/DateFormatService.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once __DIR__ .'/../../Services/DateTime/DateFormatService.php';
require_once __DIR__ .'/TypeMapperInterface.php';

class DateMapper implements TypeMapperInterface
{
@ -53,7 +52,7 @@ class DateMapper implements TypeMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
$newName = $name;

@ -77,4 +76,11 @@ class DateMapper implements TypeMapperInterface

$container[$newName] = $dbDate;
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
}
}

View file

@ -25,9 +25,8 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/Services/DateTime/DateFormatService.php';
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once __DIR__ .'/../../Services/DateTime/DateFormatService.php';
require_once __DIR__ .'/TypeMapperInterface.php';

class DateTimeMapper implements TypeMapperInterface
{
@ -53,7 +52,7 @@ class DateTimeMapper implements TypeMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
$newName = $name;

@ -77,4 +76,11 @@ class DateTimeMapper implements TypeMapperInterface

$container[$newName] = $dbDate;
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
}
}

View file

@ -25,8 +25,7 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once __DIR__ .'/TypeMapperInterface.php';

class FullNameMapper implements TypeMapperInterface
{
@ -41,7 +40,7 @@ class FullNameMapper implements TypeMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
$newName = $name;

@ -79,4 +78,11 @@ class FullNameMapper implements TypeMapperInterface

$container[$newName] = implode(' ', $fullNameFormat);
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
}
}

View file

@ -25,8 +25,7 @@
* the words "Supercharged by SuiteCRM".
*/

/* @noinspection PhpIncludeInspection */
require_once 'include/portability/ApiBeanMapper/TypeMappers/TypeMapperInterface.php';
require_once __DIR__ .'/TypeMapperInterface.php';

class MultiEnumMapper implements TypeMapperInterface
{
@ -41,7 +40,7 @@ class MultiEnumMapper implements TypeMapperInterface
/**
* @inheritDoc
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
$newName = $name;

@ -86,4 +85,11 @@ class MultiEnumMapper implements TypeMapperInterface

return explode('^,^', $string);
}

/**
* @inheritDoc
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void
{
}
}

View file

@ -42,6 +42,15 @@ interface TypeMapperInterface
* @param string $alternativeName
* @return mixed
*/
public function run(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void;
public function toApi(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void;

/**
* Map the field to bean format and add it to the container
* @param SugarBean $bean
* @param array $container
* @param string $name
* @param string $alternativeName
* @return mixed
*/
public function toBean(SugarBean $bean, array &$container, string $name, string $alternativeName = ''): void;
}

View file

@ -145,7 +145,7 @@ class ListViewDataPort extends ListViewData
$this->enforceAssignedUserId($temp);
$this->addTagInfo($id_field, $idIndex, $row, $dataIndex, $temp, $pageData);

$data[$dataIndex] = $this->apiBeanMapper->toArray($temp);
$data[$dataIndex] = $this->apiBeanMapper->toApi($temp);

$this->addACLInfo($temp, $pageData, $dataIndex);
}

View file

@ -88,7 +88,7 @@ class SubpanelDataPort
$mappedBeans = [];

foreach ($beanList as $beanData) {
$mappedBeans[] = $this->apiBeanMapper->toArray($beanData);
$mappedBeans[] = $this->apiBeanMapper->toApi($beanData);
}

$row_count = $response['row_count'];