0
0
mirror of https://github.com/salesagility/SuiteCRM.git synced 2024-11-22 07:52:36 +00:00
salesagility_SuiteCRM/lib/API/v8/Controller/ModuleController.php
2023-07-18 15:53:08 +01:00

1611 lines
64 KiB
PHP

<?php
/**
*
* SugarCRM Community Edition is a customer relationship management program developed by
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 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 SUGARCRM, SUGARCRM 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 or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* 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 "Powered by
* SugarCRM" logo and "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 "Powered by SugarCRM" and "Supercharged by SuiteCRM".
*/
namespace SuiteCRM\API\v8\Controller;
use BeanFactory;
use DateTime;
use Favorites;
use GroupedTabStructure;
use Link2;
use MBConstants;
use ParserFactory;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use SugarBean;
use SugarView;
use SuiteCRM\API\JsonApi\v1\Enumerator\RelationshipType;
use SuiteCRM\API\JsonApi\v1\Enumerator\SugarBeanRelationshipType;
use SuiteCRM\API\JsonApi\v1\Links;
use SuiteCRM\API\JsonApi\v1\Resource\Relationship;
use SuiteCRM\API\JsonApi\v1\Resource\Resource;
use SuiteCRM\API\JsonApi\v1\Resource\ResourceIdentifier;
use SuiteCRM\API\JsonApi\v1\Resource\SuiteBeanResource;
use SuiteCRM\API\v8\Exception\ApiException;
use SuiteCRM\API\v8\Exception\BadRequestException;
use SuiteCRM\API\v8\Exception\ConflictException;
use SuiteCRM\API\v8\Exception\EmptyBodyException;
use SuiteCRM\API\v8\Exception\ForbiddenException;
use SuiteCRM\API\v8\Exception\IdAlreadyExistsException;
use SuiteCRM\API\v8\Exception\InvalidJsonApiResponseException;
use SuiteCRM\API\v8\Exception\ModuleNotFoundException;
use SuiteCRM\API\v8\Exception\NotAcceptableException;
use SuiteCRM\API\v8\Exception\NotFoundException;
use SuiteCRM\API\v8\Exception\UnsupportedMediaTypeException;
use SuiteCRM\API\v8\Library\ModulesLib;
use SuiteCRM\Enumerator\ExceptionCode;
use SuiteCRM\Exception\Exception;
use SuiteCRM\Exception\InvalidArgumentException;
use SuiteCRM\Utility\ApplicationLanguage;
use SuiteCRM\Utility\SuiteValidator;
use Tracker;
/**
* Class ModuleController
* @package SuiteCRM\API\v8\Controller
*/
class ModuleController extends ApiController
{
public const MISSING_ID = '[ModuleController] ["id" does not exist]';
public const SOURCE_TYPE = '/data/attributes/type';
/**
* GET /api/v8/modules/meta/list
* @param Request $req
* @param Response $res
* @return Response
* @throws RuntimeException
*/
public function getModulesMetaList(Request $req, Response $res)
{
try {
$config = $this->containers->get('ConfigurationManager');
require_once $this->paths->getProjectPath().'/include/modules.php';
global $moduleList;
$payload = array(
'meta' => array('modules' => array('list' => array()))
);
foreach ($moduleList as $module) {
$payload['meta']['modules']['list'][$module]['links'] =
$config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/'.$module;
}
$this->negotiatedJsonApiContent($req, $res);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/meta/menu/modules
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModulesMetaMenuModules(Request $req, Response $res, array $args)
{
try {
global $current_user;
global $sugar_config;
global $app_strings;
$config = $this->containers->get('ConfigurationManager');
$this->negotiatedJsonApiContent($req, $res);
$payload = array();
require_once $this->paths->getProjectPath().'/include/GroupedTabs/GroupedTabStructure.php';
$groupedTabsClass = new GroupedTabStructure();
$modules = query_module_access_list($current_user);
$sugarView = new SugarView();
foreach ($modules as $moduleKey => $module) {
$moduleName = $module;
$menu = $sugarView->getMenu($moduleName);
$self = $config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/' . $moduleName . '/';
$actions = array();
foreach ($menu as $item) {
$url = parse_url((string) $item[0]);
parse_str($url['query'], $orig);
$actions[] = array(
'href' => $self . $item[2],
'label' => $item[1],
'action' => $item[2],
'module' => $item[3],
'type' => $item[3],
'query' => $orig,
);
}
$modules[$moduleKey] = array(
'type' => $moduleName,
'href' => $config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/' . $moduleName . '/',
'menu' => $actions
);
}
$payload['meta']['menu']['modules'] = array(
'all' => $modules,
);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/meta/menu/filters
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModulesMetaMenuFilters(Request $req, Response $res, array $args)
{
try {
global $current_user;
global $sugar_config;
global $app_strings;
$config = $this->containers->get('ConfigurationManager');
$this->negotiatedJsonApiContent($req, $res);
$payload = array();
require_once $this->paths->getProjectPath().'/include/GroupedTabs/GroupedTabStructure.php';
$groupedTabsClass = new GroupedTabStructure();
$modules = query_module_access_list($current_user);
//handle with submoremodules
$max_tabs = $current_user->getPreference('max_tabs');
// If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size
if (!isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10) {
// We have a default value. Use it
if (isset($sugar_config['default_max_tabs'])) {
$max_tabs = $sugar_config['default_max_tabs'];
} else {
$max_tabs = 8;
}
}
$subMoreModules = false;
$groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules));
// We need to put this here, so the "All" group is valid for the user's preference.
$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
// Setup the default group tab.
$allGroup = $app_strings['LBL_TABGROUP_ALL'];
// Add url to modules
foreach ($modules as $moduleKey => $module) {
$moduleName = $module;
$modules[$moduleKey] = array(
'type' => $moduleName,
'href' => $config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/' . $moduleName . '/',
'label' => $moduleKey
);
}
$payload['meta']['menu']['filters'] = array(
'all' => $modules,
'tabs' => $groupTabs
);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/viewed
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModulesMetaViewed(Request $req, Response $res, array $args)
{
try {
$this->negotiatedJsonApiContent($req, $res);
global $current_user;
$dateTimeConverter = $this->containers->get('DateTimeConverter');
/** @var Tracker $tracker */
$tracker = BeanFactory::newBean('Trackers');
$payload = array(
'data' => array(),
'included' => array(),
);
$recentlyViewedSugarBeans = $tracker->get_recently_viewed($current_user->id);
foreach ($recentlyViewedSugarBeans as $viewed) {
// Convert to DB date
$datetime = $dateTimeConverter->fromUser($viewed['date_modified']);
if (empty($datetime)) {
$datetime = $dateTimeConverter->fromDb($viewed['date_modified']);
}
if (empty($datetime)) {
throw new ApiException(
'[ModulesController] [Unable to convert datetime field from recently viewed] "date_modified"',
ExceptionCode::API_DATE_CONVERTION_SUGARBEAN
);
}
$datetimeISO8601 = $datetime->format(DateTime::ATOM);
if ($datetime === false) {
throw new ApiException(
'[ModulesController] [Unable to convert datetime field to ISO 8601] "date_modified"',
ExceptionCode::API_DATE_CONVERTION_SUGARBEAN
);
}
$payload['included'][] = array(
'id' => $viewed['item_id'],
'type' => $viewed['module_name'],
'attributes' => array(
'name' => $viewed['item_summary'],
'order'=> $viewed['id'],
'date_modified' => $datetimeISO8601
)
);
}
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/favorites
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModulesMetaFavorites(Request $req, Response $res, array $args)
{
try {
$this->negotiatedJsonApiContent($req, $res);
$payload = array(
'data' => array(),
'included' => array(),
);
/** @var Favorites $favoritesBean */
$favoritesBean = BeanFactory::newBean('Favorites');
$favorites = $favoritesBean->getCurrentUserSidebarFavorites(null);
foreach ($favorites as $favorite) {
$payload['included'][] = array(
'id' => $favorite['id'],
'type' => $favorite['module_name'],
'attributes' => array(
'name' => $favorite['item_summary']
)
);
}
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{module_name}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleRecords(Request $req, Response $res, array $args)
{
try {
$config = $this->containers->get('ConfigurationManager');
/** @var ModulesLib $modulesLib; */
$modulesLib = $this->containers->get('ModulesLib');
$payload = array(
'links' => array(),
'data' => array()
);
$this->negotiatedJsonApiContent($req, $res);
$paginatedModuleRecords = $modulesLib->generatePaginatedModuleRecords($req, $res, $args);
$payload['data'] = $paginatedModuleRecords['list'];
$links = $modulesLib->generatePaginatedLinksFromModuleRecords($req, $res, $args, $paginatedModuleRecords);
$payload['links'] = $links->toJsonApiResponse();
$page = $req->getParam('page');
$currentOffset = (integer)$paginatedModuleRecords['current_offset'] < 0 ? 0 : (integer)$paginatedModuleRecords['current_offset'];
$limit = isset($page['limit']) ? (integer)$page['limit'] : -1;
$limitOffset = ($limit <= 0) ? $config['list_max_entries_per_page'] : $limit;
$lastOffset = (integer)floor((integer)$paginatedModuleRecords['row_count'] / $limitOffset);
$payload['meta']['offsets'] = array(
'current' => $currentOffset,
'count' => $lastOffset
);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* POST /api/v8/modules/{module}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function createModuleRecord(Request $req, Response $res, array $args)
{
try {
$config = $this->containers->get('ConfigurationManager');
$this->negotiatedJsonApiContent($req, $res);
$res = $res->withStatus(202);
$moduleName = $args['module'];
$module = BeanFactory::newBean($moduleName);
$body = json_decode($req->getBody()->getContents(), true);
$payload = array();
// Validate module
if (empty($module)) {
throw new ModuleNotFoundException('Bean factory can not create a new module, module name was: ' . $moduleName);
}
// Validate JSON
if (empty($body)) {
throw new EmptyBodyException('Request body contents was incorrect, unable to JSON-decode.');
}
// Validate Type
if (!isset($body['data']['type'])) {
$exception = new ConflictException('[ModuleController] [1] [Request body contents was incorrect, Missing "type" key in data] ');
$exception->setSource(self::SOURCE_TYPE);
throw $exception;
}
if (isset($body['data']['type']) && $body['data']['type'] !== $module->module_name) {
$exception = new ConflictException(
'[ModuleController] [Request body contents was incorrect, "type" does not match resource type] '.$body['data']['type']. ' !== ' . $moduleName,
ExceptionCode::API_MODULE_NOT_FOUND
);
$exception->setSource(self::SOURCE_TYPE);
throw $exception;
}
if (
isset($body['data']['id'])
&& !empty($body['data']['id'])
) {
$beanID = $body['data']['id'];
$isValidator = new SuiteValidator();
if (!$isValidator->isValidId($beanID)) {
throw new InvalidArgumentException(sprintf('Bean id %s is invalid', $beanID));
}
$bean = \BeanFactory::getBean($moduleName, $beanID);
if ($bean instanceof SugarBean) {
throw new IdAlreadyExistsException(sprintf(
'Bean id %s already exists in %s module',
$beanID,
$moduleName
), ExceptionCode::API_ID_ALREADY_EXISTS);
}
}
// Handle Request
/** @var SuiteBeanResource $resource */
$sugarBeanResource = $this->containers->get('SuiteBeanResource');
$sugarBean = $sugarBeanResource
->fromJsonApiRequest($body['data'])
->toSugarBean();
if (!$sugarBean->ACLAccess('save')) {
throw new NotAllowedException();
}
/** @var Links $links */
$links = $this->containers->get('Links');
$self = $config['site_url'] . '/api/' . $req->getUri()->getPath() . '/' . $sugarBean->id;
$links = $links->withSelf($self);
$selectFields = $req->getParam('fields');
/** @var SuiteBeanResource $resource */
$sugarBeanResource = $sugarBeanResource->fromSugarBean($sugarBean);
if ($selectFields !== null && isset($selectFields[$moduleName])) {
$fields = explode(',', $selectFields[$moduleName]);
$payload['data'] = $sugarBeanResource->toJsonApiResponseWithFields($fields);
} else {
$payload['data'] = $sugarBeanResource->toJsonApiResponse();
}
$payload['links'] = $links->toJsonApiResponse();
$res = $res->withStatus(201);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{module}/{id}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleRecord(Request $req, Response $res, array $args)
{
$query = [];
try {
if (isset($query['include'])) {
throw new BadRequestException(
'[ModuleController] [include query param is not implemented]',
ExceptionCode::API_NOT_IMPLEMENTED
);
}
if (isset($query['filter'])) {
throw new BadRequestException(
'[ModuleController] [filter query param is not implemented]',
ExceptionCode::API_NOT_IMPLEMENTED
);
}
$this->negotiatedJsonApiContent($req, $res);
$res = $res->withStatus(202);
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$moduleName = $args['module'];
$moduleId = $args['id'];
$module = BeanFactory::newBean($moduleName);
$payload = array();
// Validate module
if (empty($module)) {
throw new ModuleNotFoundException('Bean factory can not make a new bean. Module name was: ' . $moduleName);
}
$sugarBean = BeanFactory::getBean($moduleName, $moduleId);
if (!$sugarBean) {
throw new Exception('Bean Factory can not retrive a bean: ' . $moduleName);
}
if ($sugarBean->new_with_id === true) {
$exception = new NotFoundException('Bean factory can not get a bean with new id. Module name was: ' . $moduleName . ', ' . self::MISSING_ID);
$exception->setSource('');
throw $exception;
}
if (!$sugarBean->ACLAccess('view')) {
throw new NotAllowedException();
}
// Handle Request
/** @var SuiteBeanResource $resource */
$resource = $this->containers->get('SuiteBeanResource');
$resource = $resource->fromSugarBean($sugarBean);
// filter fields
$selectFields = $req->getParam('fields');
if ($selectFields !== null && isset($selectFields[$moduleName])) {
$fields = explode(',', $selectFields[$moduleName]);
$payload['data'] = $resource->toJsonApiResponseWithFields($fields);
} else {
$payload['data'] = $resource->toJsonApiResponse();
}
$res = $res->withStatus(200);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* PATCH /api/v8/modules/{module}/{id}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function updateModuleRecord(Request $req, Response $res, array $args)
{
try {
$this->negotiatedJsonApiContent($req, $res);
$res = $res->withStatus(202);
$moduleName = $args['module'];
$moduleId = $args['id'];
$module = BeanFactory::newBean($moduleName);
$body = json_decode($req->getBody()->getContents(), true);
$payload = array();
// Validate module
if (empty($module)) {
throw new ModuleNotFoundException('Bean factory can not retrive a new bean. Module name was: ' . $moduleName);
}
// Validate JSON
if (empty($body)) {
throw new EmptyBodyException('Request body contents was incorrect, unable to JSON-decode.');
}
// Validate Type
if (!isset($body['data']['type'])) {
$exception = new ConflictException('[Request body contents was incorrect, Missing "type" key in data]');
$exception->setSource(self::SOURCE_TYPE);
throw $exception;
}
if (isset($body['data']['type']) && $body['data']['type'] !== $module->module_name) {
$exception = new ConflictException('[Request body contents was incorrect, "type" does not match with module name]"', ExceptionCode::API_MODULE_NOT_FOUND);
$exception->setSource(self::SOURCE_TYPE);
throw $exception;
}
// Validate ID
$sugarBean = BeanFactory::getBean($moduleName, $moduleId);
if ($sugarBean->new_with_id === true || $sugarBean === false) {
$exception = new NotFoundException('[ModuleController] ["id" does not exist]');
$exception->setSource('');
throw $exception;
}
if (!$sugarBean->ACLAccess('save')) {
throw new NotAllowedException();
}
/** @var Resource $resource */
$resource = $this->containers->get('Resource');
/** @var SuiteBeanResource $sugarBeanResource */
$sugarBeanResource = $this->containers->get('SuiteBeanResource');
$sugarBeanResource = $sugarBeanResource->fromSugarBean($sugarBean);
$sugarBeanResource->mergeAttributes(
$resource->fromJsonApiRequest($body['data'])
);
$sugarBean = $sugarBeanResource->toSugarBean();
// Handle Request
if (empty($sugarBean->save())) {
throw new ApiException('[ModuleController] [Unable to update record]');
}
$sugarBeanResource = $this->containers->get('SuiteBeanResource');
$sugarBeanResource = $sugarBeanResource->fromSugarBean($sugarBean);
$selectFields = $req->getParam('fields');
if ($selectFields !== null && isset($selectFields[$moduleName])) {
$fields = explode(',', $selectFields[$moduleName]);
$payload['data'] = $sugarBeanResource->toJsonApiResponseWithFields($fields);
} else {
$payload['data'] = $sugarBeanResource->toJsonApiResponse();
}
$res = $res->withStatus(200);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* DELETE /api/v8/modules/{module}/{id}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function deleteModuleRecord(Request $req, Response $res, array $args)
{
try {
$this->negotiatedJsonApiContent($req, $res);
$res = $res->withStatus(202);
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$moduleName = $args['module'];
$moduleId = $args['id'];
$module = BeanFactory::newBean($moduleName);
$payload = array();
// Validate module
if (empty($module)) {
throw new ModuleNotFoundException('Bean factory can not get a new bean, module name was: ' . $moduleName);
}
// Validate ID
$sugarBean = BeanFactory::getBean($moduleName, $moduleId);
if ($sugarBean->new_with_id === true) {
$exception = new NotFoundException('Bean factory can not get a bean. Module name was: ' . $moduleName . ' ' . self::MISSING_ID);
$exception->setSource('');
throw $exception;
}
if (!$sugarBean->ACLAccess('delete')) {
throw new NotAllowedException();
}
// Handle Request
$sugarBean->deleted = 1;
if (empty($sugarBean->save())) {
throw new ApiException('[Unable to delete record]');
}
$payload['meta'] = array(
'status' => 200
);
$res = $res->withStatus(200);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{id}/meta/language
*
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleMetaLanguage(Request $req, Response $res, array $args)
{
$payload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$this->negotiatedJsonApiContent($req, $res);
$currentLanguage = $this->containers->get('CurrentLanguage');
$moduleLanguage = $this->containers->get('ModuleLanguage');
$moduleLanguageStrings = $moduleLanguage->getModuleLanguageStrings($currentLanguage, $args['module']);
$payload['meta'][$args['module']]['language'] = $moduleLanguageStrings;
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/meta/language
*
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getApplicationMetaLanguages(Request $req, Response $res, array $args)
{
$payload = [];
try {
$this->negotiatedJsonApiContent($req, $res);
$currentLanguage = $this->containers->get('CurrentLanguage');
/** @var ApplicationLanguage $moduleLanguage */
$applicationLanguage = $this->containers->get('ApplicationLanguages');
$payload['meta']['application']['language'] =
$applicationLanguage->getApplicationLanguageStrings($currentLanguage);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{id}/meta/attributes
*
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleMetaAttributes(Request $req, Response $res, array $args)
{
$payload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$this->negotiatedJsonApiContent($req, $res);
$payload['meta'][$args['module']]['attributes'] = BeanFactory::getBean($args['module'])->field_defs;
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* see: getModuleMetaAttributes
*
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws InvalidJsonApiResponseException
* @throws \InvalidArgumentException
* @throws NotFoundExceptionInterface
* @throws ContainerExceptionInterface
* @throws UnsupportedMediaTypeException
* @throws NotAcceptableException
*/
public function getModuleMetaFields(Request $req, Response $res, array $args)
{
return $this->getModuleMetaAttributes($req, $res, $args);
}
/**
* GET /api/v8/modules/{id}/meta/menu
*
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleMetaMenu(Request $req, Response $res, array $args)
{
$payload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$this->negotiatedJsonApiContent($req, $res);
$sugarView = new SugarView();
$menu = $sugarView->getMenu($args['module']);
$config = $this->containers->get('ConfigurationManager');
$self = $config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/' . $args['module'] . '/';
$results = array();
foreach ($menu as $item) {
$url = parse_url((string) $item[0]);
parse_str($url['query'], $orig);
$results[] = array(
'href' => $self . $item[2],
'label' => $item[1],
'action' => $item[2],
'module' => $item[3],
'type' => $item[3],
'query' => $orig,
);
}
$payload['meta'][$args['module']]['menu'] = $results;
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{module}/viewed
* @param Request $req
* @param Response $res
* @param array $args
* @throws RuntimeException
*/
public function getModuleRecordsViewed(Request $req, Response $res, array $args)
{
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$this->negotiatedJsonApiContent($req, $res);
global $current_user;
$dateTimeConverter = $this->containers->get('DateTimeConverter');
/** @var Tracker $tracker */
$tracker = BeanFactory::newBean('Trackers');
$payload = array(
'data' => array(),
'included' => array(),
);
$recentlyViewedSugarBeans = $tracker->get_recently_viewed($current_user->id, $args['module']);
foreach ($recentlyViewedSugarBeans as $viewed) {
// Convert to DB date
$datetime = $dateTimeConverter->fromUser($viewed['date_modified']);
if (empty($datetime)) {
$datetime = $dateTimeConverter->fromDb($viewed['date_modified']);
}
if (empty($datetime)) {
throw new ApiException(
'[ModulesController] [Unable to convert datetime field from recently viewed] "date_modified"',
ExceptionCode::API_DATE_CONVERTION_SUGARBEAN
);
}
$datetimeISO8601 = $datetime->format(DateTime::ATOM);
$payload['included'][] = array(
'id' => $viewed['item_id'],
'type' => $viewed['module_name'],
'attributes' => array(
'name' => $viewed['item_summary'],
'order'=> $viewed['id'],
'date_modified' => $datetimeISO8601
)
);
}
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/favorites
* @param Request $req
* @param Response $res
* @param array $args
* @throws RuntimeException
*/
public function getModuleFavorites(Request $req, Response $res, array $args)
{
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
$this->negotiatedJsonApiContent($req, $res);
$payload = array();
/** @var Favorites $favoritesBean */
$favoritesBean = BeanFactory::newBean('Favorites');
$payload['data'] = $favoritesBean->getCurrentUserFavoritesForModule($args['module']);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{module}/meta/view/{view}
* @see MBConstants for {view}
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function getModuleMetaLayout(Request $req, Response $res, array $args)
{
$payload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
if (!isset($args['view'])) {
throw new \InvalidArgumentException('Arguments array should contains a "view" index.');
}
$this->negotiatedJsonApiContent($req, $res);
/** @var SugarBean $bean */
$sugarBean = BeanFactory::newBean($args['module']);
if (empty($sugarBean)) {
throw new NotFoundException(
'[ModuleController] [Module does not exist] ' . $args['module'],
ExceptionCode::API_MODULE_NOT_FOUND
);
}
require_once $this->paths->getProjectPath().'/modules/ModuleBuilder/parsers/ParserFactory.php';
$parser = ParserFactory::getParser($args['view'], $args['module']);
$viewdefs = $parser->_viewdefs;
if (empty($viewdefs)) {
throw new NotFoundException(
'[ModuleController] [ViewDefinitions does not exist] ' . $args['view'],
ExceptionCode::API_VIEWDEF_NOT_FOUND
);
}
$payload['meta'][$args['module']]['view'][$args['view']] = $viewdefs;
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $payload);
}
/**
* GET /api/v8/modules/{id}/relationships/{link}
* @param Request $req
* @param Response $res
* @param array $args
* @see http://jsonapi.org/format/1.0/#fetching-relationships
* @throws RuntimeException
*/
public function getModuleRelationship(Request $req, Response $res, array $args)
{
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
if (!isset($args['id'])) {
throw new \InvalidArgumentException('Arguments array should contains a "id" index.');
}
if (!isset($args['link'])) {
throw new \InvalidArgumentException('Arguments array should contains a "link" index.');
}
$query = $req->getQueryParams('include');
if (isset($query['include'])) {
throw new BadRequestException('[ModuleController] [include query param is not implemented]', ExceptionCode::API_NOT_IMPLEMENTED);
}
if (isset($query['filter'])) {
throw new BadRequestException('[ModuleController] [filter query param is not implemented]', ExceptionCode::API_NOT_IMPLEMENTED);
}
$config = $this->containers->get('ConfigurationManager');
$this->negotiatedJsonApiContent($req, $res);
$payload = array(
'data' => array()
);
$sugarBean = BeanFactory::getBean($args['module'], $args['id']);
if (empty($sugarBean)) {
throw new NotFoundException(
'[ModuleController] [Record does not exist] ' . $args['link'],
ExceptionCode::API_RECORD_NOT_FOUND
);
}
if (!$sugarBean->ACLAccess('view')) {
throw new NotFoundException('[Record]');
}
if ($sugarBean->load_relationship($args['link']) === false) {
throw new NotFoundException(
'[ModuleController] [Relationship does not exist] ' . $args['link'],
ExceptionCode::API_RELATIONSHIP_NOT_FOUND
);
}
$relationshipType = $sugarBean->{$args['link']}->focus->{$args['link']}->relationship->type;
/** @var Link2 $sugarBeanRelationship */
$sugarBeanRelationship = $sugarBean->{$args['link']};
$sugarBeanRelationshipType = $sugarBeanRelationship->getType();
switch ($sugarBeanRelationshipType) {
case 'one':
// to one
$relatedIds = $sugarBean->{$args['link']}->get();
$relatedDefinition = $sugarBean->{$args['link']}->focus->{$args['link']}->relationship->def;
if (!isset($relatedDefinition['lhs_module'])) {
throw new \Exception('Related definition should contains a "lhs_module" index.');
}
foreach ($relatedIds as $id) {
// only needs one result
$data = array(
'type' => $relatedDefinition['lhs_module'],
'id' => $id
);
$links = new Links();
$data['links'] = $links
->withHref(
$config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/'.
$relatedDefinition['lhs_module'].'/'.$id
)
->toJsonApiResponse();
$payload['data'] = $data;
}
break;
case 'many':
// to many
/** @var Resource $resource */
$resource = $this->containers->get('Resource');
$related = $sugarBeanRelationship->query(
array(
'include_middle_table_fields' => true
)
);
$relatedDefinition = $sugarBean->field_defs[$args['link']];
$relatedType = $sugarBeanRelationship->getRelatedModuleName();
foreach ($related['rows'] as $row) {
if (!isset($row['id'])) {
throw new \Exception('Related definition should contains "id" index.');
}
$data = array(
'id' => $row['id'],
'type' => $relatedType
);
$meta = array(
'middle_table' => array(
'data' => array(
'id' => '',
'type' => 'Link',
'attributes' => $row
)
)
);
$links = new Links();
$data['links'] = $links
->withHref(
$config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/'.
$args['module'] . '/' . $row['id']
)
->toJsonApiResponse();
$data['meta'] = $meta;
$payload['data'][] = $data;
}
if (isset($sugarBeanRelationship->relationship->def['fields'])) {
$payload['meta']['attributes'] = $middleTableFieldDefs = $sugarBeanRelationship->relationship->def['fields'];
}
break;
default:
throw new BadRequestException('[ModuleController] [Relationship type not supported] type was: ' . $sugarBeanRelationshipType);
}
$payload['meta']['relationships']['type'] = $relationshipType;
$links = new Links();
$payload['links'] = $links
->withSelf(
$config['site_url'] . '/api/v'. self::VERSION_MAJOR . '/modules/'.
$args['module'].'/'.$args['id'].'/relationships/'.$args['link']
)
->toJsonApiResponse();
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
$this->generateJsonApiResponse($req, $res, $payload);
}
/**
* POST /api/v8/modules/{id}/relationships/{link}
* @see http://jsonapi.org/format/1.0/#crud-creating
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function createModuleRelationship(Request $req, Response $res, array $args)
{
$additional_fields = [];
$link = [];
$responsePayload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
if (!isset($args['id'])) {
throw new \InvalidArgumentException('Arguments array should contains a "id" index.');
}
if (!isset($args['link'])) {
throw new \InvalidArgumentException('Arguments array should contains a "link" index.');
}
$this->negotiatedJsonApiContent($req, $res);
$sugarBean = BeanFactory::getBean($args['module'], $args['id']);
if ($sugarBean->new_with_id === true) {
$exception = new NotFoundException(self::MISSING_ID);
$exception->setSource('');
throw $exception;
}
if ($sugarBean === false) {
$exception = new NotFoundException('[ModuleController] [Unable to find SugarBean] /modules/'.$args['module'].'/'.$args['id']);
$exception->setDetail('Please ensure that the module name and the id is correct.');
$exception->setSource('');
throw $exception;
}
if ($sugarBean->load_relationship($args['link']) === false) {
throw new NotFoundException(
'[ModuleController] [Relationship does not exist] ' . $args['link'],
ExceptionCode::API_RELATIONSHIP_NOT_FOUND
);
}
if (!$sugarBean->ACLAccess('save')) {
throw new NotAllowedException('[Record]');
}
/** @var Link2 $sugarBeanRelationship */
$sugarBeanRelationship = $sugarBean->{$args['link']};
$requestPayload = json_decode($req->getBody(), true);
// Validate JSON
if (empty($requestPayload)) {
throw new EmptyBodyException('Unable to JSON decode the requested body.');
}
/** @var Relationship $relationship */
$relationship = $this->containers->get('Relationship');
$relationship->setRelationshipName($args['link']);
$sugarBeanRelationshipTypeFromSugarBeanLink = SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship);
$relationship->setRelationshipType(
// $sugarBeanRelationshipTypeFromSugarBeanLink could be invalid, see below..
$sugarBeanRelationshipTypeFromSugarBeanLink
);
switch ($sugarBeanRelationshipTypeFromSugarBeanLink) {
case RelationshipType::TO_MANY:
if (!isset($requestPayload['data'])) {
throw new \InvalidArgumentException('Requested payload should contains a "data" attribute.');
}
$data = $requestPayload['data'];
$links = array();
// if a single ResourceIdentifier has been posted
if (!isset($data[0])) {
// convert to array
$data = array($data);
}
foreach ($data as $link) {
if (!isset($link['id'])) {
throw new \InvalidArgumentException('Arguments array should contains a "id" index.');
}
$links[] = $link['id'];
/** @var ResourceIdentifier $resourceIdentifier */
$resourceIdentifier = $this->containers->get('ResourceIdentifier');
$meta = null;
$additional_fields = array();
if (
isset($link['meta']['middle_table']['data']['attributes']) &&
!empty($link['meta']['middle_table']['data']['attributes'])
) {
$additional_fields = $link['meta']['middle_table']['data']['attributes'];
$meta = array(
'middle_table' => array(
'data' => array(
'id' => '',
'type' => 'Link',
'attributes' => $link['meta']['middle_table']['data']['attributes']
)
)
);
}
if (!isset($link['type'])) {
throw new \InvalidArgumentException('Arguments array should contains a "type" index.');
}
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
->withId($link['id'])
->withType($link['type'])
->withMeta($meta)
);
}
$added = $sugarBeanRelationship->add($links, $additional_fields);
if ($added !== true) {
throw new ConflictException('[ModuleController] [Unable to add relationships (to many)] ' . json_encode($added));
}
break;
case RelationshipType::TO_ONE:
$resourceIdentifier = $this->containers->get('ResourceIdentifier');
if (!isset($requestPayload['data']['id'])) {
throw new \InvalidArgumentException('Requested payload date should contains an "id".');
}
if (empty($requestPayload['data'])) {
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
);
} else {
if (!isset($requestPayload['data']['type'])) {
throw new \InvalidArgumentException('Requested payload date should contains a "type".');
}
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
->withId($requestPayload['data']['id'])
->withType($requestPayload['data']['type'])
);
}
$additional_fields = array();
if (
isset($link['meta']['middle_table']['data']['attributes']) &&
!empty($link['meta']['middle_table']['data']['attributes'])
) {
$additional_fields = $link['meta']['middle_table']['data']['attributes'];
}
$sugarBeanRelationship->add($requestPayload['data']['id'], $additional_fields);
break;
default:
throw new ForbiddenException('[ModuleController] [Invalid Relationship type]');
}
/** @var SuiteBeanResource $sugarBeanResource */
$sugarBeanResource = $this->containers->get('SuiteBeanResource');
$sugarBeanResource = $sugarBeanResource
->fromSugarBean($sugarBean);
$sugarBean = $sugarBeanResource->toSugarBean();
$sugarBean->retrieve($sugarBeanResource->getId());
$responsePayload['data'] = $relationship->toJsonApiResponse();
} catch (\Exception $e) {
$responsePayload = $this->handleExceptionIntoPayloadError($req, $e, isset($responsePayload) ? $responsePayload : []);
}
return $this->generateJsonApiResponse($req, $res, $responsePayload);
}
/**
* Replaces related items with request
* PATCH /api/v8/modules/{id}/relationships/{link}/{id}
* Note: Clear all related links with empty data payload such as null, [] etc.
* @see http://jsonapi.org/format/1.0/#crud-updating-relationships
* @param Request $req
* @param Response $res
* @param array $args
* @return Response
* @throws RuntimeException
*/
public function updateModuleRelationship(Request $req, Response $res, array $args)
{
$responsePayload = [];
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
if (!isset($args['id'])) {
throw new \InvalidArgumentException('Arguments array should contains a "id" index.');
}
if (!isset($args['link'])) {
throw new \InvalidArgumentException('Arguments array should contains a "link" index.');
}
$this->negotiatedJsonApiContent($req, $res);
$sugarBean = BeanFactory::getBean($args['module'], $args['id']);
if ($sugarBean->new_with_id === true) {
$exception = new NotFoundException(self::MISSING_ID);
$exception->setSource('');
throw $exception;
}
if ($sugarBean === false) {
$exception = new NotFoundException('[ModuleController] [Unable to find SugarBean] /modules/'.$args['module'].'/'.$args['id']);
$exception->setDetail('Please ensure that the module name and the id is correct.');
$exception->setSource('');
throw $exception;
}
if ($sugarBean->load_relationship($args['link']) === false) {
throw new NotFoundException(
'[ModuleController] [Relationship does not exist] ' . $args['link'],
ExceptionCode::API_RELATIONSHIP_NOT_FOUND
);
}
if (!$sugarBean->ACLAccess('save')) {
throw new NotAllowedException('[Record]');
}
/** @var \Link2 $sugarBeanRelationship */
$sugarBeanRelationship = $sugarBean->{$args['link']};
$requestPayload = json_decode($req->getBody(), true);
// Validate JSON
if (empty($requestPayload)) {
throw new EmptyBodyException('Invalid Request Payload given, unable to JSON decode body');
}
/** @var Relationship $relationship */
$relationship = $this->containers->get('Relationship');
$relationship->setRelationshipName($args['link']);
$relationship->setRelationshipType(
SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship)
);
if (!isset($requestPayload['data'])) {
throw new \InvalidArgumentException('Request Payload should contains a "data"');
}
if (SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship) === RelationshipType::TO_MANY) {
$data = $requestPayload['data'];
// if a single ResourceIdentifier has been posted
if (!isset($data[0])) {
// convert to array
$data = array($data);
}
foreach ($data as $link) {
/** @var ResourceIdentifier $resourceIdentifier */
$resourceIdentifier = $this->containers->get('ResourceIdentifier');
$meta = null;
if (
isset($link['meta']['middle_table']['data']['attributes']) &&
!empty($link['meta']['middle_table']['data']['attributes'])
) {
$meta = array(
'middle_table' => array(
'data' => array(
'id' => '',
'type' => 'Link',
'attributes' => $link['meta']['middle_table']['data']['attributes']
)
)
);
}
// The following removes PHP notice: Undefined index
$linkId = isset($link['id']) ? $link['id'] : null;
$linkType = isset($link['type']) ? $link['type'] : null;
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
->withId($linkId)
->withType($linkType)
->withMeta($meta)
);
}
} elseif (SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship) === RelationshipType::TO_ONE) {
/** @var ResourceIdentifier $resourceIdentifier */
$resourceIdentifier = $this->containers->get('ResourceIdentifier');
if (empty($requestPayload['data'])) {
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
);
} else {
if (!isset($requestPayload['data']['id'])) {
throw new \InvalidArgumentException('Request Payload "data" should contains an "id"');
}
if (!isset($requestPayload['data']['type'])) {
throw new \InvalidArgumentException('Request Payload "data" should contains an "type"');
}
$relationship = $relationship
->withResourceIdentifier(
$resourceIdentifier
->withId($requestPayload['data']['id'])
->withType($requestPayload['data']['type'])
);
}
}
/** @var SuiteBeanResource $sugarBeanResource */
$sugarBeanResource = $this->containers->get('SuiteBeanResource');
$sugarBeanResource = $sugarBeanResource
->fromSugarBean($sugarBean)
->withRelationship($relationship);
$sugarBean = $sugarBeanResource->toSugarBean();
$sugarBean->retrieve($sugarBeanResource->getId());
$responsePayload = array();
$responsePayload['data'] = $sugarBeanResource->getRelationshipByName($args['link']);
} catch (\Exception $e) {
$payload = $this->handleExceptionIntoPayloadError($req, $e, isset($payload) ? $payload : []);
}
return $this->generateJsonApiResponse($req, $res, $responsePayload);
}
/**
* DELETE /api/v8/modules/{id}/relationships/{link}/{id}
* @param Request $req
* @param Response $res
* @param array $args
* @see http://jsonapi.org/format/1.0/#crud-updating-relationships
* @return Response
* @throws RuntimeException
*/
public function deleteModuleRelationship(Request $req, Response $res, array $args)
{
try {
if (!isset($args['module'])) {
throw new \InvalidArgumentException('Arguments array should contains a "module" index to describe module name.');
}
if (!isset($args['id'])) {
throw new \InvalidArgumentException('Arguments array should contains a "id" index.');
}
if (!isset($args['link'])) {
throw new \InvalidArgumentException('Arguments array should contains a "link" index.');
}
$this->negotiatedJsonApiContent($req, $res);
$sugarBean = BeanFactory::getBean($args['module'], $args['id']);
if ($sugarBean->new_with_id === true) {
$exception = new NotFoundException(self::MISSING_ID);
$exception->setSource('');
throw $exception;
}
if ($sugarBean === false) {
$exception = new NotFoundException('[ModuleController] [Unable to find SugarBean] /modules/'.$args['module'].'/'.$args['id']);
$exception->setDetail('Please ensure that the module name and the id is correct.');
$exception->setSource('');
throw $exception;
}
if ($sugarBean->load_relationship($args['link']) === false) {
throw new NotFoundException(
'[ModuleController] [Relationship does not exist] ' . $args['link'],
ExceptionCode::API_RELATIONSHIP_NOT_FOUND
);
}
/** @var \Link2 $sugarBeanRelationship */
$sugarBeanRelationship = $sugarBean->{$args['link']};
$requestPayload = json_decode($req->getBody(), true);
/** @var Relationship $relationship */
$relationship = $this->containers->get('Relationship');
$relationship->setRelationshipName($args['link']);
$relationship->setRelationshipType(
SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship)
);
if (SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship) === RelationshipType::TO_MANY) {
if (empty($requestPayload['data'])) {
$sugarBeanRelationship->getRelationshipObject()->removeAll($sugarBeanRelationship);
} else {
$data = $requestPayload['data'];
// if a single ResourceIdentifier has been posted
if (!isset($data[0])) {
// convert to array
$data = array($data);
}
$links = array();
foreach ($data as $link) {
$links[] = $link['id'];
}
$removed = $sugarBeanRelationship->remove($links);
if ($removed !== true) {
throw new ConflictException(
'[ModuleController] [Unable to remove relationships (to many)]' . json_encode($removed)
);
}
}
} elseif (SugarBeanRelationshipType::fromSugarBeanLink($sugarBeanRelationship) === RelationshipType::TO_ONE) {
if (empty($requestPayload['data'])) {
$sugarBeanRelationship->getRelationshipObject()->removeAll($sugarBeanRelationship);
} else {
if (!isset($requestPayload['data']['id'])) {
throw new \InvalidArgumentException('Requested payload date should contains a "id".');
}
$sugarBeanRelationship->remove($requestPayload['data']['id']);
}
} else {
throw new ForbiddenException('[ModuleController] [Invalid Relationship type]');
}
$responsePayload = array();
$responsePayload['data'] = array();
} catch (\Exception $e) {
$responsePayload = $this->handleExceptionIntoPayloadError($req, $e, isset($responsePayload) ? $responsePayload : []);
}
return $this->generateJsonApiResponse($req, $res->withStatus(204), $responsePayload);
}
}