mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2025-03-17 23:02:43 +00:00
Merge branch 'hotfix' of https://github.com/salesagility/SuiteCRM into hotfix_inboundemail_tests
This commit is contained in:
commit
9ee11c1c06
284 changed files with 10039 additions and 1243 deletions
.gitignore.travis.yml
Api
Core
V8
BeanDecorator
Config
Controller
BaseController.php
InvocationStrategy
ListViewController.phpListViewSearchController.phpLogoutController.phpModuleController.phpRelationshipController.phpUserController.phpUserPreferencesController.phpFactory
Helper
JsonApi
Helper
Repository
Response
Middleware
OAuth2
Param
BaseParam.phpCreateModuleDataParams.phpCreateModuleParams.phpCreateRelationshipParams.phpDeleteModuleParams.phpDeleteRelationshipParams.phpGetModuleParams.phpGetModulesParams.phpGetRelationshipDataParams.phpGetRelationshipParams.phpGetUserPreferencesParams.phpListViewColumnsParams.phpListViewSearchParams.php
Options
Attributes.phpBaseOption.phpFields.phpFilter.phpId.phpLinkFieldName.phpModuleName.phpPage.phpSort.phpType.php
PageParams.phpUpdateModuleDataParams.phpUpdateModuleParams.phpService
docs
index.phpModuleInstall
composer.jsoncomposer.lockdata/Relationships
include
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -79,6 +79,7 @@ SuiteCRM.kdev4
|
|||
vendor/
|
||||
public/
|
||||
|
||||
|
||||
#Ignore bower_components
|
||||
bower_components/
|
||||
node_modules/
|
||||
|
|
31
.travis.yml
31
.travis.yml
|
@ -22,7 +22,7 @@ addons:
|
|||
chrome: stable
|
||||
|
||||
env:
|
||||
- INSTANCE_URL=http://localhost/ DATABASE_DRIVER=MYSQL DATABASE_NAME=automated_tests DATABASE_HOST=localhost DATABASE_USER=automated_tests DATABASE_PASSWORD=automated_tests INSTANCE_ADMIN_USER=admin INSTANCE_ADMIN_PASSWORD=admin1 COMPOSER_MEMORY_LIMIT=-1
|
||||
- INSTANCE_URL=http://localhost DATABASE_DRIVER=MYSQL DATABASE_NAME=automated_tests DATABASE_HOST=localhost DATABASE_USER=automated_tests DATABASE_PASSWORD=automated_tests INSTANCE_ADMIN_USER=admin INSTANCE_ADMIN_PASSWORD=admin1 COMPOSER_MEMORY_LIMIT=-1
|
||||
|
||||
before_install:
|
||||
# Install chrome driver#
|
||||
|
@ -53,31 +53,38 @@ before_script:
|
|||
# Configure apache virtual hosts - images with PHP 7 or above
|
||||
- sudo cp -f build/travis-ci-apache /etc/apache2/sites-available/000-default.conf
|
||||
- sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/000-default.conf
|
||||
- sudo service apache2 restart
|
||||
# Install composer
|
||||
- composer install
|
||||
- ./vendor/bin/codecept build
|
||||
# Additional PHP config
|
||||
- phpenv config-add travis.php.ini
|
||||
- sudo service apache2 restart
|
||||
# Install composer
|
||||
- rm composer.lock
|
||||
- composer install
|
||||
- ./vendor/bin/codecept build
|
||||
|
||||
script:
|
||||
# Run the wizard installer ?
|
||||
# Run the wizard installer
|
||||
- echo "using install wizard"
|
||||
- ./vendor/bin/codecept run install --env travis-ci-hub -f -vvv -d
|
||||
- ./build/push_output.sh
|
||||
|
||||
|
||||
|
||||
# set the log level to error
|
||||
- echo "\$sugar_config['logger']['level']='error';" >> config_override.php
|
||||
# Run the unit tests
|
||||
- ./vendor/bin/codecept run unit --steps -f -vvv -d
|
||||
# Install OAuth2 demo data
|
||||
- mysql -u root -D automated_tests -v -e "source tests/_data/api_data.sql"
|
||||
# Install demo user data
|
||||
- mysql -u root -D automated_tests -v -e "source tests/_data/demo_users.sql"
|
||||
# Run the unit tests
|
||||
# set the log level to error
|
||||
- echo "\$sugar_config['logger']['level']='error';" >> config_override.php
|
||||
# add keys
|
||||
- sudo chmod -R 777 .
|
||||
- openssl genrsa -out Api/V8/OAuth2/private.key 2048
|
||||
- openssl rsa -in Api/V8/OAuth2/private.key -pubout -out Api/V8/OAuth2/public.key
|
||||
- sudo chmod 600 Api/V8/OAuth2/p*.key
|
||||
# - sudo chown www-data:www-data Api/V8/OAuth2/p*.key
|
||||
# Run API functional tests
|
||||
- ./vendor/bin/codecept run tests/api/V8/ -f -vvv -d
|
||||
# RUN Basic Acceptance test
|
||||
- ./vendor/bin/codecept run -f unit --steps -v && ./vendor/bin/codecept run api --steps -f -v && sudo chmod -R 777 . && ./vendor/bin/codecept run acceptance --env travis-ci-hub -f -vvv;
|
||||
- ./vendor/bin/codecept run acceptance --env travis-ci-hub -f -vvv -d
|
||||
|
||||
after_script:
|
||||
- ./build/push_output.sh
|
||||
|
|
61
Api/Core/Config/ApiConfig.php
Normal file
61
Api/Core/Config/ApiConfig.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
namespace Api\Core\Config;
|
||||
|
||||
class ApiConfig
|
||||
{
|
||||
// we still support 5.5.9
|
||||
private static $slimSettings = [
|
||||
'Api/Core/Config/slim.php',
|
||||
];
|
||||
|
||||
private static $containers = [
|
||||
'Api/V8/Config/services.php',
|
||||
];
|
||||
|
||||
private static $routes = [
|
||||
'Api/V8/Config/routes.php',
|
||||
];
|
||||
|
||||
const OAUTH2_PRIVATE_KEY = 'Api/V8/OAuth2/private.key';
|
||||
const OAUTH2_PUBLIC_KEY = 'Api/V8/OAuth2/public.key';
|
||||
const OAUTH2_ENCRYPTION_KEY = 'KcWedk/XtvWgtuf7UHx6ayHnrIaMC/t4RjZrdVBY2Ho=';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private static $debugExceptions = false;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function getDebugExceptions()
|
||||
{
|
||||
return self::$debugExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getSlimSettings()
|
||||
{
|
||||
return self::$slimSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getContainers()
|
||||
{
|
||||
return self::$containers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getRoutes()
|
||||
{
|
||||
return self::$routes;
|
||||
}
|
||||
}
|
12
Api/Core/Config/slim.php
Normal file
12
Api/Core/Config/slim.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
'settings' => [
|
||||
/** Additional information about exceptions are displayed by the default error handler. */
|
||||
'displayErrorDetails' => true,
|
||||
/** Routes are accessible in middleware. */
|
||||
'determineRouteBeforeAppMiddleware' => true,
|
||||
]
|
||||
], basename(__FILE__));
|
29
Api/Core/Loader/ContainerLoader.php
Normal file
29
Api/Core/Loader/ContainerLoader.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace Api\Core\Loader;
|
||||
|
||||
use Api\Core\Config\ApiConfig;
|
||||
use Api\Core\Resolver\ConfigResolver;
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Slim\Container;
|
||||
|
||||
class ContainerLoader
|
||||
{
|
||||
/**
|
||||
* Load all service containers and add slim settings
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public static function configure()
|
||||
{
|
||||
$slimSettings = ConfigResolver::loadFiles(ApiConfig::getSlimSettings());
|
||||
// if we want to use this without DI, should create an instance for it
|
||||
$container = new Container($slimSettings);
|
||||
|
||||
$services = ConfigResolver::loadFiles(ApiConfig::getContainers());
|
||||
foreach ($services as $service => $closure) {
|
||||
$container[$service] = $closure;
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
161
Api/Core/Loader/CustomLoader.php
Normal file
161
Api/Core/Loader/CustomLoader.php
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?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 Api\Core\Loader;
|
||||
|
||||
use Exception;
|
||||
use LoggerManager;
|
||||
use Slim\App;
|
||||
|
||||
/**
|
||||
* CustomLoader
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class CustomLoader
|
||||
{
|
||||
const ERR_NO_ERROR = 0;
|
||||
const ERR_FILE_NOT_FOUND = 1;
|
||||
const ERR_ROUTE_FILE_NOT_FOUND = 2;
|
||||
const ERR_WRONG_CUSTOM_FORMAT = 3;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $lastError = self::ERR_NO_ERROR;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $customPath = 'custom/application/Ext/Api/V8/';
|
||||
|
||||
public static function setCustomPath($customPath = 'custom/application/Ext/Api/V8/')
|
||||
{
|
||||
self::$customPath = $customPath;
|
||||
}
|
||||
|
||||
public static function getCustomPath()
|
||||
{
|
||||
return self::$customPath;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function getLastError()
|
||||
{
|
||||
$ret = self::$lastError;
|
||||
self::$lastError = self::ERR_NO_ERROR;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* merge multidimensional arrays
|
||||
*
|
||||
* @param array $arrays
|
||||
* @return array
|
||||
*/
|
||||
public static function arrayMerge($arrays)
|
||||
{
|
||||
$result = [];
|
||||
foreach ((array)$arrays as $array) {
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_integer($key)) {
|
||||
// is indexed?
|
||||
$result[] = $value;
|
||||
} elseif (isset($result[$key]) && is_array($value) && is_array($result[$key])) {
|
||||
// is associative?
|
||||
$result[$key] = self::arrayMerge([$result[$key], $value]);
|
||||
} else {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* include and merge custom arrays (custom file should return an array)
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $customFile
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function mergeCustomArray($array, $customFile)
|
||||
{
|
||||
self::getLastError();
|
||||
$customFile = self::$customPath . $customFile;
|
||||
if (!file_exists($customFile)) {
|
||||
self::$lastError = self::ERR_FILE_NOT_FOUND;
|
||||
LoggerManager::getLogger()->debug('Custom file is not exists: ' . $customFile);
|
||||
} else {
|
||||
$customs = include $customFile;
|
||||
if (!is_array($customs)) {
|
||||
throw new Exception('Custom file should return an array.', self::ERR_WRONG_CUSTOM_FORMAT);
|
||||
}
|
||||
$array = self::arrayMerge([$array, $customs]);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param App $app
|
||||
* @return App
|
||||
*/
|
||||
public static function loadCustomRoutes(App $app, $customRoutesFile = 'Config/routes.php')
|
||||
{
|
||||
self::getLastError();
|
||||
$customRoutesFile = self::$customPath . $customRoutesFile;
|
||||
if (!file_exists($customRoutesFile)) {
|
||||
self::$lastError = self::ERR_ROUTE_FILE_NOT_FOUND;
|
||||
LoggerManager::getLogger()->debug('Custom routes file is not exists: ' . $customRoutesFile);
|
||||
} else {
|
||||
include $customRoutesFile;
|
||||
}
|
||||
return $app;
|
||||
}
|
||||
}
|
25
Api/Core/Loader/RouteLoader.php
Normal file
25
Api/Core/Loader/RouteLoader.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace Api\Core\Loader;
|
||||
|
||||
use Api\Core\Config\ApiConfig;
|
||||
use Api\Core\Resolver\ConfigResolver;
|
||||
use Slim\App;
|
||||
|
||||
class RouteLoader
|
||||
{
|
||||
/**
|
||||
* Load all app routes
|
||||
*
|
||||
* @param App $app
|
||||
*/
|
||||
public function configureRoutes(App $app)
|
||||
{
|
||||
$routes = ApiConfig::getRoutes();
|
||||
|
||||
foreach ($routes as $route) {
|
||||
if (ConfigResolver::isFileExist($route)) {
|
||||
require $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
Api/Core/Resolver/ConfigResolver.php
Normal file
51
Api/Core/Resolver/ConfigResolver.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
namespace Api\Core\Resolver;
|
||||
|
||||
class ConfigResolver
|
||||
{
|
||||
/**
|
||||
* Loading and merge files which are arrays.
|
||||
*
|
||||
* @param array $files
|
||||
*
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException When config file does not contain an array.
|
||||
*/
|
||||
public static function loadFiles(array $files)
|
||||
{
|
||||
$configs = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
// base dir must exist in entryPoint.php
|
||||
$file = sprintf('%s/%s', $GLOBALS['BASE_DIR'], $file);
|
||||
|
||||
if (self::isFileExist($file)) {
|
||||
$config = require $file;
|
||||
}
|
||||
|
||||
if (!is_array($config)) {
|
||||
throw new \InvalidArgumentException(sprintf('File %s is invalid', $file));
|
||||
}
|
||||
|
||||
$configs[] = $config;
|
||||
}
|
||||
|
||||
// since we support 5.5.9, we can't use splat op here
|
||||
return !$configs ? $configs : array_reduce($configs, 'array_merge', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return boolean
|
||||
* @throws \RuntimeException When config file is not readable.
|
||||
*/
|
||||
public static function isFileExist($file)
|
||||
{
|
||||
if (!file_exists($file) || !is_readable($file)) {
|
||||
throw new \RuntimeException(sprintf('File %s is not readable', $file));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
19
Api/Core/app.php
Normal file
19
Api/Core/app.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
// Swagger needs this, but should remove - CORS
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT');
|
||||
header('Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
if (!defined('sugarEntry')) {
|
||||
define('sugarEntry', true);
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
chdir(__DIR__ . '/../../');
|
||||
require_once __DIR__ . '/../../include/entryPoint.php';
|
||||
|
||||
$app = new \Slim\App(\Api\Core\Loader\ContainerLoader::configure());
|
||||
// closure shouldn't be created in static context under PHP7
|
||||
$routeLoader = new \Api\Core\Loader\RouteLoader();
|
||||
$routeLoader->configureRoutes($app);
|
171
Api/V8/BeanDecorator/BeanListRequest.php
Normal file
171
Api/V8/BeanDecorator/BeanListRequest.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
namespace Api\V8\BeanDecorator;
|
||||
|
||||
class BeanListRequest
|
||||
{
|
||||
/**
|
||||
* @var \SugarBean
|
||||
*/
|
||||
private $bean;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $orderBy = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $where = '';
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $offset = BeanManager::DEFAULT_OFFSET;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $limit = -1;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $max = BeanManager::DEFAULT_ALL_RECORDS;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $deleted = 0;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $singleSelect = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $fields = [];
|
||||
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
*/
|
||||
public function __construct(\SugarBean $bean)
|
||||
{
|
||||
$this->bean = $bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $orderBy
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function orderBy($orderBy)
|
||||
{
|
||||
$this->orderBy = $orderBy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $where
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function where($where)
|
||||
{
|
||||
$this->where = $where;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function offset($offset)
|
||||
{
|
||||
$this->offset = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $limit
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function limit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $max
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function max($max)
|
||||
{
|
||||
$this->max = $max;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $deleted
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function deleted($deleted)
|
||||
{
|
||||
$this->deleted = $deleted;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $singleSelect
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function singleSelect($singleSelect)
|
||||
{
|
||||
$this->singleSelect = $singleSelect;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function fields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BeanListResponse
|
||||
*/
|
||||
public function fetch()
|
||||
{
|
||||
return new BeanListResponse($this->bean->get_list(
|
||||
$this->orderBy,
|
||||
$this->where,
|
||||
$this->offset,
|
||||
$this->limit,
|
||||
$this->max,
|
||||
$this->deleted,
|
||||
$this->singleSelect,
|
||||
$this->fields
|
||||
));
|
||||
}
|
||||
}
|
40
Api/V8/BeanDecorator/BeanListResponse.php
Normal file
40
Api/V8/BeanDecorator/BeanListResponse.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
namespace Api\V8\BeanDecorator;
|
||||
|
||||
class BeanListResponse
|
||||
{
|
||||
/**
|
||||
* @var \SugarBean[]|[]
|
||||
*/
|
||||
private $beans;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $rowCount;
|
||||
|
||||
/**
|
||||
* @param array $result
|
||||
*/
|
||||
public function __construct(array $result = [])
|
||||
{
|
||||
$this->beans = isset($result['list']) ? $result['list'] : [];
|
||||
$this->rowCount = isset($result['row_count']) ? intval($result['row_count']) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SugarBean[]|[]
|
||||
*/
|
||||
public function getBeans()
|
||||
{
|
||||
return $this->beans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getRowCount()
|
||||
{
|
||||
return $this->rowCount;
|
||||
}
|
||||
}
|
228
Api/V8/BeanDecorator/BeanManager.php
Normal file
228
Api/V8/BeanDecorator/BeanManager.php
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
namespace Api\V8\BeanDecorator;
|
||||
|
||||
class BeanManager
|
||||
{
|
||||
const DEFAULT_OFFSET = 0;
|
||||
const DEFAULT_LIMIT = -1;
|
||||
const DEFAULT_ALL_RECORDS = -99;
|
||||
|
||||
/**
|
||||
* @var \DBManager
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $beanAliases;
|
||||
|
||||
/**
|
||||
* @param \DBManager $db
|
||||
* @param array $beanAliases
|
||||
*/
|
||||
public function __construct(\DBManager $db, array $beanAliases)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->beanAliases = $beanAliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
*
|
||||
* @return \SugarBean
|
||||
* @throws \InvalidArgumentException When the module is invalid.
|
||||
*/
|
||||
public function newBeanSafe($module)
|
||||
{
|
||||
if (array_key_exists($module, $this->beanAliases)) {
|
||||
$module = $this->beanAliases[$module];
|
||||
}
|
||||
|
||||
$bean = \BeanFactory::newBean($module);
|
||||
|
||||
if (!$bean instanceof \SugarBean) {
|
||||
throw new \InvalidArgumentException(sprintf('Module %s does not exist', $module));
|
||||
}
|
||||
|
||||
return $bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
* @param string|null $id
|
||||
* @param array $params
|
||||
* @param boolean $deleted
|
||||
*
|
||||
* @return \SugarBean|boolean
|
||||
*/
|
||||
public function getBean($module, $id = null, array $params = [], $deleted = true)
|
||||
{
|
||||
return \BeanFactory::getBean($module, $id, $params, $deleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
* @param string $id
|
||||
* @param array $params
|
||||
* @param boolean $deleted
|
||||
*
|
||||
* @return \SugarBean
|
||||
* @throws \DomainException When bean id is empty or bean is not found by name.
|
||||
* @throws \InvalidArgumentException When bean is not found with the given id.
|
||||
*/
|
||||
public function getBeanSafe(
|
||||
$module,
|
||||
$id,
|
||||
array $params = [],
|
||||
$deleted = true
|
||||
) {
|
||||
if (empty($id)) {
|
||||
throw new \DomainException('Module id is empty when trying to get ' . $module);
|
||||
}
|
||||
|
||||
$objectName = \BeanFactory::getObjectName($module);
|
||||
if (!$objectName && array_key_exists($module, $this->beanAliases)) {
|
||||
$objectName = \BeanFactory::getObjectName($this->beanAliases[$module]);
|
||||
$module = $this->beanAliases[$module];
|
||||
}
|
||||
|
||||
if (!$objectName) {
|
||||
throw new \DomainException(sprintf('Module with name %s is not found', $module));
|
||||
}
|
||||
|
||||
$bean = $this->getBean($module, $id, $params, $deleted);
|
||||
if ($bean === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('%s module with id %s is not found', $module, $id)
|
||||
);
|
||||
}
|
||||
|
||||
return $bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
*
|
||||
* @return BeanListRequest
|
||||
*/
|
||||
public function getList($module)
|
||||
{
|
||||
return new BeanListRequest($this->newBeanSafe($module));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $sourceBean
|
||||
* @param \SugarBean $relatedBean
|
||||
* @param string $relationship
|
||||
*
|
||||
* @throws \RuntimeException If relationship cannot be loaded or created between beans.
|
||||
*/
|
||||
public function createRelationshipSafe(\SugarBean $sourceBean, \SugarBean $relatedBean, $relationship)
|
||||
{
|
||||
if (!$sourceBean->load_relationship($relationship)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('Cannot load relationship %s for module %s', $relationship, $sourceBean->getObjectName())
|
||||
);
|
||||
}
|
||||
|
||||
$result = $sourceBean->{$relationship}->add($relatedBean);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Cannot create relationship %s between module %s and %s',
|
||||
$relationship,
|
||||
$sourceBean->getObjectName(),
|
||||
$relatedBean->getObjectName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $sourceBean
|
||||
* @param \SugarBean $relatedBean
|
||||
* @param string $relationship
|
||||
*
|
||||
* @throws \RuntimeException If relationship cannot be loaded or deleted between beans.
|
||||
*/
|
||||
public function deleteRelationshipSafe(\SugarBean $sourceBean, \SugarBean $relatedBean, $relationship)
|
||||
{
|
||||
if (!$sourceBean->load_relationship($relationship)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('Cannot load relationship %s for module %s', $relationship, $sourceBean->getObjectName())
|
||||
);
|
||||
}
|
||||
|
||||
$result = $sourceBean->{$relationship}->delete($sourceBean->id, $relatedBean->id);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Cannot delete relationship %s between module %s and %s',
|
||||
$relationship,
|
||||
$sourceBean->getObjectName(),
|
||||
$relatedBean->getObjectName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $sourceBean
|
||||
* @param \SugarBean $relatedBean
|
||||
*
|
||||
* @return string
|
||||
* @throws \DomainException In case link field is not found.
|
||||
*/
|
||||
public function getLinkedFieldName(\SugarBean $sourceBean, \SugarBean $relatedBean)
|
||||
{
|
||||
$linkedFields = $sourceBean->get_linked_fields();
|
||||
$relationship = \Relationship::retrieve_by_modules(
|
||||
$sourceBean->module_name,
|
||||
$relatedBean->module_name,
|
||||
$sourceBean->db
|
||||
);
|
||||
|
||||
$linkFieldName = '';
|
||||
foreach ($linkedFields as $linkedField) {
|
||||
if ($linkedField['relationship'] === $relationship) {
|
||||
$linkFieldName = $linkedField['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$linkFieldName) {
|
||||
throw new \DomainException(
|
||||
sprintf(
|
||||
'Link field has not found in %s to determine relationship for %s',
|
||||
$sourceBean->getObjectName(),
|
||||
$relatedBean->getObjectName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $linkFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
* @param string $where
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function countRecords($module, $where)
|
||||
{
|
||||
$rowCount = $this->db->fetchRow(
|
||||
$this->db->query(
|
||||
sprintf(
|
||||
"SELECT COUNT(*) AS cnt FROM %s %s",
|
||||
$this->newBeanSafe($module)->getTableName(),
|
||||
$where === '' ? '' : 'WHERE ' . $where
|
||||
)
|
||||
)
|
||||
)["cnt"];
|
||||
|
||||
return intval($rowCount);
|
||||
}
|
||||
}
|
123
Api/V8/Config/routes.php
Normal file
123
Api/V8/Config/routes.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\Controller\LogoutController;
|
||||
use Api\V8\Factory\ParamsMiddlewareFactory;
|
||||
use Api\V8\Param\CreateModuleParams;
|
||||
use Api\V8\Param\CreateRelationshipParams;
|
||||
use Api\V8\Param\DeleteModuleParams;
|
||||
use Api\V8\Param\GetModuleParams;
|
||||
use Api\V8\Param\GetModulesParams;
|
||||
use Api\V8\Param\GetRelationshipParams;
|
||||
use Api\V8\Param\ListViewColumnsParams;
|
||||
use Api\V8\Param\ListViewSearchParams;
|
||||
use Api\V8\Param\UpdateModuleParams;
|
||||
use Api\V8\Param\GetUserPreferencesParams;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
$app->group('', function () use ($app) {
|
||||
/**
|
||||
* OAuth2 access token
|
||||
*/
|
||||
$app->post('/access_token', function () {
|
||||
})->add(new AuthorizationServerMiddleware($app->getContainer()->get(AuthorizationServer::class)));
|
||||
|
||||
$app->group('/V8', function () use ($app) {
|
||||
/** @var ParamsMiddlewareFactory $paramsMiddlewareFactory */
|
||||
$paramsMiddlewareFactory = $app->getContainer()->get(ParamsMiddlewareFactory::class);
|
||||
|
||||
/**
|
||||
* Logout
|
||||
*/
|
||||
$app->post('/logout', LogoutController::class);
|
||||
|
||||
$app
|
||||
->get('/search-defs/module/{moduleName}', 'Api\V8\Controller\ListViewSearchController:getModuleSearchDefs')
|
||||
->add($paramsMiddlewareFactory->bind(ListViewSearchParams::class));
|
||||
|
||||
$app
|
||||
->get('/listview/columns/{moduleName}', 'Api\V8\Controller\ListViewController:getListViewColumns')
|
||||
->add($paramsMiddlewareFactory->bind(ListViewColumnsParams::class));
|
||||
|
||||
$app->get('/current-user', 'Api\V8\Controller\UserController:getCurrentUser');
|
||||
|
||||
$app
|
||||
->get('/user-preferences/{id}', 'Api\V8\Controller\UserPreferencesController:getUserPreferences')
|
||||
->add($paramsMiddlewareFactory->bind(GetUserPreferencesParams::class));
|
||||
|
||||
/**
|
||||
* Get module records
|
||||
*/
|
||||
$app
|
||||
->get('/module/{moduleName}', 'Api\V8\Controller\ModuleController:getModuleRecords')
|
||||
->add($paramsMiddlewareFactory->bind(GetModulesParams::class));
|
||||
|
||||
/**
|
||||
* Get a module record
|
||||
*/
|
||||
$app
|
||||
->get('/module/{moduleName}/{id}', 'Api\V8\Controller\ModuleController:getModuleRecord')
|
||||
->add($paramsMiddlewareFactory->bind(GetModuleParams::class));
|
||||
|
||||
/**
|
||||
* Create a module record
|
||||
*/
|
||||
$app
|
||||
->post('/module', 'Api\V8\Controller\ModuleController:createModuleRecord')
|
||||
->add($paramsMiddlewareFactory->bind(CreateModuleParams::class));
|
||||
|
||||
/**
|
||||
* Update a module record
|
||||
*/
|
||||
$app
|
||||
->patch('/module', 'Api\V8\Controller\ModuleController:updateModuleRecord')
|
||||
->add($paramsMiddlewareFactory->bind(UpdateModuleParams::class));
|
||||
|
||||
/**
|
||||
* Delete a module record
|
||||
*/
|
||||
$app
|
||||
->delete('/module/{moduleName}/{id}', 'Api\V8\Controller\ModuleController:deleteModuleRecord')
|
||||
->add($paramsMiddlewareFactory->bind(DeleteModuleParams::class));
|
||||
|
||||
/**
|
||||
* Get relationships
|
||||
*/
|
||||
$app
|
||||
->get(
|
||||
'/module/{moduleName}/{id}/relationships/{linkFieldName}',
|
||||
'Api\V8\Controller\RelationshipController:getRelationship'
|
||||
)
|
||||
->add($paramsMiddlewareFactory->bind(GetRelationshipParams::class));
|
||||
|
||||
/**
|
||||
* Create relationship
|
||||
*/
|
||||
$app
|
||||
->post(
|
||||
'/module/{moduleName}/{id}/relationships',
|
||||
'Api\V8\Controller\RelationshipController:createRelationship'
|
||||
)
|
||||
->add($paramsMiddlewareFactory->bind(CreateRelationshipParams::class));
|
||||
|
||||
/**
|
||||
* Delete relationship
|
||||
*/
|
||||
$app
|
||||
->delete(
|
||||
'/module/{moduleName}/{id}/relationships/{linkFieldName}/{relatedBeanId}',
|
||||
'Api\V8\Controller\RelationshipController:deleteRelationship'
|
||||
)
|
||||
->add($paramsMiddlewareFactory->bind(DeleteRelationShipParams::class));
|
||||
|
||||
// add custom routes
|
||||
$app->group('/custom', function () use ($app) {
|
||||
$app = CustomLoader::loadCustomRoutes($app);
|
||||
});
|
||||
|
||||
})->add(new ResourceServerMiddleware($app->getContainer()->get(ResourceServer::class)));
|
||||
});
|
||||
|
28
Api/V8/Config/services.php
Normal file
28
Api/V8/Config/services.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\Controller\InvocationStrategy\SuiteInvocationStrategy;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
/** overwrite slim's foundHandler */
|
||||
'foundHandler' => function () {
|
||||
return new SuiteInvocationStrategy();
|
||||
},
|
||||
BeanManager::class => function (Container $container) {
|
||||
return new BeanManager(
|
||||
$container->get(DBManager::class),
|
||||
$container->get('beanAliases')
|
||||
);
|
||||
},
|
||||
] +
|
||||
(require __DIR__ . '/services/beanAliases.php') +
|
||||
(require __DIR__ . '/services/controllers.php') +
|
||||
(require __DIR__ . '/services/factories.php') +
|
||||
(require __DIR__ . '/services/globals.php') +
|
||||
(require __DIR__ . '/services/helpers.php') +
|
||||
(require __DIR__ . '/services/middlewares.php') +
|
||||
(require __DIR__ . '/services/params.php') +
|
||||
(require __DIR__ . '/services/services.php') +
|
||||
(require __DIR__ . '/services/validators.php'), basename(__FILE__));
|
61
Api/V8/Config/services/beanAliases.php
Normal file
61
Api/V8/Config/services/beanAliases.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
/**
|
||||
* Aliases for core modules
|
||||
*/
|
||||
return [
|
||||
'beanAliases' => function () {
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Account::class => 'Accounts',
|
||||
ACLAction::class => 'ACLActions',
|
||||
ACLRole::class => 'ACLRoles',
|
||||
Alert::class => 'Alerts',
|
||||
AOR_Chart::class => 'AOR_Charts',
|
||||
AOR_Condition::class => 'AOR_Conditions',
|
||||
AOR_Field::class => 'AOR_Fields',
|
||||
AOR_Report::class => 'AOR_Reports',
|
||||
AOW_Action::class => 'AOW_Actions',
|
||||
AOW_Condition::class => 'AOW_Conditions',
|
||||
Call::class => 'Calls',
|
||||
Campaign::class => 'Campaigns',
|
||||
CampaignTracker::class => 'CampaignTrackers',
|
||||
aCase::class => 'Cases',
|
||||
'Case' => 'Cases',
|
||||
ConnectorRecord::class => 'Connector',
|
||||
Contact::class => 'Contacts',
|
||||
Currency::class => 'Currencies',
|
||||
DocumentRevision::class => 'DocumentRevisions',
|
||||
Document::class => 'Documents',
|
||||
FieldsMetaData::class => 'DynamicFields',
|
||||
Email::class => 'Emails',
|
||||
EmailTemplate::class => 'EmailTemplates',
|
||||
Employee::class => 'Employees',
|
||||
UsersLastImport::class => 'Import',
|
||||
Lead::class => 'Leads',
|
||||
Meeting::class => 'Meetings',
|
||||
MergeRecord::class => 'MergeRecords',
|
||||
Note::class => 'Notes',
|
||||
OAuthKey::class => 'OAuthKeys',
|
||||
OAuthToken::class => 'OAuthTokens',
|
||||
Opportunity::class => 'Opportunities',
|
||||
ProspectList::class => 'ProspectLists',
|
||||
Prospect::class => 'Prospects',
|
||||
Relationship::class => 'Relationships',
|
||||
Reminder::class => 'Reminders',
|
||||
Reminder_Invitee::class => 'Reminders_Invitees',
|
||||
Role::class => 'Roles',
|
||||
SecurityGroup::class => 'SecurityGroups',
|
||||
Task::class => 'Tasks',
|
||||
Tracker::class => 'Trackers',
|
||||
User::class => 'Users',
|
||||
UserPreference::class => 'UserPreferences',
|
||||
vCal::class => 'vCals',
|
||||
'Contracts' => AOS_Contracts::class,
|
||||
'Invoices' => AOS_Invoices::class,
|
||||
'ProductQuotes' => AOS_Products_Quotes::class,
|
||||
'Quotes' => AOS_Quotes::class,
|
||||
], basename(__FILE__));
|
||||
}
|
||||
];
|
53
Api/V8/Config/services/controllers.php
Normal file
53
Api/V8/Config/services/controllers.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\Controller;
|
||||
use Api\V8\Service\ListViewSearchService;
|
||||
use Api\V8\Service\ListViewService;
|
||||
use Api\V8\Service\LogoutService;
|
||||
use Api\V8\Service\ModuleService;
|
||||
use Api\V8\Service\RelationshipService;
|
||||
use Api\V8\Service\UserPreferencesService;
|
||||
use Api\V8\Service\UserService;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Controller\ListViewSearchController::class => function (Container $container) {
|
||||
return new Controller\ListViewSearchController(
|
||||
$container->get(ListViewSearchService::class)
|
||||
);
|
||||
},
|
||||
Controller\UserPreferencesController::class => function (Container $container) {
|
||||
return new Controller\UserPreferencesController(
|
||||
$container->get(UserPreferencesService::class)
|
||||
);
|
||||
},
|
||||
Controller\UserController::class => function (Container $container) {
|
||||
return new Controller\UserController(
|
||||
$container->get(UserService::class)
|
||||
);
|
||||
},
|
||||
Controller\ListViewController::class => function (Container $container) {
|
||||
return new Controller\ListViewController(
|
||||
$container->get(ListViewService::class)
|
||||
);
|
||||
},
|
||||
Controller\ModuleController::class => function (Container $container) {
|
||||
return new Controller\ModuleController(
|
||||
$container->get(ModuleService::class)
|
||||
);
|
||||
},
|
||||
Controller\LogoutController::class => function (Container $container) {
|
||||
return new Controller\LogoutController(
|
||||
$container->get(LogoutService::class),
|
||||
$container->get(ResourceServer::class)
|
||||
);
|
||||
},
|
||||
Controller\RelationshipController::class => function (Container $container) {
|
||||
return new Controller\RelationshipController(
|
||||
$container->get(RelationshipService::class)
|
||||
);
|
||||
},
|
||||
], basename(__FILE__));
|
14
Api/V8/Config/services/factories.php
Normal file
14
Api/V8/Config/services/factories.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\Factory;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Factory\ParamsMiddlewareFactory::class => function (Container $container) {
|
||||
return new Factory\ParamsMiddlewareFactory($container);
|
||||
},
|
||||
Factory\ValidatorFactory::class => function (Container $container) {
|
||||
return new Factory\ValidatorFactory($container->get('Validation'));
|
||||
},
|
||||
], basename(__FILE__));
|
13
Api/V8/Config/services/globals.php
Normal file
13
Api/V8/Config/services/globals.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
'suiteConfig' => function () {
|
||||
global $sugar_config;
|
||||
return $sugar_config;
|
||||
},
|
||||
DBManager::class => function () {
|
||||
return DBManagerFactory::getInstance();
|
||||
},
|
||||
], basename(__FILE__));
|
27
Api/V8/Config/services/helpers.php
Normal file
27
Api/V8/Config/services/helpers.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\Helper;
|
||||
use Api\V8\JsonApi\Helper as ApiHelper;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Helper\VarDefHelper::class => function () {
|
||||
return new Helper\VarDefHelper();
|
||||
},
|
||||
ApiHelper\AttributeObjectHelper::class => function (Container $container) {
|
||||
return new ApiHelper\AttributeObjectHelper(
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
ApiHelper\RelationshipObjectHelper::class => function (Container $container) {
|
||||
return new ApiHelper\RelationshipObjectHelper(
|
||||
$container->get(Helper\VarDefHelper::class)
|
||||
);
|
||||
},
|
||||
ApiHelper\PaginationObjectHelper::class => function (Container $container) {
|
||||
return new ApiHelper\PaginationObjectHelper();
|
||||
},
|
||||
], basename(__FILE__));
|
66
Api/V8/Config/services/middlewares.php
Normal file
66
Api/V8/Config/services/middlewares.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
use Api\Core\Config\ApiConfig;
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\OAuth2\Entity\AccessTokenEntity;
|
||||
use Api\V8\OAuth2\Entity\ClientEntity;
|
||||
use Api\V8\OAuth2\Repository\AccessTokenRepository;
|
||||
use Api\V8\OAuth2\Repository\ClientRepository;
|
||||
use Api\V8\OAuth2\Repository\RefreshTokenRepository;
|
||||
use Api\V8\OAuth2\Repository\ScopeRepository;
|
||||
use Api\V8\OAuth2\Repository\UserRepository;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
AuthorizationServer::class => function (Container $container) {
|
||||
// base dir must exist in entryPoint.php
|
||||
$baseDir = $GLOBALS['BASE_DIR'];
|
||||
|
||||
$server = new AuthorizationServer(
|
||||
new ClientRepository(
|
||||
new ClientEntity(),
|
||||
$container->get(BeanManager::class)
|
||||
),
|
||||
new AccessTokenRepository(
|
||||
new AccessTokenEntity(),
|
||||
$container->get(BeanManager::class)
|
||||
),
|
||||
new ScopeRepository(),
|
||||
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PRIVATE_KEY),
|
||||
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PUBLIC_KEY)
|
||||
);
|
||||
$server->setEncryptionKey(ApiConfig::OAUTH2_ENCRYPTION_KEY);
|
||||
|
||||
// Client credentials grant
|
||||
$server->enableGrantType(
|
||||
new \League\OAuth2\Server\Grant\ClientCredentialsGrant(),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
// Password credentials grant
|
||||
$server->enableGrantType(
|
||||
new PasswordGrant(
|
||||
new UserRepository($container->get(BeanManager::class)),
|
||||
new RefreshTokenRepository($container->get(BeanManager::class))
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
ResourceServer::class => function (Container $container) {
|
||||
$baseDir = $GLOBALS['BASE_DIR'];
|
||||
|
||||
return new ResourceServer(
|
||||
new AccessTokenRepository(
|
||||
new AccessTokenEntity(),
|
||||
$container->get(BeanManager::class)
|
||||
),
|
||||
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PUBLIC_KEY)
|
||||
);
|
||||
},
|
||||
], basename(__FILE__));
|
76
Api/V8/Config/services/params.php
Normal file
76
Api/V8/Config/services/params.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\Factory\ValidatorFactory;
|
||||
use Api\V8\Param;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Param\ListViewSearchParams::class => function (Container $container) {
|
||||
return new Param\ListViewSearchParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\GetUserPreferencesParams::class => function (Container $container) {
|
||||
return new Param\GetUserPreferencesParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\ListViewColumnsParams::class => function (Container $container) {
|
||||
return new Param\ListViewColumnsParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\GetModuleParams::class => function (Container $container) {
|
||||
return new Param\GetModuleParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\GetModulesParams::class => function (Container $container) {
|
||||
return new Param\GetModulesParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\CreateModuleParams::class => function (Container $container) {
|
||||
return new Param\CreateModuleParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\UpdateModuleParams::class => function (Container $container) {
|
||||
return new Param\UpdateModuleParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\DeleteModuleParams::class => function (Container $container) {
|
||||
return new Param\DeleteModuleParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\GetRelationshipParams::class => function (Container $container) {
|
||||
return new Param\GetRelationshipParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\CreateRelationshipParams::class => function (Container $container) {
|
||||
return new Param\CreateRelationshipParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Param\DeleteRelationshipParams::class => function (Container $container) {
|
||||
return new Param\DeleteRelationshipParams(
|
||||
$container->get(ValidatorFactory::class),
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
], basename(__FILE__));
|
56
Api/V8/Config/services/services.php
Normal file
56
Api/V8/Config/services/services.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\PaginationObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||
use Api\V8\Service;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
Service\ListViewSearchService::class => function (Container $container) {
|
||||
return new Service\ListViewSearchService(
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Service\UserPreferencesService::class => function (Container $container) {
|
||||
return new Service\UserPreferencesService(
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Service\UserService::class => function (Container $container) {
|
||||
return new Service\UserService(
|
||||
$container->get(BeanManager::class),
|
||||
$container->get(AttributeObjectHelper::class),
|
||||
$container->get(RelationshipObjectHelper::class)
|
||||
);
|
||||
},
|
||||
Service\ListViewService::class => function (Container $container) {
|
||||
return new Service\ListViewService(
|
||||
$container->get(BeanManager::class),
|
||||
$container->get(AttributeObjectHelper::class),
|
||||
$container->get(RelationshipObjectHelper::class),
|
||||
$container->get(PaginationObjectHelper::class)
|
||||
);
|
||||
},
|
||||
Service\ModuleService::class => function (Container $container) {
|
||||
return new Service\ModuleService(
|
||||
$container->get(BeanManager::class),
|
||||
$container->get(AttributeObjectHelper::class),
|
||||
$container->get(RelationshipObjectHelper::class),
|
||||
$container->get(PaginationObjectHelper::class)
|
||||
);
|
||||
},
|
||||
Service\LogoutService::class => function (Container $container) {
|
||||
return new Service\LogoutService(
|
||||
$container->get(BeanManager::class)
|
||||
);
|
||||
},
|
||||
Service\RelationshipService::class => function (Container $container) {
|
||||
return new Service\RelationshipService(
|
||||
$container->get(BeanManager::class),
|
||||
$container->get(AttributeObjectHelper::class)
|
||||
);
|
||||
},
|
||||
], basename(__FILE__));
|
11
Api/V8/Config/services/validators.php
Normal file
11
Api/V8/Config/services/validators.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
use Api\Core\Loader\CustomLoader;
|
||||
|
||||
include_once __DIR__ . '/../../../../vendor/symfony/validator/ValidatorBuilder.php';
|
||||
|
||||
return CustomLoader::mergeCustomArray([
|
||||
'Validation' => function () {
|
||||
return (new Symfony\Component\Validator\ValidatorBuilder())->getValidator();
|
||||
},
|
||||
], basename(__FILE__));
|
52
Api/V8/Controller/BaseController.php
Normal file
52
Api/V8/Controller/BaseController.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
namespace Api\V8\Controller;
|
||||
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\JsonApi\Response\ErrorResponse;
|
||||
use Slim\Http\Response as HttpResponse;
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
const MEDIA_TYPE = 'application/vnd.api+json';
|
||||
|
||||
/**
|
||||
* @param HttpResponse $httpResponse
|
||||
* @param mixed $response
|
||||
* @param integer $status
|
||||
*
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public function generateResponse(
|
||||
HttpResponse $httpResponse,
|
||||
$response,
|
||||
$status
|
||||
) {
|
||||
return $httpResponse
|
||||
->withStatus($status)
|
||||
->withHeader('Accept', static::MEDIA_TYPE)
|
||||
->withHeader('Content-type', static::MEDIA_TYPE)
|
||||
->write(
|
||||
json_encode(
|
||||
$response,
|
||||
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HttpResponse $httpResponse
|
||||
* @param \Exception $exception
|
||||
* @param integer $status
|
||||
*
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public function generateErrorResponse(HttpResponse $httpResponse, \Exception $exception, $status)
|
||||
{
|
||||
$response = new ErrorResponse();
|
||||
$response->setStatus($status);
|
||||
$response->setDetail($exception->getMessage());
|
||||
$response->setException($exception);
|
||||
|
||||
return $this->generateResponse($httpResponse, $response, $status);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace Api\V8\Controller\InvocationStrategy;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\Interfaces\InvocationStrategyInterface;
|
||||
|
||||
class SuiteInvocationStrategy implements InvocationStrategyInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __invoke(
|
||||
callable $callable,
|
||||
ServerRequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
array $routeArguments
|
||||
) {
|
||||
foreach ($routeArguments as $attribute => $value) {
|
||||
$request = $request->withAttribute($attribute, $value);
|
||||
}
|
||||
|
||||
// since we support 5.5.9, we can't use splat op here
|
||||
return $callable(
|
||||
$request,
|
||||
$response,
|
||||
$routeArguments,
|
||||
$request->getAttribute('params') ? $request->getAttribute('params') : null
|
||||
);
|
||||
}
|
||||
}
|
95
Api/V8/Controller/ListViewController.php
Normal file
95
Api/V8/Controller/ListViewController.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?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 Api\V8\Controller;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
|
||||
|
||||
use Api\V8\Param\ListViewColumnsParams;
|
||||
use Api\V8\Service\ListViewService;
|
||||
use Api\V8\Service\ModuleService;
|
||||
use Exception;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* ListViewController
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ListViewService
|
||||
*/
|
||||
private $listViewService;
|
||||
|
||||
/**
|
||||
* @param ListViewService $listViewService
|
||||
*/
|
||||
public function __construct(ListViewService $listViewService)
|
||||
{
|
||||
$this->listViewService = $listViewService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param ListViewColumnsParams $params
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public function getListViewColumns(Request $request, Response $response, array $args, ListViewColumnsParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->listViewService->getListViewDefs($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
94
Api/V8/Controller/ListViewSearchController.php
Normal file
94
Api/V8/Controller/ListViewSearchController.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?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 Api\V8\Controller;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
|
||||
|
||||
use Api\V8\Param\ListViewSearchParams;
|
||||
use Api\V8\Service\ListViewSearchService;
|
||||
use Exception;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* ListViewSearchController
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewSearchController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ListViewSearchService
|
||||
*/
|
||||
private $listViewSearchService;
|
||||
|
||||
/**
|
||||
* @param ListViewSearchService $listViewSearchService
|
||||
*/
|
||||
public function __construct(ListViewSearchService $listViewSearchService)
|
||||
{
|
||||
$this->listViewSearchService = $listViewSearchService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param ListViewSearchParams $params
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public function getModuleSearchDefs(Request $request, Response $response, array $args, ListViewSearchParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->listViewSearchService->getListViewSearchDefs($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
51
Api/V8/Controller/LogoutController.php
Normal file
51
Api/V8/Controller/LogoutController.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
namespace Api\V8\Controller;
|
||||
|
||||
use Api\V8\Service\LogoutService;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class LogoutController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var LogoutService
|
||||
*/
|
||||
private $logoutService;
|
||||
|
||||
/**
|
||||
* @var ResourceServer
|
||||
*/
|
||||
private $resourceServer;
|
||||
|
||||
/**
|
||||
* @param LogoutService $logoutService
|
||||
* @param ResourceServer $resourceServer
|
||||
*/
|
||||
public function __construct(LogoutService $logoutService, ResourceServer $resourceServer)
|
||||
{
|
||||
$this->logoutService = $logoutService;
|
||||
$this->resourceServer = $resourceServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request, Response $response)
|
||||
{
|
||||
try {
|
||||
$accessToken = $this->resourceServer
|
||||
->validateAuthenticatedRequest($request)
|
||||
->getAttribute('oauth_access_token_id');
|
||||
|
||||
$logoutResponse = $this->logoutService->logout($accessToken);
|
||||
|
||||
return $this->generateResponse($response, $logoutResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
122
Api/V8/Controller/ModuleController.php
Normal file
122
Api/V8/Controller/ModuleController.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
namespace Api\V8\Controller;
|
||||
|
||||
use Api\V8\Param\CreateModuleParams;
|
||||
use Api\V8\Param\DeleteModuleParams;
|
||||
use Api\V8\Param\GetModuleParams;
|
||||
use Api\V8\Param\GetModulesParams;
|
||||
use Api\V8\Param\UpdateModuleParams;
|
||||
use Api\V8\Service\ModuleService;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class ModuleController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var ModuleService
|
||||
*/
|
||||
private $moduleService;
|
||||
|
||||
/**
|
||||
* @param ModuleService $moduleService
|
||||
*/
|
||||
public function __construct(ModuleService $moduleService)
|
||||
{
|
||||
$this->moduleService = $moduleService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param GetModuleParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getModuleRecord(Request $request, Response $response, array $args, GetModuleParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->moduleService->getRecord($params, $request->getUri()->getPath());
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param GetModulesParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getModuleRecords(Request $request, Response $response, array $args, GetModulesParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->moduleService->getRecords($params, $request);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param CreateModuleParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createModuleRecord(Request $request, Response $response, array $args, CreateModuleParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->moduleService->createRecord($params, $request);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 201);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param UpdateModuleParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function updateModuleRecord(Request $request, Response $response, array $args, UpdateModuleParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->moduleService->updateRecord($params, $request);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 201);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param DeleteModuleParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteModuleRecord(Request $request, Response $response, array $args, DeleteModuleParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->moduleService->deleteRecord($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
90
Api/V8/Controller/RelationshipController.php
Normal file
90
Api/V8/Controller/RelationshipController.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
namespace Api\V8\Controller;
|
||||
|
||||
use Api\V8\Param\CreateRelationshipParams;
|
||||
use Api\V8\Param\DeleteRelationshipParams;
|
||||
use Api\V8\Param\GetRelationshipParams;
|
||||
use Api\V8\Service\RelationshipService;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class RelationshipController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var RelationshipService
|
||||
*/
|
||||
private $relationshipService;
|
||||
|
||||
/**
|
||||
* @param RelationshipService $relationshipService
|
||||
*/
|
||||
public function __construct(RelationshipService $relationshipService)
|
||||
{
|
||||
$this->relationshipService = $relationshipService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param GetRelationshipParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRelationship(Request $request, Response $response, array $args, GetRelationshipParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->relationshipService->getRelationship($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param CreateRelationshipParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createRelationship(
|
||||
Request $request,
|
||||
Response $response,
|
||||
array $args,
|
||||
CreateRelationshipParams $params
|
||||
) {
|
||||
try {
|
||||
$jsonResponse = $this->relationshipService->createRelationship($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 201);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param DeleteRelationshipParams $params
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteRelationship(
|
||||
Request $request,
|
||||
Response $response,
|
||||
array $args,
|
||||
DeleteRelationshipParams $params
|
||||
) {
|
||||
try {
|
||||
$jsonResponse = $this->relationshipService->deleteRelationship($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
89
Api/V8/Controller/UserController.php
Normal file
89
Api/V8/Controller/UserController.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?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 Api\V8\Controller;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
use Api\V8\Service\UserService;
|
||||
use Exception;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* UserController
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class UserController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var UserService
|
||||
*/
|
||||
private $userService;
|
||||
|
||||
/**
|
||||
* @param UserService $userService
|
||||
*/
|
||||
public function __construct(UserService $userService)
|
||||
{
|
||||
$this->userService = $userService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @return Response
|
||||
*/
|
||||
public function getCurrentUser(Request $request, Response $response, array $args)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->userService->getCurrentUser($request);
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
94
Api/V8/Controller/UserPreferencesController.php
Normal file
94
Api/V8/Controller/UserPreferencesController.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?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 Api\V8\Controller;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
|
||||
|
||||
use Api\V8\Param\GetUserPreferencesParams;
|
||||
use Api\V8\Service\UserPreferencesService;
|
||||
use Exception;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* UserPreferencesController
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class UserPreferencesController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var UserPreferencesService
|
||||
*/
|
||||
private $userPreferencesService;
|
||||
|
||||
/**
|
||||
* @param UserPreferencesService $userPreferencesService
|
||||
*/
|
||||
public function __construct(UserPreferencesService $userPreferencesService)
|
||||
{
|
||||
$this->userPreferencesService = $userPreferencesService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $args
|
||||
* @param GetUserPreferencesParams $params
|
||||
* @return Response
|
||||
*/
|
||||
public function getUserPreferences(Request $request, Response $response, array $args, GetUserPreferencesParams $params)
|
||||
{
|
||||
try {
|
||||
$jsonResponse = $this->userPreferencesService->getUserPreferences($params);
|
||||
|
||||
return $this->generateResponse($response, $jsonResponse, 200);
|
||||
} catch (Exception $exception) {
|
||||
return $this->generateErrorResponse($response, $exception, 400);
|
||||
}
|
||||
}
|
||||
}
|
39
Api/V8/Factory/ParamsMiddlewareFactory.php
Normal file
39
Api/V8/Factory/ParamsMiddlewareFactory.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace Api\V8\Factory;
|
||||
|
||||
use Api\V8\Middleware\ParamsMiddleware;
|
||||
use Interop\Container\ContainerInterface as Container;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class ParamsMiddlewareFactory
|
||||
{
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @param Container $container
|
||||
*/
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $containerId
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function bind($containerId)
|
||||
{
|
||||
$container = $this->container;
|
||||
|
||||
return function (Request $request, Response $response, callable $next) use ($containerId, $container) {
|
||||
$paramMiddleware = new ParamsMiddleware($container->get($containerId));
|
||||
|
||||
return $paramMiddleware($request, $response, $next);
|
||||
};
|
||||
}
|
||||
}
|
66
Api/V8/Factory/ValidatorFactory.php
Normal file
66
Api/V8/Factory/ValidatorFactory.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
namespace Api\V8\Factory;
|
||||
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class ValidatorFactory
|
||||
{
|
||||
/**
|
||||
* @var ValidatorInterface
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* @param ValidatorInterface $validator
|
||||
*/
|
||||
public function __construct(ValidatorInterface $validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Validator\Constraint[] $constraints
|
||||
* @param boolean $allowNull
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
public function createClosure(array $constraints, $allowNull = false)
|
||||
{
|
||||
return function ($value) use ($constraints, $allowNull) {
|
||||
if ($allowNull && $value === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$violations = $this->validator->validate($value, $constraints);
|
||||
|
||||
return !$violations->count();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Validator\Constraint[] $constraints
|
||||
* @param boolean $allowNull
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
public function createClosureForIterator(array $constraints, $allowNull = false)
|
||||
{
|
||||
return function ($value) use ($constraints, $allowNull) {
|
||||
if ($allowNull && $value === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_array($value) && !$value instanceof \Iterator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($value as $v) {
|
||||
if ($this->validator->validate($v, $constraints)->count()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
24
Api/V8/Helper/VarDefHelper.php
Normal file
24
Api/V8/Helper/VarDefHelper.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
namespace Api\V8\Helper;
|
||||
|
||||
class VarDefHelper
|
||||
{
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllRelationships(\SugarBean $bean)
|
||||
{
|
||||
$relations = [];
|
||||
$linkedFields = $bean->get_linked_fields();
|
||||
|
||||
foreach ($linkedFields as $relation => $varDef) {
|
||||
if (isset($varDef['module']) && $bean->load_relationship($relation)) {
|
||||
$relations[$relation] = $varDef['module'];
|
||||
}
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
}
|
49
Api/V8/JsonApi/Helper/AttributeObjectHelper.php
Normal file
49
Api/V8/JsonApi/Helper/AttributeObjectHelper.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Helper;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||
|
||||
class AttributeObjectHelper
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(BeanManager $beanManager)
|
||||
{
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
* @param array|null $fields
|
||||
*
|
||||
* @return AttributeResponse
|
||||
*/
|
||||
public function getAttributes(\SugarBean $bean, $fields = null)
|
||||
{
|
||||
$bean->fixUpFormatting();
|
||||
|
||||
// using the ISO 8601 format for dates
|
||||
$attributes = array_map(function ($value) {
|
||||
return is_string($value)
|
||||
? (\DateTime::createFromFormat('Y-m-d H:i:s', $value)
|
||||
? date(\DateTime::ATOM, strtotime($value))
|
||||
: $value)
|
||||
: $value;
|
||||
}, $bean->toArray());
|
||||
|
||||
if ($fields !== null) {
|
||||
$attributes = array_intersect_key($attributes, array_flip($fields));
|
||||
}
|
||||
|
||||
unset($attributes['id']);
|
||||
|
||||
return new AttributeResponse($attributes);
|
||||
}
|
||||
}
|
60
Api/V8/JsonApi/Helper/PaginationObjectHelper.php
Normal file
60
Api/V8/JsonApi/Helper/PaginationObjectHelper.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Helper;
|
||||
|
||||
use Api\V8\JsonApi\Response\MetaResponse;
|
||||
use Api\V8\JsonApi\Response\PaginationResponse;
|
||||
use Slim\Http\Request;
|
||||
|
||||
class PaginationObjectHelper
|
||||
{
|
||||
/**
|
||||
* @param integer $totalPages
|
||||
* @param integer $numOfRecords
|
||||
*
|
||||
* @return MetaResponse
|
||||
*/
|
||||
public function getPaginationMeta($totalPages, $numOfRecords)
|
||||
{
|
||||
return new MetaResponse(
|
||||
['total-pages' => $totalPages, 'records-on-this-page' => $numOfRecords]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param integer $totalPages
|
||||
* @param integer $number
|
||||
*
|
||||
* @return PaginationResponse
|
||||
*/
|
||||
public function getPaginationLinks(Request $request, $totalPages, $number)
|
||||
{
|
||||
$pagination = new PaginationResponse();
|
||||
|
||||
if ($number > 1) {
|
||||
$pagination->setFirst($this->createPaginationLink($request, 1));
|
||||
$pagination->setPrev($this->createPaginationLink($request, $number - 1));
|
||||
}
|
||||
|
||||
if ($number + 1 <= $totalPages) {
|
||||
$pagination->setNext($this->createPaginationLink($request, $number + 1));
|
||||
$pagination->setLast($this->createPaginationLink($request, $totalPages));
|
||||
}
|
||||
|
||||
return $pagination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param integer $number
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createPaginationLink(Request $request, $number)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
$queryParams['page']['number'] = $number;
|
||||
|
||||
return sprintf('/%s?%s', $request->getUri()->getPath(), urldecode(http_build_query($queryParams)));
|
||||
}
|
||||
}
|
46
Api/V8/JsonApi/Helper/RelationshipObjectHelper.php
Normal file
46
Api/V8/JsonApi/Helper/RelationshipObjectHelper.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Helper;
|
||||
|
||||
use Api\V8\Helper\VarDefHelper;
|
||||
use Api\V8\JsonApi\Response\LinksResponse;
|
||||
use Api\V8\JsonApi\Response\RelationshipResponse;
|
||||
|
||||
class RelationshipObjectHelper
|
||||
{
|
||||
/**
|
||||
* @var VarDefHelper
|
||||
*/
|
||||
private $varDefHelper;
|
||||
|
||||
/**
|
||||
* @param VarDefHelper $varDefHelper
|
||||
*/
|
||||
public function __construct(VarDefHelper $varDefHelper)
|
||||
{
|
||||
$this->varDefHelper = $varDefHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
* @param string $uriPath
|
||||
*
|
||||
* @return RelationshipResponse
|
||||
*/
|
||||
public function getRelationships(\SugarBean $bean, $uriPath)
|
||||
{
|
||||
$relationships = $this->varDefHelper->getAllRelationships($bean);
|
||||
asort($relationships);
|
||||
|
||||
$relationshipsLinks = [];
|
||||
foreach (array_unique($relationships) as $module) {
|
||||
$linkResponse = new LinksResponse();
|
||||
$linkResponse->setRelated(
|
||||
sprintf('/%s/%s/%s', $uriPath, 'relationships', strtolower($module))
|
||||
);
|
||||
|
||||
$relationshipsLinks[$module] = ['links' => $linkResponse];
|
||||
}
|
||||
|
||||
return new RelationshipResponse($relationshipsLinks);
|
||||
}
|
||||
}
|
89
Api/V8/JsonApi/Repository/Filter.php
Normal file
89
Api/V8/JsonApi/Repository/Filter.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Repository;
|
||||
|
||||
class Filter
|
||||
{
|
||||
// operators so far
|
||||
const OP_EQ = '=';
|
||||
const OP_NEQ = '<>';
|
||||
const OP_GT = '>';
|
||||
const OP_GTE = '>=';
|
||||
const OP_LT = '<';
|
||||
const OP_LTE = '<=';
|
||||
|
||||
const OP_AND = 'AND';
|
||||
const OP_OR = 'OR';
|
||||
|
||||
/**
|
||||
* @var \DBManager
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param \DBManager $db
|
||||
*/
|
||||
public function __construct(\DBManager $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException When field is not found or is not an array.
|
||||
*/
|
||||
public function parseWhere(\SugarBean $bean, array $params)
|
||||
{
|
||||
$operator = self::OP_AND;
|
||||
if (isset($params['operator'])) {
|
||||
$this->checkOperator($params['operator']);
|
||||
$operator = strtoupper($params['operator']);
|
||||
unset($params['operator']);
|
||||
}
|
||||
|
||||
$where = [];
|
||||
foreach ($params as $field => $expr) {
|
||||
if (!property_exists($bean, $field)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Filter field %s in %s module is not found',
|
||||
$field,
|
||||
$bean->getObjectName()
|
||||
));
|
||||
}
|
||||
|
||||
if (!is_array($expr)) {
|
||||
throw new \InvalidArgumentException(sprintf('Filter field %s must be an array', $field));
|
||||
}
|
||||
|
||||
foreach ($expr as $op => $value) {
|
||||
$this->checkOperator($op);
|
||||
$where[] = sprintf(
|
||||
'%s.%s %s %s',
|
||||
$bean->getTableName(),
|
||||
$field,
|
||||
constant(sprintf('%s::OP_%s', self::class, strtoupper($op))),
|
||||
$this->db->quoted($value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(sprintf(' %s ', $operator), $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $op
|
||||
*
|
||||
* @throws \InvalidArgumentException When the given operator is invalid.
|
||||
*/
|
||||
private function checkOperator($op)
|
||||
{
|
||||
$operator = sprintf('%s::OP_%s', self::class, strtoupper($op));
|
||||
if (!defined($operator)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Filter operator %s is invalid', $op)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
36
Api/V8/JsonApi/Repository/Sort.php
Normal file
36
Api/V8/JsonApi/Repository/Sort.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Repository;
|
||||
|
||||
class Sort
|
||||
{
|
||||
const ORDER_BY_ASC = 'ASC';
|
||||
const ORDER_BY_DESC = 'DESC';
|
||||
|
||||
/**
|
||||
* We don't support multiple sorting. for now.
|
||||
*
|
||||
* @param \SugarBean $bean
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException When sort field is not found in the bean.
|
||||
*/
|
||||
public function parseOrderBy(\SugarBean $bean, $value)
|
||||
{
|
||||
$orderBy = self::ORDER_BY_ASC;
|
||||
if ($value[0] === '-') {
|
||||
$orderBy = self::ORDER_BY_DESC;
|
||||
$value = ltrim($value, '-');
|
||||
}
|
||||
|
||||
if (!property_exists($bean, $value)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Sort field %s in %s module is not found',
|
||||
$value,
|
||||
$bean->getObjectName()
|
||||
));
|
||||
}
|
||||
|
||||
return sprintf('%s %s', $value, $orderBy);
|
||||
}
|
||||
}
|
29
Api/V8/JsonApi/Response/AttributeResponse.php
Normal file
29
Api/V8/JsonApi/Response/AttributeResponse.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class AttributeResponse extends MetaResponse
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @see http://jsonapi.org/format/#document-resource-object-attributes
|
||||
*/
|
||||
private static $forbiddenKeys = ['relationships', 'links'];
|
||||
|
||||
/**
|
||||
* @param array|\stdClass $properties
|
||||
*
|
||||
* @throws \InvalidArgumentException When attribute object includes forbidden keys.
|
||||
*/
|
||||
public function __construct($properties = [])
|
||||
{
|
||||
parent::__construct($properties);
|
||||
|
||||
$invalidKeys = array_intersect_key($properties, array_flip(self::$forbiddenKeys));
|
||||
if ($invalidKeys) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Attribute object must not contain these keys: ' . implode(', ', array_keys($invalidKeys))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
120
Api/V8/JsonApi/Response/DataResponse.php
Normal file
120
Api/V8/JsonApi/Response/DataResponse.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class DataResponse implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var AttributeResponse
|
||||
*/
|
||||
private $attributes;
|
||||
|
||||
/**
|
||||
* @var RelationshipResponse
|
||||
*/
|
||||
private $relationships;
|
||||
|
||||
/**
|
||||
* @var LinksResponse
|
||||
*/
|
||||
private $links;
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $id
|
||||
*/
|
||||
public function __construct($type, $id)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AttributeResponse
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AttributeResponse $attributes
|
||||
*/
|
||||
public function setAttributes(AttributeResponse $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RelationshipResponse
|
||||
*/
|
||||
public function getRelationships()
|
||||
{
|
||||
return $this->relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RelationshipResponse $relationships
|
||||
*/
|
||||
public function setRelationships(RelationshipResponse $relationships)
|
||||
{
|
||||
$this->relationships = $relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LinksResponse
|
||||
*/
|
||||
public function getLinks()
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LinksResponse $links
|
||||
*/
|
||||
public function setLinks(LinksResponse $links)
|
||||
{
|
||||
$this->links = $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$response = [
|
||||
'type' => $this->getType(),
|
||||
'id' => $this->getId(),
|
||||
'attributes' => $this->getAttributes(),
|
||||
'relationships' => $this->getRelationships(),
|
||||
'links' => $this->getLinks()
|
||||
];
|
||||
|
||||
return array_filter($response);
|
||||
}
|
||||
}
|
92
Api/V8/JsonApi/Response/DocumentResponse.php
Normal file
92
Api/V8/JsonApi/Response/DocumentResponse.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class DocumentResponse implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array|DataResponse|DataResponse[]
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
/**
|
||||
* @var MetaResponse
|
||||
*/
|
||||
private $meta;
|
||||
|
||||
/**
|
||||
* @var LinksResponse
|
||||
*/
|
||||
private $links;
|
||||
|
||||
/**
|
||||
* @return array|DataResponse|DataResponse[]
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|DataResponse|DataResponse[] $data
|
||||
*/
|
||||
public function setData($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MetaResponse
|
||||
*/
|
||||
public function getMeta()
|
||||
{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MetaResponse $meta
|
||||
*/
|
||||
public function setMeta(MetaResponse $meta)
|
||||
{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LinksResponse
|
||||
*/
|
||||
public function getLinks()
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LinksResponse $links
|
||||
*/
|
||||
public function setLinks(LinksResponse $links)
|
||||
{
|
||||
$this->links = $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$response = [
|
||||
'data' => $this->getData()
|
||||
];
|
||||
|
||||
if (!$this->getData() && !$this->getMeta()) {
|
||||
$this->setMeta(new MetaResponse(['message' => 'Request was successful, but there is no result']));
|
||||
}
|
||||
|
||||
if ($this->getMeta()) {
|
||||
$response = ['meta' => $this->getMeta()] + $response;
|
||||
}
|
||||
|
||||
if ($this->getLinks()) {
|
||||
$response['links'] = $this->getLinks();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
158
Api/V8/JsonApi/Response/ErrorResponse.php
Normal file
158
Api/V8/JsonApi/Response/ErrorResponse.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
use Api\Core\Config\ApiConfig;
|
||||
use Exception;
|
||||
use JsonSerializable;
|
||||
|
||||
class ErrorResponse implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $detail;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Exception
|
||||
*/
|
||||
private $exception;
|
||||
|
||||
/**
|
||||
* In debug mode, ErrorResponse should shows full description about occurred exceptions.
|
||||
*
|
||||
* @todo documentation needs to be updated at this point (about debug exceptions)
|
||||
* @var boolean
|
||||
*/
|
||||
protected $debugExceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bool|null $debugExceptions optional - using ApiConfig setting by default
|
||||
*/
|
||||
public function __construct($debugExceptions = null)
|
||||
{
|
||||
$this->debugExceptions =
|
||||
null === $debugExceptions ?
|
||||
ApiConfig::getDebugExceptions() :
|
||||
$debugExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $status
|
||||
*/
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDetail()
|
||||
{
|
||||
return $this->detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $detail
|
||||
*/
|
||||
public function setDetail($detail)
|
||||
{
|
||||
$this->detail = $detail;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Exception $exception
|
||||
*/
|
||||
public function setException(Exception $exception)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Exception $exception
|
||||
* @return array
|
||||
*/
|
||||
protected static function exceptionToArray(Exception $exception)
|
||||
{
|
||||
return [
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'message' => $exception->getMessage(),
|
||||
'previous' => self::exceptionToArray($exception->getPrevious()),
|
||||
'trace' => $exception->getTrace(),
|
||||
'traceAsString' => $exception->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExceptionArray()
|
||||
{
|
||||
if (!$this->exception) {
|
||||
return null;
|
||||
}
|
||||
return self::exceptionToArray($this->exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$ret = [
|
||||
'errors' => [
|
||||
'status' => $this->getStatus(),
|
||||
'title' => $this->getTitle(),
|
||||
'detail' => $this->getDetail(),
|
||||
]
|
||||
];
|
||||
|
||||
// do it only in debug mode!!!!
|
||||
if ($this->debugExceptions) {
|
||||
$ret['errors']['exception'] = $this->getExceptionArray();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
60
Api/V8/JsonApi/Response/LinksResponse.php
Normal file
60
Api/V8/JsonApi/Response/LinksResponse.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class LinksResponse implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $self;
|
||||
|
||||
/**
|
||||
* @var string|array
|
||||
*/
|
||||
private $related;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSelf()
|
||||
{
|
||||
return $this->self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $self
|
||||
*/
|
||||
public function setSelf($self)
|
||||
{
|
||||
$this->self = $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string
|
||||
*/
|
||||
public function getRelated()
|
||||
{
|
||||
return $this->related;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $related
|
||||
*/
|
||||
public function setRelated($related)
|
||||
{
|
||||
$this->related = $related;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$response = [
|
||||
'self' => $this->getSelf(),
|
||||
'related' => $this->getRelated()
|
||||
];
|
||||
|
||||
return array_filter($response);
|
||||
}
|
||||
}
|
55
Api/V8/JsonApi/Response/MetaResponse.php
Normal file
55
Api/V8/JsonApi/Response/MetaResponse.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class MetaResponse implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* Meta object can contain any properties.
|
||||
*
|
||||
* @param array|\stdClass $properties
|
||||
*
|
||||
* @throws \InvalidArgumentException When bean is not found with the given id.
|
||||
*/
|
||||
public function __construct($properties = [])
|
||||
{
|
||||
if (!is_array($properties) && !$properties instanceof \stdClass) {
|
||||
throw new \InvalidArgumentException('The properties must be an array or sdtClass');
|
||||
}
|
||||
|
||||
foreach ($properties as $property => $value) {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return isset($this->properties[$name]) ? $this->properties[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->properties[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
}
|
102
Api/V8/JsonApi/Response/PaginationResponse.php
Normal file
102
Api/V8/JsonApi/Response/PaginationResponse.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class PaginationResponse extends LinksResponse
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $first;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $prev;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $next;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $last;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFirst()
|
||||
{
|
||||
return $this->first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $first
|
||||
*/
|
||||
public function setFirst($first)
|
||||
{
|
||||
$this->first = $first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPrev()
|
||||
{
|
||||
return $this->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prev
|
||||
*/
|
||||
public function setPrev($prev)
|
||||
{
|
||||
$this->prev = $prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNext()
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $next
|
||||
*/
|
||||
public function setNext($next)
|
||||
{
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLast()
|
||||
{
|
||||
return $this->last;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $last
|
||||
*/
|
||||
public function setLast($last)
|
||||
{
|
||||
$this->last = $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return [
|
||||
'first' => $this->getFirst(),
|
||||
'prev' => $this->getPrev(),
|
||||
'next' => $this->getNext(),
|
||||
'last' => $this->getLast()
|
||||
];
|
||||
}
|
||||
}
|
6
Api/V8/JsonApi/Response/RelationshipResponse.php
Normal file
6
Api/V8/JsonApi/Response/RelationshipResponse.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
namespace Api\V8\JsonApi\Response;
|
||||
|
||||
class RelationshipResponse extends MetaResponse
|
||||
{
|
||||
}
|
83
Api/V8/Middleware/ParamsMiddleware.php
Normal file
83
Api/V8/Middleware/ParamsMiddleware.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
namespace Api\V8\Middleware;
|
||||
|
||||
use Api\V8\JsonApi\Response\ErrorResponse;
|
||||
use Api\V8\Param\BaseParam;
|
||||
use Exception;
|
||||
use LoggerManager;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class ParamsMiddleware
|
||||
{
|
||||
/**
|
||||
* @var BaseParam
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* @param BaseParam $params
|
||||
*/
|
||||
public function __construct(BaseParam $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $httpResponse
|
||||
* @param callable $next
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request, Response $httpResponse, callable $next)
|
||||
{
|
||||
try {
|
||||
$parameters = $this->getParameters($request);
|
||||
$this->params->configure($parameters);
|
||||
$request = $request->withAttribute('params', $this->params);
|
||||
} catch (Exception $exception) {
|
||||
$response = new ErrorResponse();
|
||||
$response->setStatus(400);
|
||||
$msg = $exception->getMessage();
|
||||
$dbg = "\nCode:" . $exception->getCode() .
|
||||
"\n" . $exception->getFile() . ':' . $exception->getLine() .
|
||||
"\nTrace:\n" . $exception->getTraceAsString() .
|
||||
"\n";
|
||||
LoggerManager::getLogger()->fatal("API Exception detected:\nMessage was: $msg\nException details:\n$dbg");
|
||||
$response->setDetail($msg);
|
||||
|
||||
return $httpResponse->withJson(
|
||||
$response,
|
||||
400,
|
||||
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
);
|
||||
}
|
||||
|
||||
return $next($request, $httpResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getParameters(Request $request)
|
||||
{
|
||||
$routeParams = array_map(
|
||||
function ($value) {
|
||||
return is_bool($value) ? $value : urldecode($value);
|
||||
},
|
||||
$request->getAttribute('route')->getArguments()
|
||||
);
|
||||
|
||||
$queryParams = $request->getQueryParams();
|
||||
$parsedBody = $request->getParsedBody();
|
||||
|
||||
return array_merge(
|
||||
$routeParams,
|
||||
isset($queryParams) ? $queryParams : [],
|
||||
isset($parsedBody) ? $parsedBody : []
|
||||
);
|
||||
}
|
||||
}
|
2
Api/V8/OAuth2/.gitignore
vendored
Normal file
2
Api/V8/OAuth2/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
private.key
|
||||
public.key
|
12
Api/V8/OAuth2/Entity/AccessTokenEntity.php
Normal file
12
Api/V8/OAuth2/Entity/AccessTokenEntity.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Entity;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AccessTokenEntity implements AccessTokenEntityInterface
|
||||
{
|
||||
use AccessTokenTrait, TokenEntityTrait, EntityTrait;
|
||||
}
|
27
Api/V8/OAuth2/Entity/ClientEntity.php
Normal file
27
Api/V8/OAuth2/Entity/ClientEntity.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Entity;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\ClientTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class ClientEntity implements ClientEntityInterface
|
||||
{
|
||||
use EntityTrait, ClientTrait;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setRedirectUri($uri)
|
||||
{
|
||||
$this->redirectUri = $uri;
|
||||
}
|
||||
}
|
11
Api/V8/OAuth2/Entity/RefreshTokenEntity.php
Normal file
11
Api/V8/OAuth2/Entity/RefreshTokenEntity.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Entity;
|
||||
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||
|
||||
class RefreshTokenEntity implements RefreshTokenEntityInterface
|
||||
{
|
||||
use RefreshTokenTrait, EntityTrait;
|
||||
}
|
16
Api/V8/OAuth2/Entity/UserEntity.php
Normal file
16
Api/V8/OAuth2/Entity/UserEntity.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Entity;
|
||||
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
|
||||
class UserEntity implements UserEntityInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
// we skip this right now, since we are not using scopes atm
|
||||
return true;
|
||||
}
|
||||
}
|
99
Api/V8/OAuth2/Repository/AccessTokenRepository.php
Normal file
99
Api/V8/OAuth2/Repository/AccessTokenRepository.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Repository;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\OAuth2\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
|
||||
class AccessTokenRepository implements AccessTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var AccessTokenEntity
|
||||
*/
|
||||
private $accessTokenEntity;
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param AccessTokenEntity $accessTokenEntity
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(AccessTokenEntity $accessTokenEntity, BeanManager $beanManager)
|
||||
{
|
||||
$this->accessTokenEntity = $accessTokenEntity;
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
|
||||
{
|
||||
$this->accessTokenEntity->setClient($clientEntity);
|
||||
|
||||
// we keep this even we don't have scopes atm
|
||||
foreach ($scopes as $scope) {
|
||||
$this->accessTokenEntity->addScope($scope);
|
||||
}
|
||||
|
||||
$this->accessTokenEntity->setUserIdentifier($userIdentifier);
|
||||
|
||||
return $this->accessTokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
|
||||
{
|
||||
/** @var \OAuth2Tokens $token */
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->access_token = $accessTokenEntity->getIdentifier();
|
||||
$token->access_token_expires = $accessTokenEntity->getExpiryDateTime()->format('Y-m-d H:i:s');
|
||||
$token->client = $accessTokenEntity->getClient()->getIdentifier();
|
||||
|
||||
$token->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws \InvalidArgumentException When access token is not found.
|
||||
*/
|
||||
public function revokeAccessToken($tokenId)
|
||||
{
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['access_token' => $tokenId]
|
||||
);
|
||||
|
||||
if ($token->id === null) {
|
||||
throw new \InvalidArgumentException('Access token is not found for this client');
|
||||
}
|
||||
|
||||
$token->mark_deleted($token->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId)
|
||||
{
|
||||
/** @var \OAuth2Tokens $token */
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['access_token' => $tokenId]
|
||||
);
|
||||
|
||||
if (new \DateTime() > new \DateTime($token->access_token_expires) || $token->id === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
47
Api/V8/OAuth2/Repository/ClientRepository.php
Normal file
47
Api/V8/OAuth2/Repository/ClientRepository.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Repository;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\OAuth2\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
|
||||
class ClientRepository implements ClientRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var ClientEntity
|
||||
*/
|
||||
private $clientEntity;
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param ClientEntity $clientEntity
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(ClientEntity $clientEntity, BeanManager $beanManager)
|
||||
{
|
||||
$this->clientEntity = $clientEntity;
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true)
|
||||
{
|
||||
/** @var \OAuth2Clients $client */
|
||||
$client = $this->beanManager->getBeanSafe(\OAuth2Clients::class, $clientIdentifier);
|
||||
if ($mustValidateSecret && hash('sha256', $clientSecret) !== $client->secret) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->clientEntity->setIdentifier($clientIdentifier);
|
||||
$this->clientEntity->setName($client->name);
|
||||
$this->clientEntity->setRedirectUri(isset($client->redirect_uri) ? $client->redirect_uri : '');
|
||||
|
||||
return $this->clientEntity;
|
||||
}
|
||||
}
|
90
Api/V8/OAuth2/Repository/RefreshTokenRepository.php
Normal file
90
Api/V8/OAuth2/Repository/RefreshTokenRepository.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Repository;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\OAuth2\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
|
||||
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(BeanManager $beanManager)
|
||||
{
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getNewRefreshToken()
|
||||
{
|
||||
return new RefreshTokenEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws \InvalidArgumentException When access token is not found.
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
|
||||
{
|
||||
/** @var \OAuth2Tokens $token */
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['access_token' => $refreshTokenEntity->getAccessToken()->getIdentifier()]
|
||||
);
|
||||
|
||||
if ($token->id === null) {
|
||||
throw new \InvalidArgumentException('Access token is not found for this client');
|
||||
}
|
||||
|
||||
$token->refresh_token = $refreshTokenEntity->getIdentifier();
|
||||
$token->refresh_token_expires = $refreshTokenEntity->getExpiryDateTime()->format('Y-m-d H:i:s');
|
||||
$token->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws \InvalidArgumentException When refresh token is not found.
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId)
|
||||
{
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['refresh_token' => $tokenId]
|
||||
);
|
||||
|
||||
if ($token->id === null) {
|
||||
throw new \InvalidArgumentException('Refresh token is not found for this client');
|
||||
}
|
||||
|
||||
$token->mark_deleted($token->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId)
|
||||
{
|
||||
/** @var \OAuth2Tokens $token */
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['refresh_token' => $tokenId]
|
||||
);
|
||||
|
||||
if (new \DateTime() > new \DateTime($token->refresh_token_expires) || $token->id === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
28
Api/V8/OAuth2/Repository/ScopeRepository.php
Normal file
28
Api/V8/OAuth2/Repository/ScopeRepository.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Repository;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
|
||||
class ScopeRepository implements ScopeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($identifier)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity,
|
||||
$userIdentifier = null
|
||||
) {
|
||||
// we just return scopes for now
|
||||
return $scopes;
|
||||
}
|
||||
}
|
51
Api/V8/OAuth2/Repository/UserRepository.php
Normal file
51
Api/V8/OAuth2/Repository/UserRepository.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
namespace Api\V8\OAuth2\Repository;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\OAuth2\Entity\UserEntity;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
|
||||
class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(BeanManager $beanManager)
|
||||
{
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws \InvalidArgumentException If user does not exist or the password is invalid.
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity
|
||||
) {
|
||||
/** @var \User $user */
|
||||
$user = $this->beanManager->newBeanSafe('Users');
|
||||
$user->retrieve_by_string_fields(
|
||||
['user_name' => $username]
|
||||
);
|
||||
|
||||
if ($user->id === null) {
|
||||
throw new \InvalidArgumentException('No user found with this username: ' . $username);
|
||||
}
|
||||
|
||||
if (!\User::checkPassword($password, $user->user_hash)) {
|
||||
throw new \InvalidArgumentException('The password is invalid: ' . $password);
|
||||
}
|
||||
|
||||
return new UserEntity();
|
||||
}
|
||||
}
|
98
Api/V8/Param/BaseParam.php
Normal file
98
Api/V8/Param/BaseParam.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\Factory\ValidatorFactory;
|
||||
use Api\V8\Param\Options\BaseOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
abstract class BaseParam implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @var ValidatorFactory
|
||||
*/
|
||||
protected $validatorFactory;
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
protected $beanManager;
|
||||
|
||||
/**
|
||||
* @param ValidatorFactory $validatorFactory
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(ValidatorFactory $validatorFactory, BeanManager $beanManager)
|
||||
{
|
||||
$this->validatorFactory = $validatorFactory;
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
final public function configure(array $arguments)
|
||||
{
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$this->setDefined($optionsResolver, $arguments);
|
||||
$this->configureParameters($optionsResolver);
|
||||
$this->parameters = $optionsResolver->resolve($arguments);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* We can overwrite this method, if necessary
|
||||
*
|
||||
* @param OptionsResolver $resolver
|
||||
* @param array $arguments
|
||||
*/
|
||||
public function setDefined(OptionsResolver $resolver, array $arguments)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure parameters.
|
||||
*
|
||||
* @param OptionsResolver $resolver
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function configureParameters(OptionsResolver $resolver);
|
||||
|
||||
/**
|
||||
* Configure already defined options.
|
||||
*
|
||||
* @param OptionsResolver $optionResolver
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \InvalidArgumentException If option is not exist.
|
||||
*/
|
||||
protected function setOptions(OptionsResolver $optionResolver, array $options)
|
||||
{
|
||||
foreach ($options as $key => $option) {
|
||||
if (!class_exists($option)) {
|
||||
throw new \InvalidArgumentException(sprintf('Option %s does not exist!', $option));
|
||||
}
|
||||
|
||||
/** @var BaseOption $class */
|
||||
$class = new $option($this->validatorFactory, $this->beanManager);
|
||||
$class->add($optionResolver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
}
|
56
Api/V8/Param/CreateModuleDataParams.php
Normal file
56
Api/V8/Param/CreateModuleDataParams.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CreateModuleDataParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->parameters['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return isset($this->parameters['id']) ? $this->parameters['id'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return isset($this->parameters['attributes']) ? $this->parameters['attributes'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
// need to make this more simple
|
||||
$resolver
|
||||
->setDefined('id')
|
||||
->setAllowedTypes('id', 'string')
|
||||
->setAllowedValues('id', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Uuid(['strict' => false]),
|
||||
]));
|
||||
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\Type::class,
|
||||
ParamOption\Attributes::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
36
Api/V8/Param/CreateModuleParams.php
Normal file
36
Api/V8/Param/CreateModuleParams.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CreateModuleParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return CreateModuleDataParams
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->parameters['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('data')
|
||||
->setAllowedTypes('data', 'array')
|
||||
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
]))
|
||||
->setNormalizer('data', function (Options $options, $values) {
|
||||
$dataParams = new CreateModuleDataParams($this->validatorFactory, $this->beanManager);
|
||||
$dataParams->configure($values);
|
||||
|
||||
return $dataParams;
|
||||
});
|
||||
}
|
||||
}
|
99
Api/V8/Param/CreateRelationshipParams.php
Normal file
99
Api/V8/Param/CreateRelationshipParams.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CreateRelationshipParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GetRelationshipDataParams
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->parameters['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SugarBean
|
||||
*/
|
||||
public function getSourceBean()
|
||||
{
|
||||
return $this->parameters['sourceBean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SugarBean
|
||||
*/
|
||||
public function getRelatedBean()
|
||||
{
|
||||
return $this->parameters['relatedBean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Id::class,
|
||||
]
|
||||
);
|
||||
|
||||
$resolver
|
||||
->setRequired('data')
|
||||
->setAllowedTypes('data', 'array')
|
||||
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
]))
|
||||
->setNormalizer('data', function (Options $options, $value) {
|
||||
$dataParams = new GetRelationshipDataParams($this->validatorFactory, $this->beanManager);
|
||||
$dataParams->configure($value);
|
||||
|
||||
return $dataParams;
|
||||
});
|
||||
|
||||
$resolver
|
||||
->setDefined('sourceBean')
|
||||
->setDefault('sourceBean', function (Options $options) {
|
||||
return $this->beanManager->getBeanSafe(
|
||||
$options->offsetGet('moduleName'),
|
||||
$options->offsetGet('id')
|
||||
);
|
||||
})
|
||||
->setAllowedTypes('sourceBean', \SugarBean::class);
|
||||
|
||||
$resolver
|
||||
->setDefined('relatedBean')
|
||||
->setDefault('relatedBean', function (Options $options) {
|
||||
$dataParams = $options->offsetGet('data');
|
||||
|
||||
return $this->beanManager->getBeanSafe(
|
||||
$dataParams->getType(),
|
||||
$dataParams->getId()
|
||||
);
|
||||
})
|
||||
->setAllowedTypes('relatedBean', \SugarBean::class);
|
||||
}
|
||||
}
|
38
Api/V8/Param/DeleteModuleParams.php
Normal file
38
Api/V8/Param/DeleteModuleParams.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class DeleteModuleParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Id::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
85
Api/V8/Param/DeleteRelationshipParams.php
Normal file
85
Api/V8/Param/DeleteRelationshipParams.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class DeleteRelationshipParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLinkedFieldName()
|
||||
{
|
||||
return $this->parameters['linkFieldName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRelatedBeanId()
|
||||
{
|
||||
return $this->parameters['relatedBeanId'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SugarBean
|
||||
*/
|
||||
public function getSourceBean()
|
||||
{
|
||||
return $this->parameters['sourceBean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Id::class,
|
||||
]
|
||||
);
|
||||
|
||||
$resolver
|
||||
->setRequired('relatedBeanId')
|
||||
->setAllowedTypes('relatedBeanId', 'string')
|
||||
->setAllowedValues('relatedBeanId', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Uuid(['strict' => false]),
|
||||
]));
|
||||
|
||||
$resolver
|
||||
->setDefined('sourceBean')
|
||||
->setDefault('sourceBean', function (Options $options) {
|
||||
return $this->beanManager->getBeanSafe(
|
||||
$options->offsetGet('moduleName'),
|
||||
$options->offsetGet('id')
|
||||
);
|
||||
})
|
||||
->setAllowedTypes('sourceBean', \SugarBean::class);
|
||||
|
||||
// dependency on sourceBean field
|
||||
$this->setOptions($resolver, [ParamOption\LinkFieldName::class]);
|
||||
}
|
||||
}
|
47
Api/V8/Param/GetModuleParams.php
Normal file
47
Api/V8/Param/GetModuleParams.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class GetModuleParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return isset($this->parameters['fields']) ? $this->parameters['fields'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Id::class,
|
||||
ParamOption\Fields::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
67
Api/V8/Param/GetModulesParams.php
Normal file
67
Api/V8/Param/GetModulesParams.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class GetModulesParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return isset($this->parameters['fields']) ? $this->parameters['fields'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PageParams
|
||||
*/
|
||||
public function getPage()
|
||||
{
|
||||
return isset($this->parameters['page'])
|
||||
? $this->parameters['page']
|
||||
: new PageParams($this->validatorFactory, $this->beanManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSort()
|
||||
{
|
||||
return isset($this->parameters['sort']) ? $this->parameters['sort'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFilter()
|
||||
{
|
||||
return isset($this->parameters['filter']) ? $this->parameters['filter'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Fields::class,
|
||||
ParamOption\Page::class,
|
||||
ParamOption\Sort::class,
|
||||
ParamOption\Filter::class
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
38
Api/V8/Param/GetRelationshipDataParams.php
Normal file
38
Api/V8/Param/GetRelationshipDataParams.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class GetRelationshipDataParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->parameters['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\Type::class,
|
||||
ParamOption\Id::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
69
Api/V8/Param/GetRelationshipParams.php
Normal file
69
Api/V8/Param/GetRelationshipParams.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class GetRelationshipParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLinkedFieldName()
|
||||
{
|
||||
return $this->parameters['linkFieldName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SugarBean
|
||||
*/
|
||||
public function getSourceBean()
|
||||
{
|
||||
return $this->parameters['sourceBean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
ParamOption\Id::class,
|
||||
]
|
||||
);
|
||||
|
||||
$resolver
|
||||
->setDefined('sourceBean')
|
||||
->setDefault('sourceBean', function (Options $options) {
|
||||
return $this->beanManager->getBeanSafe(
|
||||
$options->offsetGet('moduleName'),
|
||||
$options->offsetGet('id')
|
||||
);
|
||||
})
|
||||
->setAllowedTypes('sourceBean', [\SugarBean::class]);
|
||||
|
||||
// dependency on sourceBean field
|
||||
$this->setOptions($resolver, [ParamOption\LinkFieldName::class]);
|
||||
}
|
||||
}
|
74
Api/V8/Param/GetUserPreferencesParams.php
Normal file
74
Api/V8/Param/GetUserPreferencesParams.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?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 Api\V8\Param;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* GetUserPreferencesParams
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class GetUserPreferencesParams extends BaseParam
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param OptionsResolver $resolver
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions($resolver, [ParamOption\Id::class]);
|
||||
}
|
||||
}
|
79
Api/V8/Param/ListViewColumnsParams.php
Normal file
79
Api/V8/Param/ListViewColumnsParams.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?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 Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Api\V8\Param\OptionsResolver;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
/**
|
||||
* ListViewColumnsParams
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewColumnsParams extends BaseParam
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Api\V8\Param\OptionsResolver $resolver
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
79
Api/V8/Param/ListViewSearchParams.php
Normal file
79
Api/V8/Param/ListViewSearchParams.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?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 Api\V8\Param;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* ListViewSearchParams
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewSearchParams extends BaseParam
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
return $this->parameters['moduleName'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param OptionsResolver $resolver
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\ModuleName::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
49
Api/V8/Param/Options/Attributes.php
Normal file
49
Api/V8/Param/Options/Attributes.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OutOfBoundsException;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Attributes extends BaseOption
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws InvalidArgumentException If attributes parameters have invalid property.
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('attributes')
|
||||
->setAllowedTypes('attributes', 'array')
|
||||
->setAllowedValues('attributes', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => Fields::REGEX_FIELD_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
]))
|
||||
->setNormalizer('attributes', function (Options $options, $values) {
|
||||
$bean = $this->beanManager->newBeanSafe($options->offsetGet('type'));
|
||||
|
||||
foreach ($values as $attribute => $value) {
|
||||
$invalidProperty =
|
||||
!property_exists($bean, $attribute) &&
|
||||
!array_key_exists($attribute, $bean->field_defs) &&
|
||||
!array_key_exists($attribute, $bean->field_name_map);
|
||||
if ($invalidProperty) {
|
||||
throw new OutOfBoundsException(sprintf(
|
||||
'Property %s in %s module is invalid',
|
||||
$attribute,
|
||||
$bean->getObjectName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
});
|
||||
}
|
||||
}
|
47
Api/V8/Param/Options/BaseOption.php
Normal file
47
Api/V8/Param/Options/BaseOption.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\Factory\ValidatorFactory;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
abstract class BaseOption
|
||||
{
|
||||
/**
|
||||
* @var ValidatorFactory
|
||||
*/
|
||||
protected $validatorFactory;
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
protected $beanManager;
|
||||
|
||||
/**
|
||||
* @param ValidatorFactory $validatorFactory
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(ValidatorFactory $validatorFactory, BeanManager $beanManager)
|
||||
{
|
||||
$this->validatorFactory = $validatorFactory;
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OptionsResolver $resolver
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function add(OptionsResolver $resolver);
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @see https://github.com/rappasoft/laravel-helpers#class_basename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getOptionName($class)
|
||||
{
|
||||
return lcfirst(basename(str_replace('\\', '/', $class)));
|
||||
}
|
||||
}
|
53
Api/V8/Param/Options/Fields.php
Normal file
53
Api/V8/Param/Options/Fields.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Fields extends BaseOption
|
||||
{
|
||||
const REGEX_FIELD_PATTERN = '/[^\w-,]/';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @throws \InvalidArgumentException In case fields are invalid.
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('fields')
|
||||
->setAllowedTypes('fields', 'array')
|
||||
->setAllowedValues('fields', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => self::REGEX_FIELD_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
], true))
|
||||
->setNormalizer('fields', function (Options $options, $values) {
|
||||
$bean = $this->beanManager->newBeanSafe(key($values));
|
||||
$attributes = $bean->toArray();
|
||||
$fields = explode(',', array_shift($values));
|
||||
|
||||
$invalidFields = array_filter($fields, function ($field) use ($attributes) {
|
||||
return !array_key_exists($field, $attributes);
|
||||
});
|
||||
|
||||
if ($invalidFields) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'The following field%s in %s module %s not found: %s',
|
||||
count($invalidFields) > 1 ? 's' : '',
|
||||
$bean->getObjectName(),
|
||||
count($invalidFields) > 1 ? 'are' : 'is',
|
||||
implode(', ', $invalidFields)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
});
|
||||
}
|
||||
}
|
30
Api/V8/Param/Options/Filter.php
Normal file
30
Api/V8/Param/Options/Filter.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Api\V8\JsonApi\Repository\Filter as FilterRepository;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Filter extends BaseOption
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('filter')
|
||||
->setAllowedTypes('filter', 'array')
|
||||
->setAllowedValues('filter', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
]))
|
||||
->setNormalizer('filter', function (Options $options, $values) {
|
||||
// we don't support multiple level filtering. for now.
|
||||
$bean = $this->beanManager->newBeanSafe($options->offsetGet('moduleName'));
|
||||
$filter = new FilterRepository($bean->db);
|
||||
|
||||
return $filter->parseWhere($bean, $values);
|
||||
});
|
||||
}
|
||||
}
|
21
Api/V8/Param/Options/Id.php
Normal file
21
Api/V8/Param/Options/Id.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Id extends BaseOption
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('id')
|
||||
->setAllowedTypes('id', 'string')
|
||||
->setAllowedValues('id', $this->validatorFactory->createClosure([
|
||||
new Assert\Regex('/^(\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i')
|
||||
]));
|
||||
}
|
||||
}
|
40
Api/V8/Param/Options/LinkFieldName.php
Normal file
40
Api/V8/Param/Options/LinkFieldName.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class LinkFieldName extends BaseOption
|
||||
{
|
||||
/**
|
||||
* Has a dependency of bean field.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @throws \RuntimeException If relationship cannot loaded
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('linkFieldName')
|
||||
->setAllowedTypes('linkFieldName', ['string'])
|
||||
->setAllowedValues('linkFieldName', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => ModuleName::REGEX_MODULE_NAME_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
]))
|
||||
->setNormalizer('linkFieldName', function (Options $options, $value) {
|
||||
$bean = $options->offsetGet('sourceBean');
|
||||
|
||||
if (!$bean->load_relationship($value)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('Cannot load relationship %s for %s module', $value, $bean->getObjectName())
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
}
|
||||
}
|
27
Api/V8/Param/Options/ModuleName.php
Normal file
27
Api/V8/Param/Options/ModuleName.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class ModuleName extends BaseOption
|
||||
{
|
||||
const REGEX_MODULE_NAME_PATTERN = '/^(\d|\W)|\W/';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('moduleName')
|
||||
->setAllowedTypes('moduleName', 'string')
|
||||
->setAllowedValues('moduleName', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => self::REGEX_MODULE_NAME_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
]));
|
||||
}
|
||||
}
|
35
Api/V8/Param/Options/Page.php
Normal file
35
Api/V8/Param/Options/Page.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Api\V8\Param\PageParams;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Page extends BaseOption
|
||||
{
|
||||
const REGEX_PAGE_PATTERN = '/[^\d]/';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('page')
|
||||
->setAllowedTypes('page', 'array')
|
||||
->setAllowedValues('page', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => self::REGEX_PAGE_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
], true))
|
||||
->setNormalizer('page', function (Options $options, $values) {
|
||||
$pageParams = new PageParams($this->validatorFactory, $this->beanManager);
|
||||
$pageParams->configure($values);
|
||||
|
||||
return $pageParams;
|
||||
});
|
||||
}
|
||||
}
|
35
Api/V8/Param/Options/Sort.php
Normal file
35
Api/V8/Param/Options/Sort.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Api\V8\JsonApi\Repository\Sort as SortRepository;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Sort extends BaseOption
|
||||
{
|
||||
const REGEX_SORT_PATTERN = '/[^\w-]/';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('sort')
|
||||
->setAllowedTypes('sort', 'string')
|
||||
->setAllowedValues('sort', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => self::REGEX_SORT_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
], true))
|
||||
->setNormalizer('sort', function (Options $options, $value) {
|
||||
$bean = $this->beanManager->newBeanSafe($options->offsetGet('moduleName'));
|
||||
$sort = new SortRepository();
|
||||
|
||||
return $sort->parseOrderBy($bean, $value);
|
||||
});
|
||||
}
|
||||
}
|
25
Api/V8/Param/Options/Type.php
Normal file
25
Api/V8/Param/Options/Type.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace Api\V8\Param\Options;
|
||||
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class Type extends BaseOption
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function add(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('type')
|
||||
->setAllowedTypes('type', 'string')
|
||||
->setAllowedValues('type', $this->validatorFactory->createClosure([
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Regex([
|
||||
'pattern' => ModuleName::REGEX_MODULE_NAME_PATTERN,
|
||||
'match' => false,
|
||||
]),
|
||||
]));
|
||||
}
|
||||
}
|
45
Api/V8/Param/PageParams.php
Normal file
45
Api/V8/Param/PageParams.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class PageParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return isset($this->parameters['size']) ? intval($this->parameters['size']) : BeanManager::DEFAULT_ALL_RECORDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getNumber()
|
||||
{
|
||||
return isset($this->parameters['number']) ? intval($this->parameters['number']) : BeanManager::DEFAULT_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setDefined('size')
|
||||
->setAllowedTypes('size', 'string')
|
||||
->setAllowedValues('size', $this->validatorFactory->createClosure([
|
||||
new Assert\GreaterThan(0),
|
||||
]));
|
||||
|
||||
$resolver
|
||||
->setDefined('number')
|
||||
->setAllowedTypes('number', 'string')
|
||||
->setAllowedValues('number', $this->validatorFactory->createClosure([
|
||||
new Assert\GreaterThan(0),
|
||||
]));
|
||||
}
|
||||
}
|
47
Api/V8/Param/UpdateModuleDataParams.php
Normal file
47
Api/V8/Param/UpdateModuleDataParams.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Api\V8\Param\Options as ParamOption;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class UpdateModuleDataParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->parameters['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->parameters['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return isset($this->parameters['attributes']) ? $this->parameters['attributes'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
$this->setOptions(
|
||||
$resolver,
|
||||
[
|
||||
ParamOption\Type::class,
|
||||
ParamOption\Id::class,
|
||||
ParamOption\Attributes::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
37
Api/V8/Param/UpdateModuleParams.php
Normal file
37
Api/V8/Param/UpdateModuleParams.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
namespace Api\V8\Param;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class UpdateModuleParams extends BaseParam
|
||||
{
|
||||
/**
|
||||
* @return CreateModuleDataParams
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->parameters['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configureParameters(OptionsResolver $resolver)
|
||||
{
|
||||
// need to make this more simple
|
||||
$resolver
|
||||
->setRequired('data')
|
||||
->setAllowedTypes('data', 'array')
|
||||
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||
new Assert\NotBlank(),
|
||||
]))
|
||||
->setNormalizer('data', function (Options $options, $values) {
|
||||
$dataParams = new UpdateModuleDataParams($this->validatorFactory, $this->beanManager);
|
||||
$dataParams->configure($values);
|
||||
|
||||
return $dataParams;
|
||||
});
|
||||
}
|
||||
}
|
160
Api/V8/Service/ListViewSearchService.php
Normal file
160
Api/V8/Service/ListViewSearchService.php
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?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 Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\PaginationObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||
use Api\V8\JsonApi\Response\DataResponse;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\Param\ListViewSearchParams;
|
||||
use JsonSerializable;
|
||||
use SearchForm;
|
||||
use SuiteCRM\LangText;
|
||||
use ListViewFacade;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
include_once __DIR__ . '/../../../include/SearchForm/SearchForm2.php';
|
||||
include_once __DIR__ . '/../../../include/ListView/ListViewFacade.php';
|
||||
|
||||
/**
|
||||
* ListViewSearchService
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewSearchService
|
||||
{
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
* @param AttributeObjectHelper $attributeHelper
|
||||
* @param RelationshipObjectHelper $relationshipHelper
|
||||
* @param PaginationObjectHelper $paginationHelper
|
||||
*/
|
||||
public function __construct(
|
||||
BeanManager $beanManager
|
||||
) {
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param LangText $trans
|
||||
* @param array $data
|
||||
* @param string $part
|
||||
* @param string $valueKey
|
||||
* @param array $displayColumns
|
||||
* @return array
|
||||
*/
|
||||
protected function getDataTranslated($trans, $data, $part, $valueKey, $displayColumns)
|
||||
{
|
||||
foreach ($data[$part] as $key => $value) {
|
||||
$text = null;
|
||||
if (isset($value[$valueKey])) {
|
||||
$text = $value[$valueKey];
|
||||
} elseif (isset($value['name']) && isset($displayColumns[strtoupper($value['name'])]['label'])) {
|
||||
$text = $displayColumns[strtoupper($value['name'])]['label'];
|
||||
} else {
|
||||
\LoggerManager::getLogger()->warn("Not found translation text key for search defs for selected module field: $key");
|
||||
}
|
||||
|
||||
$label = $text ? $trans->getText($text) : $text;
|
||||
$data[$part][$key][$valueKey] = $label;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ListViewSearchParams $params
|
||||
*
|
||||
* @return JsonSerializable
|
||||
*/
|
||||
public function getListViewSearchDefs(ListViewSearchParams $params)
|
||||
{
|
||||
// retrieving search defs
|
||||
|
||||
$moduleName = $params->getModuleName();
|
||||
$searchDefs = SearchForm::retrieveSearchDefs($moduleName);
|
||||
|
||||
// get list view defs
|
||||
$displayColumns = ListViewFacade::getDisplayColumns($moduleName);
|
||||
|
||||
// simplified data struct
|
||||
|
||||
$data = [
|
||||
'module' => $moduleName,
|
||||
'templateMeta' => $searchDefs['searchdefs'][$moduleName]['templateMeta'],
|
||||
'basic' => array_values($searchDefs['searchdefs'][$moduleName]['layout']['basic_search']),
|
||||
'advanced' => array_values($searchDefs['searchdefs'][$moduleName]['layout']['advanced_search']),
|
||||
'fields' => $searchDefs['searchFields'][$moduleName]
|
||||
];
|
||||
|
||||
// translations
|
||||
|
||||
$trans = new LangText(null, null, LangText::USING_ALL_STRINGS, true, false, $moduleName);
|
||||
|
||||
|
||||
$data = $this->getDataTranslated($trans, $data, 'basic', 'label', $displayColumns);
|
||||
$data = $this->getDataTranslated($trans, $data, 'advanced', 'label', $displayColumns);
|
||||
$data = $this->getDataTranslated($trans, $data, 'fields', 'vname', $displayColumns);
|
||||
|
||||
// generate response
|
||||
|
||||
$dataResponse = new DataResponse('SearchDefs', null);
|
||||
$attributeResponse = new AttributeResponse($data);
|
||||
$dataResponse->setAttributes($attributeResponse);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
return $response;
|
||||
}
|
||||
}
|
150
Api/V8/Service/ListViewService.php
Normal file
150
Api/V8/Service/ListViewService.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?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 Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\PaginationObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||
use Api\V8\Param\ListViewColumnsParams;
|
||||
use ListViewFacade;
|
||||
use SuiteCRM\LangText;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
include_once __DIR__ . '/../../../include/ListView/ListViewFacade.php';
|
||||
|
||||
/**
|
||||
* ListViewService
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class ListViewService
|
||||
{
|
||||
|
||||
/**
|
||||
* an exact match to ListViewColumnInterface struct of Angular front-end
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $listViewColumnInterface = [
|
||||
'fieldName' => '',
|
||||
'width' => '',
|
||||
'label' => '',
|
||||
'link' => false,
|
||||
'default' => false,
|
||||
'module' => '',
|
||||
'id' => '',
|
||||
'sortable' => false,
|
||||
'customCode' => '', // deprecated from legacy (using only on PHP front-end)
|
||||
];
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @var AttributeObjectHelper
|
||||
*/
|
||||
private $attributeHelper;
|
||||
|
||||
/**
|
||||
* @var RelationshipObjectHelper
|
||||
*/
|
||||
private $relationshipHelper;
|
||||
|
||||
/**
|
||||
* @var PaginationObjectHelper
|
||||
*/
|
||||
private $paginationHelper;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
* @param AttributeObjectHelper $attributeHelper
|
||||
* @param RelationshipObjectHelper $relationshipHelper
|
||||
* @param PaginationObjectHelper $paginationHelper
|
||||
*/
|
||||
public function __construct(
|
||||
BeanManager $beanManager,
|
||||
AttributeObjectHelper $attributeHelper,
|
||||
RelationshipObjectHelper $relationshipHelper,
|
||||
PaginationObjectHelper $paginationHelper
|
||||
) {
|
||||
$this->beanManager = $beanManager;
|
||||
$this->attributeHelper = $attributeHelper;
|
||||
$this->relationshipHelper = $relationshipHelper;
|
||||
$this->paginationHelper = $paginationHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ListViewColumnsParams $params
|
||||
*
|
||||
* @return JsonSerializable
|
||||
*/
|
||||
public function getListViewDefs(ListViewColumnsParams $params)
|
||||
{
|
||||
$moduleName = $params->getModuleName();
|
||||
/** @var SugarBean */
|
||||
$bean = \BeanFactory::getBean($moduleName);
|
||||
|
||||
$text = new LangText(null, null, LangText::USING_ALL_STRINGS, true, false, $moduleName);
|
||||
$displayColumns = ListViewFacade::getDisplayColumns($moduleName);
|
||||
$data = [];
|
||||
foreach ($displayColumns as $key => $column) {
|
||||
$column = array_merge(self::$listViewColumnInterface, $column);
|
||||
$column['fieldName'] = $key; // get the vardef instead this "intuitive fieldName"
|
||||
$translated = $text->getText($column['label']);
|
||||
if (!$translated) {
|
||||
$translated = $text->getText($bean->field_name_map[strtolower($key)]['vname']);
|
||||
}
|
||||
$column['label'] = $translated ? $translated : $column['label'];
|
||||
|
||||
// TODO: validate the column name (for e.g label and name should be requered etc...) also check the ListViewColumnInterface keys are match..
|
||||
$data[] = $column;
|
||||
}
|
||||
$response = new AttributeResponse($data);
|
||||
return $response;
|
||||
}
|
||||
}
|
50
Api/V8/Service/LogoutService.php
Normal file
50
Api/V8/Service/LogoutService.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
namespace Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\JsonApi\Response\MetaResponse;
|
||||
|
||||
class LogoutService
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(BeanManager $beanManager)
|
||||
{
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return DocumentResponse
|
||||
* @throws \InvalidArgumentException When access token is not found.
|
||||
*/
|
||||
public function logout($accessToken)
|
||||
{
|
||||
// same logic in Access and Refresh token repository, refactor this later
|
||||
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||
$token->retrieve_by_string_fields(
|
||||
['access_token' => $accessToken]
|
||||
);
|
||||
|
||||
if ($token->id === null) {
|
||||
throw new \InvalidArgumentException('Access token is not found for this client');
|
||||
}
|
||||
|
||||
$token->mark_deleted($token->id);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setMeta(
|
||||
new MetaResponse(['message' => 'You have been successfully logged out'])
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
250
Api/V8/Service/ModuleService.php
Normal file
250
Api/V8/Service/ModuleService.php
Normal file
|
@ -0,0 +1,250 @@
|
|||
<?php
|
||||
namespace Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\PaginationObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||
use Api\V8\JsonApi\Response\DataResponse;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\JsonApi\Response\MetaResponse;
|
||||
use Api\V8\Param\CreateModuleParams;
|
||||
use Api\V8\Param\DeleteModuleParams;
|
||||
use Api\V8\Param\GetModuleParams;
|
||||
use Api\V8\Param\GetModulesParams;
|
||||
use Api\V8\Param\UpdateModuleParams;
|
||||
use Slim\Http\Request;
|
||||
|
||||
class ModuleService
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @var AttributeObjectHelper
|
||||
*/
|
||||
private $attributeHelper;
|
||||
|
||||
/**
|
||||
* @var RelationshipObjectHelper
|
||||
*/
|
||||
private $relationshipHelper;
|
||||
|
||||
/**
|
||||
* @var PaginationObjectHelper
|
||||
*/
|
||||
private $paginationHelper;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
* @param AttributeObjectHelper $attributeHelper
|
||||
* @param RelationshipObjectHelper $relationshipHelper
|
||||
* @param PaginationObjectHelper $paginationHelper
|
||||
*/
|
||||
public function __construct(
|
||||
BeanManager $beanManager,
|
||||
AttributeObjectHelper $attributeHelper,
|
||||
RelationshipObjectHelper $relationshipHelper,
|
||||
PaginationObjectHelper $paginationHelper
|
||||
) {
|
||||
$this->beanManager = $beanManager;
|
||||
$this->attributeHelper = $attributeHelper;
|
||||
$this->relationshipHelper = $relationshipHelper;
|
||||
$this->paginationHelper = $paginationHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GetModuleParams $params
|
||||
* @param string $path
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function getRecord(GetModuleParams $params, $path)
|
||||
{
|
||||
$fields = $params->getFields();
|
||||
$bean = $this->beanManager->getBeanSafe(
|
||||
$params->getModuleName(),
|
||||
$params->getId()
|
||||
);
|
||||
|
||||
$dataResponse = $this->getDataResponse($bean, $fields, $path);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GetModulesParams $params
|
||||
* @param Request $request
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function getRecords(GetModulesParams $params, Request $request)
|
||||
{
|
||||
// this whole method should split into separated classes later
|
||||
$module = $params->getModuleName();
|
||||
$orderBy = $params->getSort();
|
||||
$where = $params->getFilter();
|
||||
$fields = $params->getFields();
|
||||
|
||||
$size = $params->getPage()->getSize();
|
||||
$number = $params->getPage()->getNumber();
|
||||
// negative numbers are validated in params
|
||||
$offset = $number !== 0 ? ($number - 1) * $size : $number;
|
||||
$realRowCount = $this->beanManager->countRecords($module, $where);
|
||||
$limit = $size === BeanManager::DEFAULT_ALL_RECORDS ? BeanManager::DEFAULT_LIMIT : $size;
|
||||
|
||||
$beanListResponse = $this->beanManager->getList($module)
|
||||
->orderBy($orderBy)
|
||||
->where($where)
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
->max($size)
|
||||
->fetch();
|
||||
|
||||
$data = [];
|
||||
foreach ($beanListResponse->getBeans() as $bean) {
|
||||
$dataResponse = $this->getDataResponse(
|
||||
$bean,
|
||||
$fields,
|
||||
$request->getUri()->getPath() . '/' . $bean->id
|
||||
);
|
||||
|
||||
$data[] = $dataResponse;
|
||||
}
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($data);
|
||||
|
||||
// pagination
|
||||
if ($data && $limit !== BeanManager::DEFAULT_LIMIT) {
|
||||
$totalPages = ceil($realRowCount / $size);
|
||||
|
||||
$paginationMeta = $this->paginationHelper->getPaginationMeta($totalPages, count($data));
|
||||
$paginationLinks = $this->paginationHelper->getPaginationLinks($request, $totalPages, $number);
|
||||
|
||||
$response->setMeta($paginationMeta);
|
||||
$response->setLinks($paginationLinks);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateModuleParams $params
|
||||
* @param Request $request
|
||||
*
|
||||
* @return DocumentResponse
|
||||
* @throws \InvalidArgumentException When bean is already exist.
|
||||
*/
|
||||
public function createRecord(CreateModuleParams $params, Request $request)
|
||||
{
|
||||
$module = $params->getData()->getType();
|
||||
$id = $params->getData()->getId();
|
||||
$attributes = $params->getData()->getAttributes();
|
||||
|
||||
if ($id !== null && $this->beanManager->getBean($module, $id, [], false) instanceof \SugarBean) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Bean %s with id %s is already exist',
|
||||
$module,
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
$bean = $this->beanManager->newBeanSafe($module);
|
||||
if ($id !== null) {
|
||||
$bean->id = $id;
|
||||
$bean->new_with_id = true;
|
||||
}
|
||||
|
||||
foreach ($attributes as $property => $value) {
|
||||
$bean->$property = $value;
|
||||
}
|
||||
|
||||
$bean->save();
|
||||
|
||||
$dataResponse = $this->getDataResponse(
|
||||
$bean,
|
||||
null,
|
||||
$request->getUri()->getPath() . '/' . $bean->id
|
||||
);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UpdateModuleParams $params
|
||||
* @param Request $request
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function updateRecord(UpdateModuleParams $params, Request $request)
|
||||
{
|
||||
$module = $params->getData()->getType();
|
||||
$id = $params->getData()->getId();
|
||||
$attributes = $params->getData()->getAttributes();
|
||||
$bean = $this->beanManager->getBeanSafe($module, $id);
|
||||
|
||||
foreach ($attributes as $property => $value) {
|
||||
$bean->$property = $value;
|
||||
}
|
||||
|
||||
$bean->save();
|
||||
|
||||
$dataResponse = $this->getDataResponse(
|
||||
$bean,
|
||||
null,
|
||||
$request->getUri()->getPath() . '/' . $bean->id
|
||||
);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteModuleParams $params
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function deleteRecord(DeleteModuleParams $params)
|
||||
{
|
||||
$bean = $this->beanManager->getBeanSafe(
|
||||
$params->getModuleName(),
|
||||
$params->getId()
|
||||
);
|
||||
$bean->mark_deleted($bean->id);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setMeta(
|
||||
new MetaResponse(['message' => sprintf('Record with id %s is deleted', $bean->id)])
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SugarBean $bean
|
||||
* @param array|null $fields
|
||||
* @param string|null $path
|
||||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function getDataResponse(\SugarBean $bean, $fields = null, $path = null)
|
||||
{
|
||||
// this will be split into separated classed later
|
||||
$dataResponse = new DataResponse($bean->getObjectName(), $bean->id);
|
||||
$dataResponse->setAttributes($this->attributeHelper->getAttributes($bean, $fields));
|
||||
$dataResponse->setRelationships($this->relationshipHelper->getRelationships($bean, $path));
|
||||
|
||||
return $dataResponse;
|
||||
}
|
||||
}
|
150
Api/V8/Service/RelationshipService.php
Normal file
150
Api/V8/Service/RelationshipService.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
namespace Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Response\DataResponse;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\JsonApi\Response\LinksResponse;
|
||||
use Api\V8\JsonApi\Response\MetaResponse;
|
||||
use Api\V8\Param\CreateRelationshipParams;
|
||||
use Api\V8\Param\DeleteRelationshipParams;
|
||||
use Api\V8\Param\GetRelationshipParams;
|
||||
|
||||
class RelationshipService
|
||||
{
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @var AttributeObjectHelper
|
||||
*/
|
||||
private $attributeHelper;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
* @param AttributeObjectHelper $attributeHelper
|
||||
*/
|
||||
public function __construct(BeanManager $beanManager, AttributeObjectHelper $attributeHelper)
|
||||
{
|
||||
$this->beanManager = $beanManager;
|
||||
$this->attributeHelper = $attributeHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GetRelationshipParams $params
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function getRelationship(GetRelationshipParams $params)
|
||||
{
|
||||
$sourceBean = $params->getSourceBean();
|
||||
$linkFieldName = $params->getLinkedFieldName();
|
||||
$relatedBeans = $sourceBean->get_linked_beans($linkFieldName);
|
||||
$response = new DocumentResponse();
|
||||
|
||||
if (!$relatedBeans) {
|
||||
$response->setMeta(new MetaResponse(
|
||||
[
|
||||
'message' => sprintf(
|
||||
'There is no relationship set in %s module with %s link field',
|
||||
$sourceBean->getObjectName(),
|
||||
$linkFieldName
|
||||
)
|
||||
]
|
||||
));
|
||||
} else {
|
||||
$data = [];
|
||||
/** @var \SugarBean $relatedBean */
|
||||
foreach ($relatedBeans as $relatedBean) {
|
||||
$linkResponse = new LinksResponse();
|
||||
$linkResponse->setSelf(sprintf('/V8/module/%s/%s', $relatedBean->getObjectName(), $relatedBean->id));
|
||||
|
||||
$dataResponse = new DataResponse($relatedBean->getObjectName(), $relatedBean->id);
|
||||
$dataResponse->setLinks($linkResponse);
|
||||
$data[] = $dataResponse;
|
||||
}
|
||||
|
||||
$response->setData($data);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateRelationshipParams $params
|
||||
*
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function createRelationship(CreateRelationshipParams $params)
|
||||
{
|
||||
$sourceBean = $params->getSourceBean();
|
||||
$relatedBean = $params->getRelatedBean();
|
||||
$linkFieldName = $this->beanManager->getLinkedFieldName($sourceBean, $relatedBean);
|
||||
|
||||
$this->beanManager->createRelationshipSafe($sourceBean, $relatedBean, $linkFieldName);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setMeta(new MetaResponse(
|
||||
[
|
||||
'message' => sprintf(
|
||||
'%s with id %s has been added to %s with id %s',
|
||||
$relatedBean->getObjectName(),
|
||||
$relatedBean->id,
|
||||
$sourceBean->getObjectName(),
|
||||
$sourceBean->id
|
||||
)
|
||||
]
|
||||
));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteRelationshipParams $params
|
||||
*
|
||||
* @return DocumentResponse
|
||||
* @throws \DomainException When the source module is not related to the target module.
|
||||
*/
|
||||
public function deleteRelationship(DeleteRelationshipParams $params)
|
||||
{
|
||||
$sourceBean = $params->getSourceBean();
|
||||
$linkFieldName = $params->getLinkedFieldName();
|
||||
$relatedBeans = $sourceBean->get_linked_beans($linkFieldName);
|
||||
$relatedBeanId = $params->getRelatedBeanId();
|
||||
|
||||
$relatedBean = array_filter($relatedBeans, function ($bean) use ($relatedBeanId) {
|
||||
return $bean->id === $relatedBeanId;
|
||||
});
|
||||
|
||||
if (!$relatedBean) {
|
||||
throw new \DomainException(
|
||||
sprintf(
|
||||
'Module with %s id is not related to %s',
|
||||
$relatedBeanId,
|
||||
$sourceBean->getObjectName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$relatedBean = array_shift($relatedBean);
|
||||
$this->beanManager->deleteRelationshipSafe($sourceBean, $relatedBean, $linkFieldName);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setMeta(new MetaResponse(
|
||||
[
|
||||
'message' => sprintf(
|
||||
'Relationship has been deleted between %s with id %s and %s with id %s',
|
||||
$sourceBean->getObjectName(),
|
||||
$sourceBean->id,
|
||||
$relatedBean->getObjectName(),
|
||||
$relatedBean->id
|
||||
)
|
||||
]
|
||||
));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
103
Api/V8/Service/UserPreferencesService.php
Normal file
103
Api/V8/Service/UserPreferencesService.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?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 Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||
use Api\V8\JsonApi\Response\DataResponse;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Api\V8\Param\GetUserPreferencesParams;
|
||||
use DBManagerFactory;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
/**
|
||||
* UserPreferencesService
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class UserPreferencesService
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(
|
||||
BeanManager $beanManager
|
||||
) {
|
||||
$this->beanManager = $beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GetUserPreferencesParams $params
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function getUserPreferences(GetUserPreferencesParams $params)
|
||||
{
|
||||
// needs to determinate the user preferences
|
||||
$user = $this->beanManager->getBeanSafe('Users', $params->getUserId());
|
||||
|
||||
$db = DBManagerFactory::getInstance();
|
||||
$result = $db->query("SELECT contents, category FROM user_preferences WHERE assigned_user_id='$user->id' AND deleted = 0", false, 'Failed to load user preferences');
|
||||
$preferences = [];
|
||||
while ($row = $db->fetchByAssoc($result)) {
|
||||
$category = $row['category'];
|
||||
$preferences[$category] = unserialize(base64_decode($row['contents']));
|
||||
}
|
||||
|
||||
$dataResponse = new DataResponse('UserPreference', $params->getUserId());
|
||||
$attributeResponse = new AttributeResponse($preferences);
|
||||
$dataResponse->setAttributes($attributeResponse);
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
return $response;
|
||||
}
|
||||
}
|
118
Api/V8/Service/UserService.php
Normal file
118
Api/V8/Service/UserService.php
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?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 Api\V8\Service;
|
||||
|
||||
use Api\V8\BeanDecorator\BeanManager;
|
||||
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||
use Api\V8\JsonApi\Response\DataResponse;
|
||||
use Api\V8\JsonApi\Response\DocumentResponse;
|
||||
use Slim\Http\Request;
|
||||
|
||||
if (!defined('sugarEntry') || !sugarEntry) {
|
||||
die('Not A Valid Entry Point');
|
||||
}
|
||||
|
||||
include_once __DIR__ . '/../../../include/ListView/ListViewFacade.php';
|
||||
|
||||
/**
|
||||
* UserService
|
||||
*
|
||||
* @author gyula
|
||||
*/
|
||||
class UserService
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var BeanManager
|
||||
*/
|
||||
private $beanManager;
|
||||
|
||||
/**
|
||||
* @var AttributeObjectHelper
|
||||
*/
|
||||
private $attributeHelper;
|
||||
|
||||
/**
|
||||
* @var RelationshipObjectHelper
|
||||
*/
|
||||
private $relationshipHelper;
|
||||
|
||||
/**
|
||||
* @param BeanManager $beanManager
|
||||
*/
|
||||
public function __construct(
|
||||
BeanManager $beanManager,
|
||||
AttributeObjectHelper $attributeHelper,
|
||||
RelationshipObjectHelper $relationshipHelper
|
||||
) {
|
||||
$this->beanManager = $beanManager;
|
||||
$this->attributeHelper = $attributeHelper;
|
||||
$this->relationshipHelper = $relationshipHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @return DocumentResponse
|
||||
*/
|
||||
public function getCurrentUser(Request $request)
|
||||
{
|
||||
// needs to determinate the curent user without globals
|
||||
$oauthClientId = $request->getAttribute('oauth_client_id');
|
||||
$oauthClient = $this->beanManager->getBeanSafe('OAuth2Clients', $oauthClientId);
|
||||
$currentUser = $this->beanManager->getBeanSafe('Users', $oauthClient->assigned_user_id);
|
||||
|
||||
$currentUserData = $currentUser->toArray();
|
||||
unset($currentUserData['user_hash']);
|
||||
|
||||
$dataResponse = new DataResponse($currentUser->getObjectName(), $currentUser->id);
|
||||
$attributeResponse = new AttributeResponse($currentUserData);
|
||||
$dataResponse->setAttributes($attributeResponse);
|
||||
$dataResponse->setRelationships($this->relationshipHelper->getRelationships($currentUser, $request->getUri()->getPath()));
|
||||
|
||||
$response = new DocumentResponse();
|
||||
$response->setData($dataResponse);
|
||||
return $response;
|
||||
}
|
||||
}
|
936
Api/docs/postman/SalesAgility.postman_collection.json
Normal file
936
Api/docs/postman/SalesAgility.postman_collection.json
Normal file
|
@ -0,0 +1,936 @@
|
|||
{
|
||||
"info": {
|
||||
"name": "SalesAgility",
|
||||
"_postman_id": "9977217b-9e4a-b8fe-f32d-a59c29424939",
|
||||
"description": "",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "SuiteCRM/V8",
|
||||
"description": "",
|
||||
"item": [
|
||||
{
|
||||
"name": "Get module",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjEyZmEzOWU5NGE1OWI1ZTkwMjBmMjg3NjZjYWM1MGRhNGJlODQ3MzE1ZmM0NjNkZTU5ZDE4Mjk2M2VlMDg3ZGQ3ZTU1NmYwMjMwMmZjMDZmIn0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiIxMmZhMzllOTRhNTliNWU5MDIwZjI4NzY2Y2FjNTBkYTRiZTg0NzMxNWZjNDYzZGU1OWQxODI5NjNlZTA4N2RkN2U1NTZmMDIzMDJmYzA2ZiIsImlhdCI6MTUyOTA1NTgzOSwibmJmIjoxNTI5MDU1ODM5LCJleHAiOjE1MjkwNTk0MzksInN1YiI6IjEiLCJzY29wZXMiOltdfQ.NE2EPG-T1S58dkVAT4iK5TUE9s1Z_LrpzJK6YfLm8CCoAkzeRgdd1cYK63V2YspZuZENdat4QPXZU7aMSGjDguiKMiyCkIXmiB71zSUNfU-uDlPL8MUBepPc2cl72eahxJ-Z8ssbGxT8mwil9lakCaGn2K-OWl25jPtRWdeN2UC7dqVFLdbmPbThzxE3OkF1xPdUnCCbJNPyX7CZzsjV8w8Ap2k8V9pDtDNLI4BELFx17b2zKPB7gxcqNQyYZMkHIIu2N6QtpjuFXjS5Em1VgW5_SYznUVF_httQ0-IbvLGYVGzOT71dYNKMdbU0R2hNFyy3SrhVSM3OIA8iEq1SZA",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts/11a71596-83e7-624d-c792-5ab9006dd493?fields[Accounts]=name,account_type",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts",
|
||||
"11a71596-83e7-624d-c792-5ab9006dd493"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "fields[Accounts]",
|
||||
"value": "name,account_type",
|
||||
"equals": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get modules",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImFiNGUyYzkyMzIxZjQ5OTgwNDMyOGNmMTFjMjdiOTk2MzBiMjE0NGE5M2YxN2FhZmI4MTM4ZDE4ZWY0OWRkYWRkNGIwOGVjNDVhOTg3NmNmIn0.eyJhdWQiOiJiMTNhMzlmOC0xYzI0LWM1ZDAtYmEwZC01YWIxMjNkNmU4OTkiLCJqdGkiOiJhYjRlMmM5MjMyMWY0OTk4MDQzMjhjZjExYzI3Yjk5NjMwYjIxNDRhOTNmMTdhYWZiODEzOGQxOGVmNDlkZGFkZDRiMDhlYzQ1YTk4NzZjZiIsImlhdCI6MTUyNjU1ODQyNiwibmJmIjoxNTI2NTU4NDI2LCJleHAiOjE1MjY1NjIwMjYsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.XoR3_CT19V8vkrSC668oQen6UHGiJB_EqUArvTUj6svuYW_VFS5QP57P2NCPuy_NlcD3WmqKgSG_v2c_ye7tvEV1dnpW1dqI0yWUTtOmRICtlPzc_DQgVCPJKMU0OFyBDIdoPu7hOL3gp-D46ImMQuQhBQDYVN9AAyBwef8CeSJ_0_V7_nrryXBRisiAGnQAhuuXcGsbUpVRnssBizBQzif9-ikRoh7PQ6q3WZ6oqmZCyj_7-azQyAMs3I0VytdV_EnfTJbwLTl4r47zwiahHy72JH5oTOdItjngFB921IncXSPGWukBUflUbz-Ds7A5tPZBKm2axpKxQRV_Dt-daA",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts?fields[Accounts]=name,account_type&page[size]=4&page[number]=4&sort=name&filter[operator]=and&filter[account_type][eq]=Customer",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "fields[Accounts]",
|
||||
"value": "name,account_type",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"key": "page[size]",
|
||||
"value": "4",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"key": "page[number]",
|
||||
"value": "4",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"key": "sort",
|
||||
"value": "name",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"key": "filter[operator]",
|
||||
"value": "and",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"key": "filter[account_type][eq]",
|
||||
"value": "Customer",
|
||||
"equals": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create module",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwYTczODU5NjZkY2FiNjM3ZTk3YzM5ZWU2MzQ1NzhiZTIxYTlkMDViNmUxMmRiMDBjN2ZiMDYyYTA5ZTRjNzgxYTFjMmM4N2RiNmRhMzgwIn0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiJhMGE3Mzg1OTY2ZGNhYjYzN2U5N2MzOWVlNjM0NTc4YmUyMWE5ZDA1YjZlMTJkYjAwYzdmYjA2MmEwOWU0Yzc4MWExYzJjODdkYjZkYTM4MCIsImlhdCI6MTUyOTUwNjE3OCwibmJmIjoxNTI5NTA2MTc4LCJleHAiOjE1Mjk1MDk3NzgsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.sUBY05yiw6WGeeftrZOPesSSxzxvEoNSoP5oL3Q_pdrdm7Z5UTN0dnedUsL4fNSlPKzyuuFgFxlwLCk-kUTQ1LtSVe2OuMGdURxbK-hoA5K-5MEwWP-EudckJAcToTLVhr7K4iZdhK1i1_HRSFG-_9MWM3HkyB9xr2JpySdxlUvD9yxhmOMgK5BdL-m7IdeokoQUPE5GFZkbG0OA8EVJ92otD0PYE_6AbC8RIGqGgRZmIQDDe5AWTwT-6xYsHMTGpGQQUNiYRlGA_cQj3wseXZAoW13WpmHhoKOoJcI2A4uLzrOIoYzInujsTLtSUnJkxo47T7ZL7xNmbJEXRcfVvQ",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"data\": {\n \"type\": \"Accounts\",\n \"id\": \"11a71596-83e7-624d-c792-5ab9006dd493\",\n \"attributes\": {\n \"name\": \"Muhahaha\"\n }\n }\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module"
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Update module",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwYTczODU5NjZkY2FiNjM3ZTk3YzM5ZWU2MzQ1NzhiZTIxYTlkMDViNmUxMmRiMDBjN2ZiMDYyYTA5ZTRjNzgxYTFjMmM4N2RiNmRhMzgwIn0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiJhMGE3Mzg1OTY2ZGNhYjYzN2U5N2MzOWVlNjM0NTc4YmUyMWE5ZDA1YjZlMTJkYjAwYzdmYjA2MmEwOWU0Yzc4MWExYzJjODdkYjZkYTM4MCIsImlhdCI6MTUyOTUwNjE3OCwibmJmIjoxNTI5NTA2MTc4LCJleHAiOjE1Mjk1MDk3NzgsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.sUBY05yiw6WGeeftrZOPesSSxzxvEoNSoP5oL3Q_pdrdm7Z5UTN0dnedUsL4fNSlPKzyuuFgFxlwLCk-kUTQ1LtSVe2OuMGdURxbK-hoA5K-5MEwWP-EudckJAcToTLVhr7K4iZdhK1i1_HRSFG-_9MWM3HkyB9xr2JpySdxlUvD9yxhmOMgK5BdL-m7IdeokoQUPE5GFZkbG0OA8EVJ92otD0PYE_6AbC8RIGqGgRZmIQDDe5AWTwT-6xYsHMTGpGQQUNiYRlGA_cQj3wseXZAoW13WpmHhoKOoJcI2A4uLzrOIoYzInujsTLtSUnJkxo47T7ZL7xNmbJEXRcfVvQ",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "PATCH",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"data\": {\n \"type\": \"Accounts\",\n \"id\": \"11a71596-83e7-624d-c792-5ab9006dd493\",\n \"attributes\": {\n \"name\": \"hapff111fff\"\n }\n }\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module"
|
||||
]
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Delete module",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwYTczODU5NjZkY2FiNjM3ZTk3YzM5ZWU2MzQ1NzhiZTIxYTlkMDViNmUxMmRiMDBjN2ZiMDYyYTA5ZTRjNzgxYTFjMmM4N2RiNmRhMzgwIn0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiJhMGE3Mzg1OTY2ZGNhYjYzN2U5N2MzOWVlNjM0NTc4YmUyMWE5ZDA1YjZlMTJkYjAwYzdmYjA2MmEwOWU0Yzc4MWExYzJjODdkYjZkYTM4MCIsImlhdCI6MTUyOTUwNjE3OCwibmJmIjoxNTI5NTA2MTc4LCJleHAiOjE1Mjk1MDk3NzgsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.sUBY05yiw6WGeeftrZOPesSSxzxvEoNSoP5oL3Q_pdrdm7Z5UTN0dnedUsL4fNSlPKzyuuFgFxlwLCk-kUTQ1LtSVe2OuMGdURxbK-hoA5K-5MEwWP-EudckJAcToTLVhr7K4iZdhK1i1_HRSFG-_9MWM3HkyB9xr2JpySdxlUvD9yxhmOMgK5BdL-m7IdeokoQUPE5GFZkbG0OA8EVJ92otD0PYE_6AbC8RIGqGgRZmIQDDe5AWTwT-6xYsHMTGpGQQUNiYRlGA_cQj3wseXZAoW13WpmHhoKOoJcI2A4uLzrOIoYzInujsTLtSUnJkxo47T7ZL7xNmbJEXRcfVvQ",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts/11a71596-83e7-624d-c792-5ab9006dd493",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts",
|
||||
"11a71596-83e7-624d-c792-5ab9006dd493"
|
||||
]
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get relationship",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMyZWQ4ZGEzZjQxM2QyNWI1ZGUxMWNhNGFjNWVmMWYwMmFkNDkwNzkyOGU4NjcyYTM1NWNmYTRmY2VkNWNkZWU5MjUzODVkN2I0MDU1ZmM2In0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiIzMmVkOGRhM2Y0MTNkMjViNWRlMTFjYTRhYzVlZjFmMDJhZDQ5MDc5MjhlODY3MmEzNTVjZmE0ZmNlZDVjZGVlOTI1Mzg1ZDdiNDA1NWZjNiIsImlhdCI6MTUyOTUwMjU1MSwibmJmIjoxNTI5NTAyNTUxLCJleHAiOjE1Mjk1MDYxNTEsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.s-eQwjwvS2DA8A4GjATUnRyrTQ5MRhoDMpzcArtVWnLZT0sLWrUqDh3qtZ6U5qGcli-C609E_hUoi0wtn1SEVTMXMSIbu_ipb109LvAv9dgpOfnFdP8kOIOvQR9kkMnI0jw4AY7w0PrON_-kZjPvucBZuRv5TVguJwRSXy3_xVFMiXGI1KfyanFwpW4AT1aDmdQ-R6nl7ginGpEzphySOK8khe9FEb9rvvwtqJGbZG7khFMVw9nAzVEF4pT4ZCS774cwEhagxWUeJKs-8yYPANMJyoFxlds54InJTuxlB6P6AIddBtjMc8_aiGz1-PU8Ulsjkpp-b_KslXUtPUGy1w",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts/11a71596-83e7-624d-c792-5ab9006dd493/relationships/contacts",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts",
|
||||
"11a71596-83e7-624d-c792-5ab9006dd493",
|
||||
"relationships",
|
||||
"contacts"
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create relationship",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMyZWQ4ZGEzZjQxM2QyNWI1ZGUxMWNhNGFjNWVmMWYwMmFkNDkwNzkyOGU4NjcyYTM1NWNmYTRmY2VkNWNkZWU5MjUzODVkN2I0MDU1ZmM2In0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiIzMmVkOGRhM2Y0MTNkMjViNWRlMTFjYTRhYzVlZjFmMDJhZDQ5MDc5MjhlODY3MmEzNTVjZmE0ZmNlZDVjZGVlOTI1Mzg1ZDdiNDA1NWZjNiIsImlhdCI6MTUyOTUwMjU1MSwibmJmIjoxNTI5NTAyNTUxLCJleHAiOjE1Mjk1MDYxNTEsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.s-eQwjwvS2DA8A4GjATUnRyrTQ5MRhoDMpzcArtVWnLZT0sLWrUqDh3qtZ6U5qGcli-C609E_hUoi0wtn1SEVTMXMSIbu_ipb109LvAv9dgpOfnFdP8kOIOvQR9kkMnI0jw4AY7w0PrON_-kZjPvucBZuRv5TVguJwRSXy3_xVFMiXGI1KfyanFwpW4AT1aDmdQ-R6nl7ginGpEzphySOK8khe9FEb9rvvwtqJGbZG7khFMVw9nAzVEF4pT4ZCS774cwEhagxWUeJKs-8yYPANMJyoFxlds54InJTuxlB6P6AIddBtjMc8_aiGz1-PU8Ulsjkpp-b_KslXUtPUGy1w",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"data\": {\n \"type\": \"Contacts\",\n \"id\": \"11806811-0b4b-fcdd-268b-5b2260e68333\"\n }\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts/11a71596-83e7-624d-c792-5ab9006dd493/relationships",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts",
|
||||
"11a71596-83e7-624d-c792-5ab9006dd493",
|
||||
"relationships"
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Delete relationship",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjE1MDhmZWY3Yzg2OTkxODliMGZlOWE2Nzk1MDcyMzhjNTM4YWM2YzlmMTI2M2JjMWJiZmVkMDdjMjRlYmY4MGU0MWM5NDdiNmUyYTFhYzRjIn0.eyJhdWQiOiJjOTlmZDM2Ny1kY2QwLTU4NDAtN2YwMS01YjIyNjIzMzNhYjIiLCJqdGkiOiIxNTA4ZmVmN2M4Njk5MTg5YjBmZTlhNjc5NTA3MjM4YzUzOGFjNmM5ZjEyNjNiYzFiYmZlZDA3YzI0ZWJmODBlNDFjOTQ3YjZlMmExYWM0YyIsImlhdCI6MTUyOTQ4ODczNywibmJmIjoxNTI5NDg4NzM3LCJleHAiOjE1Mjk0OTIzMzcsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.WYBD1Gc9ggTHjXqSxRvxmM-WaR9gdL6lJyqznnD9Vvm6xNll4SKe54wM9rR_PZQjMtNdCATCtewLcnB5EzGsS7RqVZcBDhFKVvt3LC0oScPpnfw20qTeAZECnsuOs9RrLD_JAV4Lk-8WhUF5PZUl9n_UK1V8Y9ll8DMQryiBj1XrN54_LEPKeQbnHOKTpqptXjxz6rVZ9oc0JjJzwG2x3CUK9J8sp0RhQjSx_G_SJrAjVkM0yDKPaYg2Cn5OyvRRMjFhTwNxW6gUjnK9WgP65d5jNwXhmcNsIeb_iDCl5aYaqDPf3V0mARoS_BFjhiizu5QSwlfH16whhKx_ZwVpKQ",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/module/Accounts/11a71596-83e7-624d-c792-5ab9006dd493/relationships/contacts/11806811-0b4b-fcdd-268b-5b2260e68333",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"module",
|
||||
"Accounts",
|
||||
"11a71596-83e7-624d-c792-5ab9006dd493",
|
||||
"relationships",
|
||||
"contacts",
|
||||
"11806811-0b4b-fcdd-268b-5b2260e68333"
|
||||
]
|
||||
},
|
||||
"description": null
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Logout",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "oauth2",
|
||||
"oauth2": [
|
||||
{
|
||||
"key": "accessToken",
|
||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjNhZDE1ZDQzZjFlMmRhNDhhZGMzMmU1OWFlNWE2NmRjYzI4ZjljZjFmZmJhMzdkMjQ4YzExOWVmOGI1ZmI4MWM1Y2MxOTdkOWQ4ZmEwYzliIn0.eyJhdWQiOiJiMTNhMzlmOC0xYzI0LWM1ZDAtYmEwZC01YWIxMjNkNmU4OTkiLCJqdGkiOiIzYWQxNWQ0M2YxZTJkYTQ4YWRjMzJlNTlhZTVhNjZkY2MyOGY5Y2YxZmZiYTM3ZDI0OGMxMTllZjhiNWZiODFjNWNjMTk3ZDlkOGZhMGM5YiIsImlhdCI6MTUyNTE2MDEzNSwibmJmIjoxNTI1MTYwMTM1LCJleHAiOjE1MjUyMDMzMzUsInN1YiI6IjEiLCJzY29wZXMiOltdfQ.Ypei77VrFLiY-TLI4fCUWyDVGpJ_H9OSdHmZKmReRpKKVuhltmTgyYjYDU96yWF9uBrjsthF7_87bCfTk-wIYelSqH_v-02-TlQru_qyNd9xkUxmm3-7v03FI3Fw9gyj0zruPtHBi6V8x0G1ZSYAqsuAIygIPpZH10TrNKPYIFeo0Lxwg3oGkpH9YfXGJSQkliFv--euiB3C2sJDE9Djk-xxA-48xwZvzn-249-ox7FI6qU2OIPNDlnVjx0l8N9KVjFPsz79U40T259QvwHZiFiubUE4pWjs6u74KBr-z6Rls0d3ndqi8JYA5ZLYjEQq8txmrqwjBISn1nZqBsGbiQ",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "tokenType",
|
||||
"value": "Bearer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "addTokenTo",
|
||||
"value": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "callBackUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "authUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "accessTokenUrl",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientId",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientSecret",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "clientAuth",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "grantType",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "scope",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "redirectUri",
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"key": "refreshToken",
|
||||
"type": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{suitecrm.url}}/V8/logout",
|
||||
"host": [
|
||||
"{{suitecrm.url}}"
|
||||
],
|
||||
"path": [
|
||||
"V8",
|
||||
"logout"
|
||||
]
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
488
Api/docs/swagger/swagger.json
Normal file
488
Api/docs/swagger/swagger.json
Normal file
|
@ -0,0 +1,488 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "SalesAgility REST API",
|
||||
"version": "8.1",
|
||||
"contact": {
|
||||
"name": "Support",
|
||||
"url": "https://suitecrm.com/forum"
|
||||
},
|
||||
"license": {
|
||||
"name": "GNU AFFERO GENERAL PUBLIC LICENSE VERSION 3",
|
||||
"url": "https://github.com/salesagility/SuiteCRM/blob/master/LICENSE.txt"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://localhost/forkedSuite/Api/V8"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/module/{moduleName}/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Module"
|
||||
],
|
||||
"description": "Returns a bean with the specific ID",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "moduleName",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Contacts"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "b13a39f8-1c24-c5d0-ba0d-5ab123d6e899"
|
||||
},
|
||||
{
|
||||
"name": "fields[Contacts]",
|
||||
"in": "query",
|
||||
"description": "Filtering attributes of the bean",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "name,account_type"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Module"
|
||||
],
|
||||
"description": "Delete a bean with specific ID",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "moduleName",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Contacts"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "b13a39f8-1c24-c5d0-ba0d-5ab123d6e899"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/module/{module}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Module"
|
||||
],
|
||||
"description": "Returns a collections of beans",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "module",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Contacts"
|
||||
},
|
||||
{
|
||||
"name": "fields[Contacts]",
|
||||
"in": "query",
|
||||
"description": "Filtering attributes of each bean",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "name,account_type"
|
||||
},
|
||||
{
|
||||
"name": "page[size]",
|
||||
"in": "query",
|
||||
"description": "Number of beans showed in a page",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"example": "4"
|
||||
},
|
||||
{
|
||||
"name": "page[number]",
|
||||
"in": "query",
|
||||
"description": "Number of a page",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"example": "4"
|
||||
},
|
||||
{
|
||||
"name": "sort",
|
||||
"in": "query",
|
||||
"description": "Sorting the bean list based on this parameter. Ascending by default, but if sort is prefixed with a minus (U+002D HYPHEN-MINUS, '-'), sort will be descending",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "-name"
|
||||
},
|
||||
{
|
||||
"name": "filter[operator]",
|
||||
"in": "query",
|
||||
"description": "Filtering the bean collection and using it between two or more conditions as logical operator. Only one level conditions are supported so far. Supported operators: AND, OR",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "AND"
|
||||
},
|
||||
{
|
||||
"name": "filter[name][eq]",
|
||||
"in": "query",
|
||||
"description": "Filtering the bean collections by conditions. The [name] is the bean's property, the [eq] is a comparison operator. Supported operators: EQ, NEQ, GT, GTE, LT, LTE",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "John Doe"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/module": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Module"
|
||||
],
|
||||
"requestBody": {
|
||||
"description": "Create a module record. If ID is not set, it will be created automatically. Attributes is optional, if the new bean will be set with certain, valid properties",
|
||||
"content": {
|
||||
"application/vnd.api+json": {
|
||||
"schema": {
|
||||
"example": {
|
||||
"data": {
|
||||
"type": "Accounts",
|
||||
"id": "86ee02b3-96d2-47b3-bd6d-9e1035daff3a",
|
||||
"attributes": {
|
||||
"name": "Account name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "CREATED"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"Module"
|
||||
],
|
||||
"requestBody": {
|
||||
"description": "Update a module record. Type and ID are required, attributes have to be valid",
|
||||
"content": {
|
||||
"application/vnd.api+json": {
|
||||
"schema": {
|
||||
"example": {
|
||||
"data": {
|
||||
"type": "Accounts",
|
||||
"id": "86ee02b3-96d2-47b3-bd6d-9e1035daff3a",
|
||||
"attributes": {
|
||||
"name": "Another account name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/module/{moduleName}/{id}/relationships/{relationship}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Relationship"
|
||||
],
|
||||
"description": "Get relationship of a bean",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "moduleName",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Accounts"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "11a71596-83e7-624d-c792-5ab9006dd493"
|
||||
},
|
||||
{
|
||||
"name": "relationship",
|
||||
"in": "path",
|
||||
"description": "The name of the relationship related to the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "contacts"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/module/{moduleName}/{id}/relationships": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Relationship"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "moduleName",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Accounts"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "11a71596-83e7-624d-c792-5ab9006dd493"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"description": "Add relationship to a module. The type is the name of the relationship",
|
||||
"content": {
|
||||
"application/vnd.api+json": {
|
||||
"schema": {
|
||||
"example": {
|
||||
"data": {
|
||||
"type": "contacts"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "CREATED"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/module/{moduleName}/{id}/relationships/{relationship}/{relatedBeanId}": {
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Relationship"
|
||||
],
|
||||
"description": "Delete relationship between 2 modules",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "moduleName",
|
||||
"in": "path",
|
||||
"description": "Name of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "Contacts"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "b13a39f8-1c24-c5d0-ba0d-5ab123d6e899"
|
||||
},
|
||||
{
|
||||
"name": "relationship",
|
||||
"in": "path",
|
||||
"description": "The name of the relationship related to the module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "contacts"
|
||||
},
|
||||
{
|
||||
"name": "relatedBeanId",
|
||||
"in": "path",
|
||||
"description": "ID of the related module",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"example": "11806811-0b4b-fcdd-268b-5b2260e68333"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "BAD REQUEST"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/logout": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Logout"
|
||||
],
|
||||
"description": "Logging out",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "UNAUTHORIZED"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"oauth2": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"oauth2": {
|
||||
"type": "oauth2",
|
||||
"flows": {
|
||||
"password": {
|
||||
"tokenUrl": "http://localhost/forkedSuite/Api/access_token",
|
||||
"scopes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
Api/index.php
Normal file
4
Api/index.php
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
chdir('../');
|
||||
require_once __DIR__ . '/Core/app.php';
|
||||
$app->run();
|
|
@ -436,14 +436,11 @@ class ModuleScanner
|
|||
echo "'''Default Extensions'''<br>";
|
||||
foreach ($this->validExt as $b) {
|
||||
echo '#' . $b . '<br>';
|
||||
|
||||
}
|
||||
echo "'''Default Black Listed Functions'''<br>";
|
||||
foreach ($this->blackList as $b) {
|
||||
echo '#' . $b . '<br>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
"psr/log": "^1.0",
|
||||
"league/oauth2-server": "^5.1",
|
||||
"justinrainbow/json-schema": "^5.2",
|
||||
"onelogin/php-saml": "3.0.0.x-dev as 3.0.0",
|
||||
"onelogin/php-saml": "^3.0.0",
|
||||
"google/recaptcha": "^1.1",
|
||||
"symfony/options-resolver": "^3.4",
|
||||
"symfony/validator": "^3.4",
|
||||
"ezyang/htmlpurifier": "^4.10"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -36,7 +38,9 @@
|
|||
"jeroendesloovere/vcard": "v1.5",
|
||||
"browserstack/browserstack-local": "dev-master",
|
||||
"consolidation/robo": "^1.0.0",
|
||||
"mockery/mockery": "^0.9.9"
|
||||
"mockery/mockery": "^0.9.9",
|
||||
"symfony/yaml": "^3.4",
|
||||
"flow/jsonpath": "^0.3"
|
||||
},
|
||||
"scripts": {},
|
||||
"prefer-stable": true,
|
||||
|
@ -51,7 +55,10 @@
|
|||
"SuiteCRM\\Custom\\": [
|
||||
"custom/lib"
|
||||
]
|
||||
}
|
||||
},
|
||||
"classmap": [
|
||||
"Api/"
|
||||
]
|
||||
},
|
||||
"extra": {}
|
||||
}
|
||||
|
|
719
composer.lock
generated
719
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -195,8 +195,7 @@ class One2MBeanRelationship extends One2MRelationship
|
|||
LoggerManager::getLogger()->warn('Incorrect linked relationship rhs ID: ' . get_class($link->getFocus()) . '::$' . $rhsID . ' is undefined');
|
||||
}
|
||||
|
||||
if (!empty($id))
|
||||
{
|
||||
if (!empty($id)) {
|
||||
$rows[$id] = array('id' => $id);
|
||||
}
|
||||
} else { //If the link is LHS, we need to query to get the full list and load all the beans.
|
||||
|
|
|
@ -63,14 +63,14 @@ class JSON
|
|||
/**
|
||||
* JSON encode a string
|
||||
*
|
||||
* @param array $string
|
||||
* @param array $array
|
||||
* @param bool $addSecurityEnvelope defaults to false
|
||||
* @param bool $encodeSpecial
|
||||
* @return string
|
||||
*/
|
||||
public static function encode($string, $addSecurityEnvelope = false, $encodeSpecial = false)
|
||||
public static function encode($array, $addSecurityEnvelope = false, $encodeSpecial = false)
|
||||
{
|
||||
$encodedString = json_encode($string);
|
||||
$encodedString = json_encode($array);
|
||||
|
||||
if ($encodeSpecial) {
|
||||
$charMap = array('<' => '\u003C', '>' => '\u003E', "'" => '\u0027', '&' => '\u0026');
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue