YetiForceCompany/YetiForceCRM

View on GitHub
modules/Vtiger/actions/Save.php

Summary

Maintainability
C
7 hrs
Test Coverage
F
22%
<?php
/* +***********************************************************************************
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
 * ("License"); You may not use this file except in compliance with the License
 * The Original Code is:  vtiger CRM Open Source
 * The Initial Developer of the Original Code is vtiger.
 * Portions created by vtiger are Copyright (C) vtiger.
 * All Rights Reserved.
 * Contributor(s): YetiForce S.A.
 * *********************************************************************************** */

class Vtiger_Save_Action extends \App\Controller\Action
{
    use \App\Controller\ExposeMethod;
    /**
     * Record model instance.
     *
     * @var Vtiger_Record_Model
     */
    protected $record;

    /** {@inheritdoc} */
    public function __construct()
    {
        parent::__construct();
        $this->exposeMethod('preSaveValidation');
        $this->exposeMethod('recordChanger');
    }

    /**
     * Function to check permission.
     *
     * @param \App\Request $request
     *
     * @throws \App\Exceptions\NoPermittedToRecord
     */
    public function checkPermission(App\Request $request)
    {
        $moduleName = $request->getModule();
        if ($request->isEmpty('record', true)) {
            $this->record = Vtiger_Record_Model::getCleanInstance($moduleName);
            if (!$this->record->isCreateable()) {
                throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
            }
        } else {
            $recordId = $request->getInteger('record');
            if (!\App\Privilege::isPermitted($moduleName, 'DetailView', $recordId)) {
                throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
            }
            $this->record = Vtiger_Record_Model::getInstanceById($recordId, $moduleName);
            if ('recordChanger' !== $request->getMode() && !$this->record->isEditable()) {
                throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
            }
        }
        if ($request->getBoolean('_isDuplicateRecord') && !\App\Privilege::isPermitted($moduleName, 'DetailView', $request->getInteger('_duplicateRecord'))) {
            throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
        }
        if ($request->has('recordConverter') && !\App\RecordConverter::getInstanceById($request->getInteger('recordConverter'))->isPermitted($request->getInteger('sourceRecord'))) {
            throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
        }
        if ($request->getBoolean('relationOperation') && !\App\Privilege::isPermitted($request->getByType('sourceModule', 2), 'DetailView', $request->getInteger('sourceRecord'))) {
            throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
        }
    }

    /**
     * Process.
     *
     * @param \App\Request $request
     */
    public function process(App\Request $request)
    {
        if ($mode = $request->getMode()) {
            $this->invokeExposedMethod($mode, $request);
        } else {
            $this->saveRecord($request);
            if ($request->getBoolean('relationOperation')) {
                $loadUrl = Vtiger_Record_Model::getInstanceById($request->getInteger('sourceRecord'), $request->getByType('sourceModule', 2))->getDetailViewUrl();
            } elseif ($request->getBoolean('returnToList')) {
                $loadUrl = $this->record->getModule()->getListViewUrl();
            } else {
                $this->record->clearPrivilegesCache();
                if ($this->record->isViewable()) {
                    $loadUrl = $this->record->getDetailViewUrl();
                } else {
                    $loadUrl = $this->record->getModule()->getDefaultUrl();
                }
            }
            header("location: $loadUrl");
        }
    }

    /** {@inheritdoc} */
    public function saveRecord(App\Request $request)
    {
        $this->getRecordModelFromRequest($request);
        $eventHandler = $this->record->getEventHandler();
        $skipHandlers = $request->getArray('skipHandlers', \App\Purifier::ALNUM, [], \App\Purifier::INTEGER);
        foreach ($eventHandler->getHandlers(\App\EventHandler::EDIT_VIEW_PRE_SAVE) as $handler) {
            $handlerId = $handler['eventhandler_id'];
            $response = $eventHandler->triggerHandler($handler);
            if (!($response['result'] ?? null) && (!isset($response['hash'], $skipHandlers[$handlerId]) || $skipHandlers[$handlerId] !== $response['hash'])) {
                throw new \App\Exceptions\NoPermittedToRecord($response['message'], 406);
            }
        }
        if (!$request->isEmpty('fromView') && 'MassQuickCreate' === $request->getByType('fromView')) {
            $this->multiSave($request);
        } else {
            $this->record->save();
            if ($request->has('recordConverter')) {
                $converter = \App\RecordConverter::getInstanceById($request->getInteger('recordConverter'))->set('sourceRecord', $request->getInteger('sourceRecord'));
                $eventHandler->setParams(['converter' => $converter]);
                $eventHandler->trigger(\App\EventHandler::RECORD_CONVERTER_AFTER_SAVE);
            }
        }
        if ($request->getBoolean('relationOperation')) {
            $relationId = $request->isEmpty('relationId') ? false : $request->getInteger('relationId');
            if ($relationModel = Vtiger_Relation_Model::getInstance(Vtiger_Module_Model::getInstance($request->getByType('sourceModule', 2)), $this->record->getModule(), $relationId)) {
                $relationModel->addRelation($request->getInteger('sourceRecord'), $this->record->getId());
            }
        }
    }

    /**
     * Function to get the record model based on the request parameters.
     *
     * @param \App\Request $request
     *
     * @return Vtiger_Record_Model or Module specific Record Model instance
     */
    protected function getRecordModelFromRequest(App\Request $request)
    {
        if (empty($this->record)) {
            $this->record = $request->isEmpty('record', true) ? Vtiger_Record_Model::getCleanInstance($request->getModule()) : Vtiger_Record_Model::getInstanceById($request->getInteger('record'), $request->getModule());
        }
        $fieldModelList = $this->record->getModule()->getFields();
        foreach ($fieldModelList as $fieldName => $fieldModel) {
            if (!$fieldModel->isWritable()) {
                continue;
            }
            if ($request->has($fieldName)) {
                $fieldModel->getUITypeModel()->setValueFromRequest($request, $this->record);
            }
        }
        if ($request->has('inventory') && $this->record->getModule()->isInventory()) {
            $this->record->initInventoryDataFromRequest($request);
        }
        $fromView = $request->has('fromView') ? $request->getByType('fromView') : ($request->isEmpty('record', true) ? 'Create' : 'Edit');
        $fieldsDependency = \App\FieldsDependency::getByRecordModel($fromView, $this->record);
        if ($fields = array_merge($fieldsDependency['hide']['frontend'], $fieldsDependency['hide']['backend'])) {
            foreach ($fields as $fieldName) {
                $this->record->revertPreviousValue($fieldName);
            }
        }
        return $this->record;
    }

    /**
     * Validation before saving.
     *
     * @param App\Request $request
     */
    public function preSaveValidation(App\Request $request)
    {
        $this->getRecordModelFromRequest($request);
        $eventHandler = $this->record->getEventHandler();
        $result = [];
        $skipHandlers = $request->getArray('skipHandlers', \App\Purifier::ALNUM, [], \App\Purifier::INTEGER);
        foreach ($eventHandler->getHandlers(\App\EventHandler::EDIT_VIEW_PRE_SAVE) as $handler) {
            $handlerId = $handler['eventhandler_id'];
            $response = $eventHandler->triggerHandler($handler);
            if (!($response['result'] ?? null) && (!isset($response['hash'], $skipHandlers[$handlerId]) || $skipHandlers[$handlerId] !== $response['hash'])) {
                $result[$handlerId] = $response;
            }
        }
        $response = new Vtiger_Response();
        $response->setEmitType(Vtiger_Response::$EMIT_JSON);
        $response->setResult($result);
        $response->emit();
    }

    /**
     * Quick change of record value.
     *
     * @param App\Request $request
     */
    public function recordChanger(App\Request $request)
    {
        $this->getRecordModelFromRequest($request);
        $id = $request->getInteger('id');
        $field = App\Field::getQuickChangerFields($this->record->getModule()->getId())[$id] ?? false;
        if (!$field || !App\Field::checkQuickChangerConditions($field, $this->record)) {
            throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
        }
        $fields = $this->record->getModule()->getFields();
        foreach ($field['values'] as $fieldName => $value) {
            if (isset($fields[$fieldName]) && $fields[$fieldName]->isEditable()) {
                $this->record->set($fieldName, $value);
            }
        }
        $this->record->save();
        $response = new Vtiger_Response();
        $response->setEmitType(Vtiger_Response::$EMIT_JSON);
        $response->setResult(true);
        $response->emit();
    }

    /**
     * Multiple record save mode.
     *
     * @param App\Request $request
     *
     * @return void
     */
    protected function multiSave(App\Request $request): void
    {
        $moduleName = $request->getByType('module', 'Alnum');
        $multiSaveField = $request->getByType('multiSaveField', 'Alnum');
        $sourceModule = $request->getByType('sourceModule', 'Alnum');
        $sourceView = $request->getByType('sourceView');
        if ('ListView' === $sourceView) {
            $request->set('module', $sourceModule);
            $ids = Vtiger_Mass_Action::getRecordsListFromRequest($request);
            $request->set('module', $moduleName);
        } elseif ('RelatedListView' === $sourceView) {
            $request->set('module', $request->getByType('relatedModule', 'Alnum'));
            $request->set('relatedModule', $request->getByType('sourceModule', 'Alnum'));
            $request->set('record', $request->getByType('relatedRecord', 'Alnum'));
            $ids = Vtiger_RelationAjax_Action::getRecordsListFromRequest($request);
            $request->set('module', $moduleName);
        }
        foreach ($ids as $id) {
            $recordModel = \Vtiger_Record_Model::getCleanInstance($this->record->getModuleName());
            $recordModel->setData($this->record->getData());
            $recordModel->ext = $this->record->ext;
            $recordModel->set($multiSaveField, $id);
            $recordModel->save();
        }
    }
}