YetiForceCompany/YetiForceCRM

View on GitHub
api/webservice/WebserviceStandard/BaseModule/Fields.php

Summary

Maintainability
C
7 hrs
Test Coverage
A
97%
<?php

/**
 * Webservice standard container - Get fields file.
 *
 * @package API
 *
 * @copyright YetiForce S.A.
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
 * @author    Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
 * @author    Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
 */

namespace Api\WebserviceStandard\BaseModule;

use OpenApi\Annotations as OA;

/**
 * Webservice standard container - Get fields class.
 */
class Fields extends \Api\Core\BaseAction
{
    /** {@inheritdoc}  */
    public $allowedMethod = ['GET'];

    /** {@inheritdoc}  */
    public $allowedHeaders = ['x-response-params'];

    /** @var string[] Response params, options allowed: ["inventory","blocks","privileges","dbStructure","queryOperators"] */
    protected $responseParams = [];

    /**
     * Get data about fields, blocks and inventory.
     *
     * @return array
     *
     * @OA\Get(
     *        path="/webservice/WebserviceStandard/{moduleName}/Fields",
     *        description="Returns information about fields, blocks and inventory based on the selected module",
     *        summary="Get data about fields, blocks and inventory",
     *        tags={"BaseModule"},
     *        security={{"basicAuth" : {}, "ApiKeyAuth" : {}, "token" : {}}},
     *        @OA\Parameter(name="moduleName", in="path", @OA\Schema(type="string"), description="Module name", required=true, example="Contacts"),
     *        @OA\Parameter(name="X-ENCRYPTED", in="header", @OA\Schema(ref="#/components/schemas/Header-Encrypted"), required=true),
     *        @OA\Parameter(name="x-response-params", in="header", description="The header contains information about additional data to be returned in the response [Json array]", required=false,
     *            @OA\JsonContent(type="array", @OA\Items(type="string", enum={"inventory", "blocks", "privileges", "dbStructure", "queryOperators"})),
     *        ),
     *        @OA\Response(response=200, description="Fields, blocks and inventory details",
     *            @OA\JsonContent(ref="#/components/schemas/BaseModule_Get_Fields_Response"),
     *            @OA\XmlContent(ref="#/components/schemas/BaseModule_Get_Fields_Response"),
     *        ),
     *    ),
     *    @OA\Schema(
     *        schema="BaseModule_Get_Fields_Response",
     *        title="Base module - Response action fields",
     *        description="Fields, blocks and inventory details",
     *        type="object",
     *        required={"status", "result"},
     *        @OA\Property(property="status", type="integer", enum={0, 1}, description="A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error"),
     *        @OA\Property(property="result", type="object", title="Fields parameters", required={"fields", "blocks"},
     *            @OA\Property(property="fields", type="object", title="List of all available fields in the module",
     *                required={"name", "label", "type", "mandatory", "defaultvalue", "presence", "quickcreate", "masseditable", "header_field", "maxlengthtext", "maximumlength", "maxwidthcolumn", "tabindex", "fieldtype", "id", "uitype", "sequence", "fieldparams", "blockId", "helpInfo"},
     *                @OA\AdditionalProperties(
     *                    @OA\Property(property="name", type="string", description="Field name", example="subject"),
     *                    @OA\Property(property="label", type="string", description="Field label translated into the user's language", example="Subject"),
     *                    @OA\Property(property="type", type="string", description="Field type", example="string"),
     *                    @OA\Property(property="mandatory", type="boolean", description="Check if field is mandatory", example=true),
     *                    @OA\Property(property="defaultvalue", type="string", description="Default field value", example=""),
     *                    @OA\Property(property="presence", type="boolean", description="Check if field is active", example=true),
     *                    @OA\Property(property="quickcreate", type="boolean", description="Check if field is active", example=true),
     *                    @OA\Property(property="masseditable", type="boolean", description="Check if field is quick create enabled", example=true),
     *                    @OA\Property(property="header_field", type="object", title="Field configuration available in the header",
     *                        @OA\Property(property="type", type="string", description="Type", example="value"),
     *                        @OA\Property(property="class", type="string", description="Gui class", example="badge-info"),
     *                    ),
     *                    @OA\Property(property="maxlengthtext", type="integer", description="Max length text", example=0),
     *                    @OA\Property(property="maximumlength", type="string", description="Maximum field range", example="-2147483648,2147483647"),
     *                    @OA\Property(property="maxwidthcolumn", type="integer", description="Max width column", example=0),
     *                    @OA\Property(property="tabindex", type="integer", description="Field tab index", example=0),
     *                    @OA\Property(property="fieldtype", type="string", description="Field short data type", example="V"),
     *                    @OA\Property(property="picklistvalues", type="object", title="Picklist values, available only for type of field: picklist, multipicklist, multiowner, multiReferenceValue, inventoryLimit, languages, currencyList, fileLocationType, taxes, multiListFields, mailScannerFields, country, modules, sharedOwner, categoryMultipicklist, tree",
     *                    ),
     *                    @OA\Property(property="date-format", type="string", title="Date format, available only for type of field: date, datetime"),
     *                    @OA\Property(property="time-format", type="string", title="Time format, available only for type of field: time"),
     *                    @OA\Property(property="currency_symbol", type="string", title="Currency symbol, available only for type of field: currency"),
     *                    @OA\Property(property="decimal_separator", type="string", title="Currency decimal separator, available only for type of field: currency"),
     *                    @OA\Property(property="group_separator", type="string", title="Currency group separator, available only for type of field: currency"),
     *                    @OA\Property(property="restrictedDomains", type="object", title="Email restricted domains, available only for type of field: email",
     *                        @OA\Property(property="yeti.com", description="List of domains reserved by email", example="yeti.com"),
     *                    ),
     *                    @OA\Property(property="limit", type="integer", title="Limit the amount of images, available only for type of field: multiImage, image"),
     *                    @OA\Property(property="formats", type="object", title="File Format, available only for type of field: multiImage, image",
     *                        @OA\Property(property="jpg", description="List of file data formats", example="jpg"),
     *                    ),
     *                    @OA\Property(property="id", type="integer", description="Field ID", example=24862),
     *                    @OA\Property(property="uitype", type="integer", description="Field UiType", example=1),
     *                    @OA\Property(property="isViewable", description="Check if the field is viewable, depends on header `x-response-params`", type="boolean", example=true),
     *                    @OA\Property(property="isReadOnly", description="Check if the field is read only (based on profiles), depends on header `x-response-params`", type="boolean", example=false),
     *                    @OA\Property(property="isCreatable", description="Check if the field is creatable, depends on header `x-response-params`", type="boolean", example=true),
     *                    @OA\Property(property="isEditable", description="Check if the field is editable, depends on header `x-response-params`", type="boolean", example=true),
     *                    @OA\Property(property="isEditableReadOnly", description="Check if the field is editable or read only (based on the field type), depends on header `x-response-params`", type="boolean", example=false),
     *                    @OA\Property(property="isEditableHidden", description="Check if the field is hidden in the edit (based on the field type), depends on header `x-response-params`", type="boolean", example=false),
     *                    @OA\Property(property="sequence", description="Sequence field", type="integer", example=24862),
     *                    @OA\Property(property="fieldparams", description="Field params", type="object"),
     *                    @OA\Property(property="blockId", type="integer", description="Field block id", example=280),
     *                    @OA\Property(property="helpInfo", type="string", description="Additional field description", example="Edit,Detail"),
     *                    @OA\Property(property="dbStructure", type="object", title="Info about field structure in database, depends on header `x-response-params`",
     *                        @OA\Property(property="name", type="string", description="Name of this column (without quotes).", example="parent_id"),
     *                        @OA\Property(property="allowNull", type="boolean", description="Whether this column can be null.", example=true),
     *                        @OA\Property(property="type", type="string", description="Abstract type of this column.", example="integer"),
     *                        @OA\Property(property="phpType", type="string", description="The PHP type of this column.", example="integer"),
     *                        @OA\Property(property="dbType", type="string", description="The DB type of this column.", example="int(10)"),
     *                        @OA\Property(property="defaultValue", type="string", description="Default value of this column", example="10"),
     *                        @OA\Property(property="enumValues", type="string", description="Enumerable values.", example=""),
     *                        @OA\Property(property="size", type="integer", description="Display size of the column.", example=10),
     *                        @OA\Property(property="precision", type="integer", description="Precision of the column data, if it is numeric.", example=10),
     *                        @OA\Property(property="scale", type="integer", description="Scale of the column data, if it is numeric.", example=0),
     *                        @OA\Property(property="isPrimaryKey", type="boolean", description="Whether this column is a primary key", example=false),
     *                        @OA\Property(property="autoIncrement", type="boolean", description="Whether this column is auto-incremental", example=false),
     *                        @OA\Property(property="unsigned", type="boolean", description="Whether this column is unsigned.", example=false),
     *                        @OA\Property(property="comment", type="string", description="Comment of this column.", example=""),
     *                    ),
     *                    @OA\Property(property="queryOperators", type="object", description="Field query operators, depends on header `x-response-params`"),
     *                    @OA\Property(property="isEmptyPicklistOptionAllowed", description="Defines empty picklist element availability", type="boolean", example=false),
     *                    @OA\Property(property="referenceList", type="object", title="List of related modules, available only for reference field",
     *                        @OA\AdditionalProperties(description="Tree item", type="string", example="Accounts"),
     *                    ),
     *                    @OA\Property(property="treeValues", type="object", title="Tree items, available only for tree field",
     *                        @OA\AdditionalProperties(type="object", title="Tree item",
     *                            @OA\Property(property="id", description="Number tree without prefix", type="integer", example=1),
     *                            @OA\Property(property="tree", description="Tree id", type="string", example="T10"),
     *                            @OA\Property(property="parent", description="Parent tree id", type="string", example="T1"),
     *                            @OA\Property(property="text", description="Tree value", type="string", example="Tree value"),
     *                        ),
     *                    ),
     *                    @OA\Property(property="defaultEditValue", type="object", title="Default field value in editable format",
     *                        @OA\Property(property="value", type="string", description="Value in editable format", example="Some value"),
     *                        @OA\Property(property="raw", type="string", description="Raw value", example="T10"),
     *                    ),
     *                ),
     *            ),
     *            @OA\Property(property="blocks", type="object", title="List of all available blocks in the module, depends on header `x-response-params`",
     *                @OA\AdditionalProperties(type="object", title="Block details",
     *                    required={"id", "tabid", "label", "sequence", "showtitle", "visible", "increateview", "ineditview", "indetailview", "display_status", "iscustom", "icon", "name"},
     *                    @OA\Property(property="id", description="Block id", type="integer", example=195),
     *                    @OA\Property(property="tabid", description="Module id", type="integer", example=9),
     *                    @OA\Property(property="label", description="Block label", type="string", example="Account details"),
     *                    @OA\Property(property="sequence", description="Block sequence", type="integer", example=1),
     *                    @OA\Property(property="showtitle", description="Specifies whether the title should be visible", type="integer", example=0),
     *                    @OA\Property(property="visible", description="Determines the visibility", type="integer", example=0),
     *                    @OA\Property(property="increateview", description="Determines the visibility in creat view", type="integer", example=0),
     *                    @OA\Property(property="ineditview", description="Determines the visibility in edit view", type="integer", example=0),
     *                    @OA\Property(property="indetailview", description="Determines the visibility in detail view", type="integer", example=0),
     *                    @OA\Property(property="display_status", description="Determines whether the block should be expanded", type="integer", example=2),
     *                    @OA\Property(property="iscustom", description="Determines if the block has been added by the user", type="integer", example=0),
     *                    @OA\Property(property="icon", description="Block icon class", type="string",  example="far fa-calendar-alt"),
     *                    @OA\Property(property="name", description="Block name translated into the user's language", type="string", example="Informacje podstawowe o firmie"),
     *                ),
     *            ),
     *            @OA\Property(property="inventory", type="object", title="Inventory field group, available depending on the type of module, depends on header `x-response-params`",
     *                @OA\Property(property="1", type="object", title="Inventory field list",
     *                    @OA\AdditionalProperties(type="object", title="Inventory field details", required={"label", "type", "columnname", "isSummary", "isVisibleInDetail"},
     *                        @OA\Property(property="label", description="Field label translated into the user's language", type="string", example="Unit price"),
     *                        @OA\Property(property="type", description="Field type", type="string", example="UnitPrice"),
     *                        @OA\Property(property="columnname", description="Field column name in db", type="string", example="price"),
     *                        @OA\Property(property="isSummary", description="Is the field contains summary", type="boolean", example=false),
     *                        @OA\Property(property="isVisibleInDetail", description="Check if field is visible in detail view", type="boolean", example=true),
     *                    ),
     *                ),
     *            ),
     *        ),
     *    ),
     * )
     */
    public function get(): array
    {
        $this->loadResponseParams();
        $moduleName = $this->controller->request->get('module');
        $module = \Vtiger_Module_Model::getInstance($moduleName);
        $return = $inventoryFields = $fields = $blocks = [];
        $returnBlocks = isset($this->responseParams['blocks']);
        $returnPrivileges = isset($this->responseParams['privileges']);
        $returnDbStructure = isset($this->responseParams['dbStructure']);
        $returnQueryOperators = isset($this->responseParams['queryOperators']);
        foreach ($module->getFields() as $fieldModel) {
            if (!$fieldModel->isActiveField()) {
                continue;
            }
            \Api\WebserviceStandard\Fields::loadWebserviceByField($fieldModel, $this);
            $block = $fieldModel->get('block');
            if ($returnBlocks && !isset($blocks[$block->id])) {
                $blockProperties = get_object_vars($block);
                $blocks[$block->id] = array_filter($blockProperties, fn ($v) => !\is_object($v));
                $blocks[$block->id]['name'] = \App\Language::translate($block->label, $moduleName);
            }
            $fieldInfo = $fieldModel->getFieldInfo();
            $fieldInfo['id'] = $fieldModel->getId();
            $fieldInfo['uitype'] = $fieldModel->getUIType();
            if ($returnPrivileges) {
                $isEditable = $fieldModel->isEditable();
                $fieldInfo['isViewable'] = $fieldModel->isViewable();
                $fieldInfo['isReadOnly'] = $fieldModel->isReadOnly();
                $fieldInfo['isCreatable'] = $isEditable || 4 === $fieldModel->get('displaytype');
                $fieldInfo['isEditable'] = $isEditable;
                $fieldInfo['isEditableReadOnly'] = $fieldModel->isEditableReadOnly();
                $fieldInfo['isEditableHidden'] = 9 === $fieldModel->get('displaytype');
            }
            $fieldInfo['sequence'] = $fieldModel->get('sequence');
            $fieldInfo['fieldparams'] = $fieldModel->getFieldParams();
            $fieldInfo['blockId'] = $block->id;
            $fieldInfo['helpInfo'] = \App\Language::getTranslateHelpInfo($fieldModel, 'all');
            if ($returnDbStructure) {
                $fieldInfo['dbStructure'] = $fieldModel->getDBColumnType(false);
            }
            if ($returnQueryOperators) {
                $fieldInfo['queryOperators'] = array_map(fn ($value) => \App\Language::translate($value, $moduleName), $fieldModel->getQueryOperators());
            }
            if (isset($fieldInfo['picklistvalues']) && $fieldModel->isEmptyPicklistOptionAllowed()) {
                $fieldInfo['isEmptyPicklistOptionAllowed'] = $fieldModel->isEmptyPicklistOptionAllowed();
            }
            if ($fieldModel->isReferenceField()) {
                $fieldInfo['referenceList'] = $fieldModel->getReferenceList();
            }
            if ($fieldModel->isTreeField()) {
                $fieldInfo['treeValues'] = \App\Fields\Tree::getTreeValues((int) $fieldModel->getFieldParams(), $moduleName);
            }
            if ($fieldModel->get('defaultvalue')) {
                $fieldInfo['defaultEditValue'] = $fieldModel->getUITypeModel()->getApiEditValue($fieldModel->getDefaultFieldValue());
            }
            $fields[$fieldModel->getName()] = $fieldInfo;
        }
        $return['fields'] = $fields;
        if ($returnBlocks) {
            $return['blocks'] = $blocks;
        }
        if (isset($this->responseParams['inventory']) && $module->isInventory()) {
            $inventoryInstance = \Vtiger_Inventory_Model::getInstance($moduleName);
            $fieldsInInventory = $inventoryInstance->getFieldsByBlocks();
            if (isset($fieldsInInventory[1])) {
                foreach ($fieldsInInventory[1] as $fieldName => $fieldModel) {
                    $inventoryFields[1][$fieldName] = [
                        'label' => \App\Language::translate($fieldModel->get('label'), $moduleName),
                        'type' => $fieldModel->getType(),
                        'columnname' => $fieldModel->getColumnName(),
                        'isSummary' => $fieldModel->isSummary(),
                        'isVisibleInDetail' => $fieldModel->isVisibleInDetail(),
                    ];
                }
            }
            $return['inventory'] = $inventoryFields;
        }
        return $return;
    }

    /**
     * Load response params.
     *
     * @return void
     */
    protected function loadResponseParams(): void
    {
        $responseParams = $this->controller->request->getHeader('x-response-params');
        if (empty($responseParams) || '[]' === $responseParams) {
            return;
        }
        if (!\App\Json::isJson($responseParams)) {
            throw new \Api\Core\Exception('Incorrect json syntax: x-response-params', 400);
        }
        $this->responseParams = array_flip(\App\Json::decode($responseParams));
    }
}