Files
iTop/sources/Controller/Links/LinkSetController.php

304 lines
9.7 KiB
PHP

<?php
/*
* @copyright Copyright (C) 2010-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Controller\Links;
use AjaxPage;
use cmdbAbstractObject;
use Combodo\iTop\Application\Helper\FormHelper;
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
use Combodo\iTop\Controller\AbstractController;
use Combodo\iTop\Service\Links\LinkSetModel;
use Combodo\iTop\Service\Router\Router;
use Combodo\iTop\Service\Base\ObjectRepository;
use Dict;
use Exception;
use JsonPage;
use CoreException;
use DBObject;
use MetaModel;
use UserRights;
use utils;
/**
* Class LinkSetController
*
* @internal
* @since 3.1.0
* @package Combodo\iTop\Controller
*/
class LinkSetController extends AbstractController
{
public const ROUTE_NAMESPACE = 'linkset';
/**
* OperationDeleteLinkedObject.
*
* @return JsonPage
* @throws \CoreException
*/
public function OperationDeleteLinkedObject(): JsonPage
{
if (!$this->IsHandlingXmlHttpRequest()) {
throw new CoreException('LinksetController can only be called in ajax.');
}
$oPage = new JsonPage();
$sErrorMessage = null;
$bOperationSuccess = false;
// retrieve parameters
$sLinkedObjectClass = utils::ReadParam('linked_object_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
$sLinkedObjectObjectKey = utils::ReadParam('linked_object_key', 0, false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sTransactionId = utils::ReadParam('transaction_id', null, false, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
// check transaction id
if (utils::IsTransactionValid($sTransactionId, false)) {
try {
$oDeletionPlan = MetaModel::GetObject($sLinkedObjectClass, $sLinkedObjectObjectKey)->DBDelete();
$bOperationSuccess = (count($oDeletionPlan->GetIssues()) === 0);
if (!$bOperationSuccess) {
$sErrorMessage = json_encode($oDeletionPlan->GetIssues());
}
}
catch (Exception $e) {
$sErrorMessage = $e->getMessage();
}
} else {
$sErrorMessage = 'invalid transaction id';
}
$oPage->SetData([
'success' => $bOperationSuccess,
'error_message' => $sErrorMessage,
]);
return $oPage;
}
/**
* OperationDetachLinkedObject.
*
* @return \JsonPage
* @throws \CoreException
*/
public function OperationDetachLinkedObject(): JsonPage
{
if (!$this->IsHandlingXmlHttpRequest()) {
throw new CoreException('LinksetController can only be called in ajax.');
}
$oPage = new JsonPage();
$sErrorMessage = null;
$bOperationSuccess = false;
// retrieve parameters
$sLinkedObjectClass = utils::ReadParam('linked_object_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
$sLinkedObjectKey = utils::ReadParam('linked_object_key', 0, false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sExternalKeyAttCode = utils::ReadParam('external_key_att_code', null, false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sTransactionId = utils::ReadParam('transaction_id', null, false, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
// check transaction id
if (utils::IsTransactionValid($sTransactionId, false)) {
try {
$oLinkedObject = MetaModel::GetObject($sLinkedObjectClass, $sLinkedObjectKey);
$oLinkedObject->Set($sExternalKeyAttCode, null);
$oLinkedObject->DBWrite();
$bOperationSuccess = true;
}
catch (Exception $e) {
$sErrorMessage = $e->getMessage();
}
} else {
$sErrorMessage = 'invalid transaction id';
}
$oPage->SetData([
'success' => $bOperationSuccess,
'error_message' => $sErrorMessage,
]);
return $oPage;
}
/**
* @return \AjaxPage Create edit form in its webpage
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \SecurityException
*/
public function OperationCreateLinkedObject(): AjaxPage
{
if (!$this->IsHandlingXmlHttpRequest()) {
throw new CoreException('LinksetController can only be called in ajax.');
}
$oRouter = Router::GetInstance();
$oPage = new AjaxPage('');
$sProposedRealClass = utils::ReadParam('class', '', false, 'class');
$sAttCode = utils::ReadParam('att_code', '', false, 'raw');
$sClass = utils::ReadParam('host_class', '', false, 'class');
$sId = utils::ReadParam('host_id', '', false, 'integer');
$sFormTitle = utils::ReadPostedParam('form_title', null, utils::ENUM_SANITIZATION_FILTER_STRING);
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$sRealClass = '';
$aSubClasses = MetaModel::EnumChildClasses($sProposedRealClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array();
foreach ($aSubClasses as $sCandidateClass) {
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
if ($sCandidateClass == $sProposedRealClass) {
$sRealClass = $sProposedRealClass;
}
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
}
}
// Only one of the subclasses can be instantiated...
if (count($aPossibleClasses) == 1) {
$aKeys = array_keys($aPossibleClasses);
$sRealClass = $aKeys[0];
}
if ($sRealClass != '') {
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aFieldFlags = array($sExtKeyToMe => OPT_ATT_READONLY);
$oObj = DBObject::MakeDefaultInstance($sRealClass);
$oSourceObj = MetaModel::GetObject($sClass, $sId);
$oObj->Set($sExtKeyToMe, $sId);
$aPrefillParam = array('source_obj' => $oSourceObj);
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
// We display this form in a modal, once we submit (in ajax) we probably want to only close the modal
$sFormOnSubmitJsCode =
<<<JS
event.preventDefault();
if(bOnSubmitForm === true)
{
let oForm = $(this);
let sUrl = oForm.attr('action');
let sPosting = $.post( sUrl, oForm.serialize());
/* Alerts the results */
sPosting.done(function(data) {
// fire event
oForm.trigger('itop.form.submitted', [data]);
if(data.success !== undefined && data.success === true) {
oForm.closest('[data-role="ibo-modal"]').dialog('close');
}
else {
/* We're not in submit anymore */
window.bInSubmit = false;
oForm.attr('data-form-state', 'default');
/* Display error popup */
CombodoModal.OpenErrorModal(data.data.error_message);
}
});
}
JS;
$aExtraParams = [
'noRelations' => true,
'hide_transitions' => true,
'formPrefix' => $sAttCode,
'fieldsFlags' => $aFieldFlags,
'forceFieldsSubmission' => [
$sExtKeyToMe,
],
'form_title' => $sFormTitle,
'custom_button' => \Dict::S('UI:Button:Add'),
'js_handlers' => [
'form_on_submit' => $sFormOnSubmitJsCode,
'cancel_button_on_click' =>
<<<JS
function() {
$(this).closest('[data-role="ibo-modal"]').dialog('close');
};
JS
,
],
];
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
FormHelper::DisableAttributeBlobInputs($sRealClass, $aExtraParams);
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), $aExtraParams);
}
else
{
// - We'll let the user select a class if multiple classes are available
$oClassForm = FormUIBlockFactory::MakeStandard();
// - When the user submit, redo the same request but with a real class
$sCurrentParameters = json_encode([
'att_code' => $sAttCode,
'host_class' => $sClass,
'host_id' => $sId]);
$sCurrentUrl = $oRouter->GenerateUrl('linkset.create_linked_object');
$oClassForm->SetOnSubmitJsCode(
<<<JS
let me = this;
let aParam = $sCurrentParameters;
aParam['class'] = $(this).find('[name="class"]').val();
let sPosting = $.post('$sCurrentUrl', aParam);
sPosting.done(function(data){
$(me).closest('[data-role="ibo-modal"]').html(data);
});
return false;
JS
);
// - Add a select and a button to validate the form
$oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate($sProposedRealClass, MetaModel::GetName($sProposedRealClass), $aPossibleClasses));
$oPage->AddUiBlock($oClassForm);
}
return $oPage;
}
/**
* OperationGetRemoteObject.
*
* @return JsonPage
*/
public function OperationGetRemoteObject(): JsonPage
{
$oPage = new JsonPage();
$bSuccess = true;
$aObjectData = null;
// Retrieve query params
$sObjectClass = utils::ReadParam('linked_object_class', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sObjectKey = utils::ReadParam('linked_object_key', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sRemoteClass = utils::ReadParam('remote_class', null, false, utils::ENUM_SANITIZATION_FILTER_STRING);
$sRemoteExtKey = utils::ReadParam('external_key_att_code', null, false, utils::ENUM_SANITIZATION_FILTER_STRING);
// Retrieve object
try {
$oObject = MetaModel::GetObject($sObjectClass, $sObjectKey);
$sLinkKey = $oObject->GetKey();
if (!utils::IsNullOrEmptyString($sRemoteExtKey)) {
$oObject = MetaModel::GetObject($sRemoteClass, $oObject->Get($sRemoteExtKey));
}
$aObjectData = ObjectRepository::ConvertObjectToArray($oObject, $sObjectClass);
$aObjectData['link_keys'] = [$sObjectKey];
}
catch (Exception $e) {
$bSuccess = false;
}
return $oPage->SetData([
'object' => $aObjectData,
'success' => $bSuccess,
]);
}
}