mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 07:12:26 +02:00
N°803 - Allow display & edition of attributes on n:n relations on Portal
This commit is contained in:
@@ -2385,43 +2385,59 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
{
|
||||
if ($oFormField === null)
|
||||
{
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
// Setting target class
|
||||
// Setting target class
|
||||
if (!$this->IsIndirect()) {
|
||||
$sTargetClass = $this->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sTargetClass = $oRemoteAttDef->GetTargetClass();
|
||||
$sTargetClass = $this->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sTargetClass = $oRemoteAttDef->GetTargetClass();
|
||||
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oFormField->SetExtKeyToRemote($this->GetExtKeyToRemote());
|
||||
}
|
||||
$oFormField->SetTargetClass($sTargetClass);
|
||||
$oFormField->SetIndirect($this->IsIndirect());
|
||||
// Setting attcodes to display
|
||||
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
|
||||
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
|
||||
}
|
||||
// - Adding attribute labels
|
||||
$aAttributesToDisplay = array();
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = $oAttDefToDisplay->GetLabel();
|
||||
}
|
||||
$oFormField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oFormField->SetExtKeyToRemote($this->GetExtKeyToRemote());
|
||||
}
|
||||
$oFormField->SetTargetClass($sTargetClass);
|
||||
$oFormField->SetLinkedClass($this->GetLinkedClass());
|
||||
$oFormField->SetIndirect($this->IsIndirect());
|
||||
// Setting attcodes to display
|
||||
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
|
||||
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
|
||||
}
|
||||
// - Adding attribute properties
|
||||
$aAttributesToDisplay = array();
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = [
|
||||
'label' => $oAttDefToDisplay->GetLabel(),
|
||||
'mandatory' => !$oAttDefToDisplay->IsNullAllowed(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
// Append lnk attributes (filtered from zlist)
|
||||
$aLnkAttDefToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($this->m_sHostClass, $this->m_sCode);
|
||||
$aLnkAttributesToDisplay = array();
|
||||
foreach ($aLnkAttDefToDisplay as $oLnkAttDefToDisplay) {
|
||||
$aLnkAttributesToDisplay[$oLnkAttDefToDisplay->GetCode()] = [
|
||||
'sortable' => false,
|
||||
'label' => $oLnkAttDefToDisplay->GetLabel(),
|
||||
'mandatory' => !$oLnkAttDefToDisplay->IsNullAllowed(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetLnkAttributesToDisplay($aLnkAttributesToDisplay);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function IsPartOfFingerprint()
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1802,3 +1802,22 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
|
||||
.wiki_broken_link {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
/**********************************************************/
|
||||
/* Shameful area (things that should be refactored soon) */
|
||||
/**********************************************************/
|
||||
|
||||
/* Hide attributes label in link set edition, will be fixed during attributes refactoring */
|
||||
.form_linkedset_wrapper label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Add mandatory field column label */
|
||||
.form_linkedset_wrapper .dataTables_scrollHead th.mandatory:after {
|
||||
content: "*";
|
||||
position: relative;
|
||||
left: 3px;
|
||||
color: #EA7D1E;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ use BinaryExpression;
|
||||
use Combodo\iTop\Portal\Brick\CreateBrick;
|
||||
use Combodo\iTop\Portal\Helper\ApplicationHelper;
|
||||
use Combodo\iTop\Portal\Helper\ContextManipulatorHelper;
|
||||
use Combodo\iTop\Renderer\Bootstrap\FieldRenderer\BsLinkedSetFieldRenderer;
|
||||
use DBObject;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
@@ -1312,14 +1313,20 @@ class ObjectController extends BrickController
|
||||
/** @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidator */
|
||||
$oScopeValidator = $this->get('scope_validator');
|
||||
|
||||
$aData = array();
|
||||
// Data array
|
||||
$aData = array(
|
||||
'js_inline' => '',
|
||||
'css_inline' => '',
|
||||
);
|
||||
|
||||
// Retrieving parameters
|
||||
$sObjectClass = $oRequestManipulator->ReadParam('sObjectClass', '');
|
||||
$sLinkClass = $oRequestManipulator->ReadParam('sLinkClass', '');
|
||||
$aObjectIds = $oRequestManipulator->ReadParam('aObjectIds', array(), FILTER_UNSAFE_RAW);
|
||||
$aObjectAttCodes = $oRequestManipulator->ReadParam('aObjectAttCodes', array(), FILTER_UNSAFE_RAW);
|
||||
if (empty($sObjectClass) || empty($aObjectIds) || empty($aObjectAttCodes))
|
||||
{
|
||||
$aLinkAttCodes = $oRequestManipulator->ReadParam('aLinkAttCodes', array(), FILTER_UNSAFE_RAW);
|
||||
|
||||
if (empty($sObjectClass) || empty($aObjectIds) || empty($aObjectAttCodes)) {
|
||||
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : sObjectClass, aObjectIds and aObjectAttCodes expected, "'.$sObjectClass.'", "'.implode('/',
|
||||
$aObjectIds).'" given.');
|
||||
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Invalid request data, some information are missing');
|
||||
@@ -1338,15 +1345,35 @@ class ObjectController extends BrickController
|
||||
|
||||
// Checking that id is in the AttCodes
|
||||
// Note: We do that AFTER the array is used in OptimizeColumnLoad() because the function doesn't support this anymore.
|
||||
if (!in_array('id', $aObjectAttCodes))
|
||||
{
|
||||
if (!in_array('id', $aObjectAttCodes)) {
|
||||
$aObjectAttCodes = array_merge(array('id'), $aObjectAttCodes);
|
||||
}
|
||||
|
||||
// Retrieving objects
|
||||
while ($oObject = $oSet->Fetch())
|
||||
{
|
||||
$aData['items'][] = $this->PrepareObjectInformation($oObject, $aObjectAttCodes);
|
||||
while ($oObject = $oSet->Fetch()) {
|
||||
// Prepare link data
|
||||
$aObjectData = $this->PrepareObjectInformation($oObject, $aObjectAttCodes);
|
||||
// New link object (needed for renderers)
|
||||
$oNewLink = new $sLinkClass();
|
||||
foreach ($aLinkAttCodes as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
$oField = $oAttDef->MakeFormField($oNewLink);
|
||||
$sFieldRendererClass = BsLinkedSetFieldRenderer::GetFieldRendererClass($oField);
|
||||
$sValue = $oAttDef->GetAsHTML($oNewLink->Get($sAttCode));
|
||||
if ($sFieldRendererClass !== null) {
|
||||
$oFieldRenderer = new $sFieldRendererClass($oField);
|
||||
$oFieldOutput = $oFieldRenderer->Render();
|
||||
$sValue = $oFieldOutput->GetHtml();
|
||||
}
|
||||
$aObjectData['attributes'][$sAttCode] = [
|
||||
'att_code' => $sAttCode,
|
||||
'value' => $sValue,
|
||||
'css_inline' => $oFieldOutput->GetCss(),
|
||||
'js_inline' => $oFieldOutput->GetJs(),
|
||||
];
|
||||
}
|
||||
|
||||
$aData['items'][] = $aObjectData;
|
||||
}
|
||||
|
||||
return new JsonResponse($aData);
|
||||
@@ -1356,7 +1383,7 @@ class ObjectController extends BrickController
|
||||
* Prepare a DBObject information as an array for a client side usage (typically, add a row in a table)
|
||||
*
|
||||
* @param \DBObject $oObject
|
||||
* @param array $aAttCodes
|
||||
* @param array $aAttCodes
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
@@ -1372,8 +1399,8 @@ class ObjectController extends BrickController
|
||||
|
||||
$sObjectClass = get_class($oObject);
|
||||
$aObjectData = array(
|
||||
'id' => $oObject->GetKey(),
|
||||
'name' => $oObject->GetName(),
|
||||
'id' => $oObject->GetKey(),
|
||||
'name' => $oObject->GetName(),
|
||||
'attributes' => array(),
|
||||
);
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ use Exception;
|
||||
use ExceptionLog;
|
||||
use InlineImage;
|
||||
use IssueLog;
|
||||
use LogChannels;
|
||||
use MetaModel;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
@@ -859,7 +860,10 @@ class ObjectFormManager extends FormManager
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay)
|
||||
{
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($oField->GetTargetClass(), $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = $oAttDefToDisplay->GetLabel();
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = [
|
||||
'label' => $oAttDefToDisplay->GetLabel(),
|
||||
'mandatory' => !$oAttDefToDisplay->IsNullAllowed(),
|
||||
];
|
||||
}
|
||||
$oField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
}
|
||||
@@ -869,7 +873,7 @@ class ObjectFormManager extends FormManager
|
||||
|
||||
/** @var \ormLinkSet $oFieldOriginalSet */
|
||||
$oFieldOriginalSet = $oField->GetCurrentValue();
|
||||
while ($oLink = $oFieldOriginalSet->Fetch()) {
|
||||
foreach ($oFieldOriginalSet as $oLink) {
|
||||
if ($oField->IsIndirect()) {
|
||||
$iRemoteKey = $oLink->Get($oAttDef->GetExtKeyToRemote());
|
||||
} else {
|
||||
@@ -1099,7 +1103,7 @@ class ObjectFormManager extends FormManager
|
||||
{
|
||||
$aData = parent::OnSubmit($aArgs);
|
||||
|
||||
if (! $aData['valid']) {
|
||||
if (!$aData['valid']) {
|
||||
return $aData;
|
||||
}
|
||||
|
||||
@@ -1282,6 +1286,15 @@ class ObjectFormManager extends FormManager
|
||||
$oLink = MetaModel::NewObject($sLinkedClass);
|
||||
$oLink->Set($oAttDef->GetExtKeyToRemote(), $iObjKey);
|
||||
$oLink->Set($oAttDef->GetExtKeyToMe(), $this->oObject->GetKey());
|
||||
// Set link attributes values...
|
||||
foreach ($aObjdata as $sLinkAttCode => $oAttValue) {
|
||||
if (!is_scalar($oAttValue)) {
|
||||
IssueLog::Debug("ObjectFormManager::OnUpdate invalid link attribute value, $sLinkAttCode is not a scalar value", LogChannels::PORTAL);
|
||||
continue;
|
||||
}
|
||||
$oLink->Set($sLinkAttCode, $oAttValue);
|
||||
}
|
||||
$oLinkSet->AddItem($oLink);
|
||||
}
|
||||
// ... or adding remote object when linkset id direct
|
||||
else
|
||||
@@ -1290,15 +1303,36 @@ class ObjectFormManager extends FormManager
|
||||
$oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false, true);
|
||||
}
|
||||
|
||||
if ($oLink !== null)
|
||||
{
|
||||
if ($oLink !== null) {
|
||||
$oLinkSet->AddItem($oLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking links to modify
|
||||
// TODO: Not implemented yet as we can't change lnk properties in the portal
|
||||
if ($oAttDef->IsIndirect() && isset($value['current'])) {
|
||||
foreach ($value['current'] as $iObjKey => $aObjData) {
|
||||
if ($iObjKey < 0) {
|
||||
continue;
|
||||
}
|
||||
$oLink = null;
|
||||
$oLinkSet->Rewind();
|
||||
foreach ($oLinkSet as $oItem) {
|
||||
if ($oItem->Get('id') != $iObjKey) {
|
||||
continue;
|
||||
}
|
||||
$oLink = $oItem;
|
||||
foreach ($aObjData as $sLinkAttCode => $oAttValue) {
|
||||
if (!is_scalar($oAttValue)) {
|
||||
IssueLog::Debug("ObjectFormManager::OnUpdate invalid link attribute value, $sLinkAttCode is not a scalar value", LogChannels::PORTAL);
|
||||
continue;
|
||||
}
|
||||
$oLink->Set($sLinkAttCode, $oAttValue);
|
||||
}
|
||||
$oLinkSet->ModifyItem($oLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setting value in the object
|
||||
$this->oObject->Set($sAttCode, $oLinkSet);
|
||||
|
||||
@@ -70,4 +70,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Links:Bulk:LinkExistForAllObjects' => 'All objets are already linked',
|
||||
'UI:Links:Bulk:LinkExistForOneObject' => 'One object is linked',
|
||||
'UI:Links:Bulk:LinkExistForXObjects' => '{count} objects are linked',
|
||||
|
||||
// New item
|
||||
'UI:Links:NewItem' => 'New item',
|
||||
));
|
||||
@@ -71,4 +71,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Links:Bulk:LinkExistForAllObjects' => 'Tous les objets sont déjà liés',
|
||||
'UI:Links:Bulk:LinkExistForOneObject' => 'Un objet est lié',
|
||||
'UI:Links:Bulk:LinkExistForXObjects' => '{count} objets sont liés',
|
||||
|
||||
// New item
|
||||
'UI:Links:NewItem' => 'Nouvel element',
|
||||
));
|
||||
@@ -21,6 +21,8 @@
|
||||
namespace Combodo\iTop\Form\Field;
|
||||
|
||||
use Closure;
|
||||
use Dict;
|
||||
use ormLinkSet;
|
||||
|
||||
/**
|
||||
* Description of LinkedSetField
|
||||
@@ -35,10 +37,12 @@ class LinkedSetField extends Field
|
||||
/** @var bool DEFAULT_DISPLAY_OPENED */
|
||||
const DEFAULT_DISPLAY_OPENED = false;
|
||||
/** @var bool DEFAULT_DISPLAY_LIMITED_ACCESS_ITEMS */
|
||||
const DEFAULT_DISPLAY_LIMITED_ACCESS_ITEMS = false;
|
||||
|
||||
const DEFAULT_DISPLAY_LIMITED_ACCESS_ITEMS = false;
|
||||
|
||||
/** @var string $sTargetClass */
|
||||
protected $sTargetClass;
|
||||
/** @var string $sLinkedClass */
|
||||
protected $sLinkedClass;
|
||||
/** @var string $sExtKeyToRemote */
|
||||
protected $sExtKeyToRemote;
|
||||
/** @var bool $bIndirect */
|
||||
@@ -51,6 +55,8 @@ class LinkedSetField extends Field
|
||||
protected $aLimitedAccessItemIDs;
|
||||
/** @var array $aAttributesToDisplay */
|
||||
protected $aAttributesToDisplay;
|
||||
/** @var array $aLnkAttributesToDisplay */
|
||||
protected $aLnkAttributesToDisplay;
|
||||
/** @var string $sSearchEndpoint */
|
||||
protected $sSearchEndpoint;
|
||||
/** @var string $sInformationEndpoint */
|
||||
@@ -68,6 +74,7 @@ class LinkedSetField extends Field
|
||||
$this->bDisplayLimitedAccessItems = static::DEFAULT_DISPLAY_LIMITED_ACCESS_ITEMS;
|
||||
$this->aLimitedAccessItemIDs = array();
|
||||
$this->aAttributesToDisplay = array();
|
||||
$this->aLnkAttributesToDisplay = array();
|
||||
$this->sSearchEndpoint = null;
|
||||
$this->sInformationEndpoint = null;
|
||||
|
||||
@@ -96,6 +103,31 @@ class LinkedSetField extends Field
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 3.1
|
||||
*
|
||||
*/
|
||||
public function GetLinkedClass()
|
||||
{
|
||||
return $this->sLinkedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param string $sLinkedClass
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetLinkedClass(string $sLinkedClass)
|
||||
{
|
||||
$this->sLinkedClass = $sLinkedClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
@@ -237,6 +269,35 @@ class LinkedSetField extends Field
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash array of attributes to be displayed in the linkedset in the form $sAttCode => $sAttLabel
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param boolean $bAttCodesOnly If set to true, will return only the attcodes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetLnkAttributesToDisplay(bool $bAttCodesOnly = false)
|
||||
{
|
||||
return ($bAttCodesOnly) ? array_keys($this->aLnkAttributesToDisplay) : $this->aLnkAttributesToDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param array $aAttributesToDisplay
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetLnkAttributesToDisplay(array $aAttributesToDisplay)
|
||||
{
|
||||
$this->aLnkAttributesToDisplay = $aAttributesToDisplay;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
@@ -288,4 +349,30 @@ class LinkedSetField extends Field
|
||||
{
|
||||
return in_array($iItemID, $this->aLimitedAccessItemIDs, false);
|
||||
}
|
||||
|
||||
/** @inheritdoc @since 3.1 */
|
||||
public function Validate()
|
||||
{
|
||||
$bValid = parent::Validate();
|
||||
|
||||
/** @var ormLinkSet $oSet */
|
||||
$oSet = $this->GetCurrentValue();
|
||||
|
||||
/** @var \DBObject $oItem */
|
||||
foreach ($oSet as $oItem) {
|
||||
list($bRes, $aIssues) = $oItem->CheckToWrite();
|
||||
if ($bRes === false) {
|
||||
foreach ($aIssues as $sIssue) {
|
||||
$sItem = $oItem->Get('friendlyname') != '' ? $oItem->Get('friendlyname') : Dict::S('UI:Links:NewItem');
|
||||
$this->AddErrorMessage('<b>'.$sItem.' : </b>'.$sIssue);
|
||||
}
|
||||
$bValid = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$oSet->Rewind();
|
||||
|
||||
return $bValid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace Combodo\iTop\Renderer\Bootstrap\FieldRenderer;
|
||||
|
||||
use ApplicationContext;
|
||||
use AttributeFriendlyName;
|
||||
use Combodo\iTop\Form\Field\Field;
|
||||
use Combodo\iTop\Renderer\Bootstrap\BsFieldRendererMappings;
|
||||
use Combodo\iTop\Renderer\FieldRenderer;
|
||||
use Combodo\iTop\Renderer\RenderingOutput;
|
||||
use DBObject;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
@@ -43,52 +48,62 @@ class BsLinkedSetFieldRenderer extends BsFieldRenderer
|
||||
*/
|
||||
public function Render()
|
||||
{
|
||||
$oOutput = parent::Render();
|
||||
$oOutput = parent::Render();
|
||||
|
||||
$sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : '';
|
||||
$sFieldDescriptionForHTMLTag = ($this->oField->HasDescription()) ? 'data-tooltip-content="'.utils::HtmlEntities($this->oField->GetDescription()).'"' : '';
|
||||
|
||||
// Merge lnk and remote class attributes to display
|
||||
$aAttributesToDisplay = array_merge($this->oField->GetLnkAttributesToDisplay(), $this->oField->GetAttributesToDisplay());
|
||||
$iLinkAttributesToDisplayCount = count($this->oField->GetLnkAttributesToDisplay()) + 1;
|
||||
|
||||
// Vars to build the table
|
||||
$sAttributesToDisplayAsJson = json_encode($this->oField->GetAttributesToDisplay());
|
||||
$sAttributesToDisplayAsJson = json_encode($aAttributesToDisplay);
|
||||
$sAttCodesToDisplayAsJson = json_encode($this->oField->GetAttributesToDisplay(true));
|
||||
$sLnkAttCodesToDisplayAsJson = json_encode($this->oField->GetLnkAttributesToDisplay(true));
|
||||
|
||||
|
||||
$aItems = array();
|
||||
$aItemIds = array();
|
||||
$this->PrepareItems($aItems, $aItemIds);
|
||||
$aAddedItemIds = array();
|
||||
$aAddedTargetIds = array();
|
||||
$this->InjectRendererFileAssets($this->oField->GetLinkedClass(), $this->oField->GetLnkAttributesToDisplay(true), $oOutput);
|
||||
$this->PrepareItems($aItems, $aItemIds, $oOutput, $aAddedItemIds, $aAddedTargetIds);
|
||||
$sItemsAsJson = json_encode($aItems);
|
||||
$sItemIdsAsJson = utils::EscapeHtml(json_encode(array('current' => $aItemIds)));
|
||||
$sItemIdsAsJson = utils::EscapeHtml(json_encode(array('current' => $aItemIds, 'add' => $aAddedItemIds)));
|
||||
|
||||
if (!$this->oField->GetHidden())
|
||||
{
|
||||
foreach ($aAddedTargetIds as $sId) {
|
||||
$aItemIds[$sId] = array();
|
||||
}
|
||||
|
||||
if (!$this->oField->GetHidden()) {
|
||||
// Rendering field
|
||||
$sIsEditable = ($this->oField->GetReadOnly()) ? 'false' : 'true';
|
||||
$sCollapseTogglerIconVisibleClass = 'glyphicon-menu-down';
|
||||
$sCollapseTogglerIconHiddenClass = 'glyphicon-menu-down collapsed';
|
||||
$sCollapseTogglerClass = 'form_linkedset_toggler';
|
||||
$sCollapseTogglerId = $sCollapseTogglerClass . '_' . $this->oField->GetGlobalId();
|
||||
$sFieldWrapperId = 'form_linkedset_wrapper_' . $this->oField->GetGlobalId();
|
||||
$sCollapseTogglerId = $sCollapseTogglerClass.'_'.$this->oField->GetGlobalId();
|
||||
$sFieldWrapperId = 'form_linkedset_wrapper_'.$this->oField->GetGlobalId();
|
||||
|
||||
// Preparing collapsed state
|
||||
if($this->oField->GetDisplayOpened())
|
||||
{
|
||||
$sCollapseTogglerExpanded = 'true';
|
||||
$sCollapseTogglerIconClass = $sCollapseTogglerIconVisibleClass;
|
||||
$sCollapseJSInitState = 'true';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCollapseTogglerClass .= ' collapsed';
|
||||
$sCollapseTogglerExpanded = 'false';
|
||||
$sCollapseTogglerIconClass = $sCollapseTogglerIconHiddenClass;
|
||||
$sCollapseJSInitState = 'false';
|
||||
}
|
||||
if ($this->oField->GetDisplayOpened()) {
|
||||
$sCollapseTogglerExpanded = 'true';
|
||||
$sCollapseTogglerIconClass = $sCollapseTogglerIconVisibleClass;
|
||||
$sCollapseJSInitState = 'true';
|
||||
} else {
|
||||
$sCollapseTogglerClass .= ' collapsed';
|
||||
$sCollapseTogglerExpanded = 'false';
|
||||
$sCollapseTogglerIconClass = $sCollapseTogglerIconHiddenClass;
|
||||
$sCollapseJSInitState = 'false';
|
||||
}
|
||||
|
||||
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
|
||||
if ($this->oField->GetLabel() !== '')
|
||||
{
|
||||
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label" '.$sFieldDescriptionForHTMLTag.'>')
|
||||
->AddHtml('<a id="' . $sCollapseTogglerId . '" class="' . $sCollapseTogglerClass . '" data-toggle="collapse" href="#' . $sFieldWrapperId . '" aria-expanded="' . $sCollapseTogglerExpanded . '" aria-controls="' . $sFieldWrapperId . '">')
|
||||
$oOutput->AddHtml('<div class="form-group '.$sFieldMandatoryClass.'">');
|
||||
if ($this->oField->GetLabel() !== '') {
|
||||
$oOutput->AddHtml('<label for="'.$this->oField->GetGlobalId().'" class="control-label" '.$sFieldDescriptionForHTMLTag.'>')
|
||||
->AddHtml('<a id="'.$sCollapseTogglerId.'" class="'.$sCollapseTogglerClass.'" data-toggle="collapse" href="#'.$sFieldWrapperId.'" aria-expanded="'.$sCollapseTogglerExpanded.'" aria-controls="'.$sFieldWrapperId.'">')
|
||||
->AddHtml($this->oField->GetLabel(), true)
|
||||
->AddHtml('<span class="text">' . count($aItemIds) . '</span>')
|
||||
->AddHtml('<span class="glyphicon ' . $sCollapseTogglerIconClass . '"></>')
|
||||
->AddHtml('<span class="text">'.count($aItemIds).'</span>')
|
||||
->AddHtml('<span class="glyphicon '.$sCollapseTogglerIconClass.'"></>')
|
||||
->AddHtml('</a>')
|
||||
->AddHtml('</label>');
|
||||
}
|
||||
@@ -99,7 +114,7 @@ class BsLinkedSetFieldRenderer extends BsFieldRenderer
|
||||
$sTableId = 'table_' . $this->oField->GetGlobalId();
|
||||
// - Output
|
||||
$oOutput->AddHtml(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
<div class="form_linkedset_wrapper collapse" id="{$sFieldWrapperId}">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
@@ -150,6 +165,7 @@ EOF
|
||||
var oRawDatas_{$this->oField->GetGlobalId()} = {$sItemsAsJson};
|
||||
var oTable_{$this->oField->GetGlobalId()};
|
||||
var oSelectedItems_{$this->oField->GetGlobalId()} = {};
|
||||
var oRenderersJs_{$this->oField->GetGlobalId()} = '';
|
||||
|
||||
var getColumnsDefinition_{$this->oField->GetGlobalId()} = function()
|
||||
{
|
||||
@@ -182,15 +198,17 @@ EOF
|
||||
|
||||
for(sKey in oColumnProperties_{$this->oField->GetGlobalId()})
|
||||
{
|
||||
aColumnProperties = oColumnProperties_{$this->oField->GetGlobalId()}[sKey];
|
||||
// Level main column
|
||||
aColumnsDefinition.push({
|
||||
"width": "auto",
|
||||
"searchable": true,
|
||||
"sortable": true,
|
||||
"title": oColumnProperties_{$this->oField->GetGlobalId()}[sKey],
|
||||
"sortable": !aColumnProperties.sortable,
|
||||
"title": aColumnProperties.label,
|
||||
"defaultContent": "",
|
||||
"type": "html",
|
||||
"data": "attributes."+sKey+".att_code",
|
||||
"className": aColumnProperties.mandatory ? 'mandatory' : '',
|
||||
"render": function(data, type, row){
|
||||
var cellElem;
|
||||
|
||||
@@ -205,7 +223,7 @@ EOF
|
||||
cellElem = $('<span></span>');
|
||||
}
|
||||
cellElem.html('<span>' + row.attributes[data].value + '</span>');
|
||||
|
||||
|
||||
return cellElem.prop('outerHTML');
|
||||
},
|
||||
});
|
||||
@@ -219,7 +237,7 @@ EOF
|
||||
// We would just have to override / complete the necessary elements
|
||||
var buildTable_{$this->oField->GetGlobalId()} = function()
|
||||
{
|
||||
var iDefaultOrderColumnIndex = ({$sIsEditable}) ? 1 : 0;
|
||||
var iDefaultOrderColumnIndex = {$iLinkAttributesToDisplayCount};
|
||||
|
||||
// Instantiates datatables
|
||||
oTable_{$this->oField->GetGlobalId()} = $('#{$sTableId}').DataTable({
|
||||
@@ -255,7 +273,25 @@ EOF
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Store attributes inline css and js
|
||||
for (var key in oData.attributes) {
|
||||
const aElement = oData.attributes[key];
|
||||
if(aElement.css_inline !== undefined){
|
||||
$('td:first-child', oRow).append($('<style>' + aElement.css_inline + '</style>'));
|
||||
}
|
||||
if(aElement.js_inline !== undefined){
|
||||
oRenderersJs_{$this->oField->GetGlobalId()} += aElement.js_inline;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"initComplete": function(){
|
||||
|
||||
// Execute inline js provided by attributes renderers
|
||||
eval(oRenderersJs_{$this->oField->GetGlobalId()});
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Handles items selection/deselection
|
||||
@@ -326,21 +362,46 @@ JS
|
||||
// Attaching JS widget
|
||||
$sObjectInformationsUrl = $this->oField->GetInformationEndpoint();
|
||||
$oOutput->AddJs(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field({
|
||||
'validators': {$this->GetValidatorsAsJson()},
|
||||
'get_current_value_callback': function(me, oEvent, oData){
|
||||
var value = null;
|
||||
|
||||
// Retrieving JSON value as a string and not an object
|
||||
//
|
||||
// Note : The value is passed as a string instead of an array because the attribute would not be included in the posted data when empty.
|
||||
// Which was an issue when deleting all objects from linkedset
|
||||
//
|
||||
// Old code : value = JSON.parse(me.element.find('#{$this->oField->GetGlobalId()}').val());
|
||||
value = me.element.find('#{$this->oField->GetGlobalId()}').val();
|
||||
|
||||
return value;
|
||||
|
||||
// Read linked set value as array
|
||||
var aValue = JSON.parse(me.element.find('#{$this->oField->GetGlobalId()}').val());
|
||||
|
||||
// Iterate throw table rows and extract link attributes input values...
|
||||
$('tbody tr', me.element).each(function(){
|
||||
|
||||
// Extract link id
|
||||
const sId = $(this).attr('id');
|
||||
|
||||
// Security
|
||||
if(sId !== undefined){
|
||||
|
||||
// Prepare link attributes values
|
||||
const aValues = {};
|
||||
|
||||
// Extract inputs values...
|
||||
$('input,select,textarea', $(this)).each(function(){
|
||||
if($(this).attr('id') !== undefined){
|
||||
aValues[$(this).attr('name')] = $(this).val();
|
||||
}
|
||||
});
|
||||
|
||||
// Set values
|
||||
if(aValue.current !== undefined && aValue.current[sId] !== undefined){
|
||||
aValue.current[sId] = aValues;
|
||||
}
|
||||
const iAddId = -parseInt(sId);
|
||||
if(aValue.add !== undefined && aValue.add[iAddId] !== undefined){
|
||||
aValue.add[iAddId] = aValues;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return JSON.stringify(aValue);
|
||||
},
|
||||
'set_current_value_callback': function(me, oEvent, oData){
|
||||
// When we have data (meaning that we picked objects from search)
|
||||
@@ -351,16 +412,19 @@ JS
|
||||
|
||||
// Retrieving new rows ids
|
||||
var aObjectIds = Object.keys(oData.values);
|
||||
|
||||
|
||||
// Retrieving rows informations so we can add them
|
||||
$.post(
|
||||
'{$sObjectInformationsUrl}',
|
||||
{
|
||||
sObjectClass: '{$this->oField->GetTargetClass()}',
|
||||
sLinkClass: '{$this->oField->GetLinkedClass()}',
|
||||
aObjectIds: aObjectIds,
|
||||
aObjectAttCodes: $sAttCodesToDisplayAsJson
|
||||
aObjectAttCodes: $sAttCodesToDisplayAsJson,
|
||||
aLinkAttCodes: $sLnkAttCodesToDisplayAsJson,
|
||||
},
|
||||
function(oData){
|
||||
|
||||
// Updating datatables
|
||||
if(oData.items !== undefined)
|
||||
{
|
||||
@@ -376,11 +440,15 @@ JS
|
||||
oData.items[i].id = -1 * parseInt(oData.items[i].id);
|
||||
oTable_{$this->oField->GetGlobalId()}.row.add(oData.items[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
oTable_{$this->oField->GetGlobalId()}.draw();
|
||||
|
||||
|
||||
// Execute inline js for each attributes renderers
|
||||
for(key in oData.items[i].attributes){
|
||||
eval(oData.items[i].attributes[key].js_inline)
|
||||
}
|
||||
|
||||
// Updating input
|
||||
updateInputValue_{$this->oField->GetGlobalId()}();
|
||||
}
|
||||
@@ -409,7 +477,7 @@ JS
|
||||
}
|
||||
}
|
||||
});
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
|
||||
// Rendering table
|
||||
@@ -455,7 +523,7 @@ EOF
|
||||
{
|
||||
// Retrieving table rows
|
||||
var aData = oTable_{$this->oField->GetGlobalId()}.rows().data().toArray();
|
||||
|
||||
|
||||
// Retrieving input values
|
||||
var oValues = JSON.parse($('#{$this->oField->GetGlobalId()}').val());
|
||||
oValues.add = {};
|
||||
@@ -553,98 +621,206 @@ JS
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function PrepareItems(&$aItems, &$aItemIds)
|
||||
protected function PrepareItems(&$aItems, &$aItemIds, $oOutput, &$aAddedItemIds, &$aAddedTargetIds)
|
||||
{
|
||||
/** @var \ormLinkSet $oValueSet */
|
||||
$oValueSet = $this->oField->GetCurrentValue();
|
||||
$oValueSet->OptimizeColumnLoad(array($this->oField->GetTargetClass() => $this->oField->GetAttributesToDisplay(true)));
|
||||
while ($oItem = $oValueSet->Fetch())
|
||||
{
|
||||
while ($oItem = $oValueSet->Fetch()) {
|
||||
|
||||
// In case of indirect linked set, we must retrieve the remote object
|
||||
if ($this->oField->IsIndirect())
|
||||
{
|
||||
try{
|
||||
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
|
||||
$oRemoteItem = MetaModel::GetObject($this->oField->GetTargetClass(), $oItem->Get($this->oField->GetExtKeyToRemote()), true, true);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// In some cases we can't retrieve an object from a linkedset, eg. when the extkey to remote is 0 due to a database corruption.
|
||||
// Rather than crashing we rather just skip the object like in the administration console
|
||||
IssueLog::Error('Could not retrieve object of linkedset in form #'.$this->oField->GetFormPath().' for field #'.$this->oField->GetId().'. Message: '.$e->getMessage());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->oField->IsIndirect()) {
|
||||
try {
|
||||
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
|
||||
$oRemoteItem = MetaModel::GetObject($this->oField->GetTargetClass(), $oItem->Get($this->oField->GetExtKeyToRemote()), true, true);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// In some cases we can't retrieve an object from a linkedset, eg. when the extkey to remote is 0 due to a database corruption.
|
||||
// Rather than crashing we rather just skip the object like in the administration console
|
||||
IssueLog::Error('Could not retrieve object of linkedset in form #'.$this->oField->GetFormPath().' for field #'.$this->oField->GetId().'. Message: '.$e->getMessage());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$oRemoteItem = $oItem;
|
||||
}
|
||||
|
||||
|
||||
// Skip item if not supposed to be displayed
|
||||
$bLimitedAccessItem = $this->oField->IsLimitedAccessItem($oRemoteItem->GetKey());
|
||||
if ($bLimitedAccessItem && !$this->oField->GetDisplayLimitedAccessItems())
|
||||
{
|
||||
if ($bLimitedAccessItem && !$this->oField->GetDisplayLimitedAccessItems()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aItemProperties = array(
|
||||
'id' => ($this->oField->IsIndirect() && $oItem->IsNew()) ? -1*$oRemoteItem->GetKey() : $oItem->GetKey(),
|
||||
'target_id' => $oRemoteItem->GetKey(),
|
||||
'name' => $oItem->GetName(),
|
||||
'attributes' => array(),
|
||||
'id' => ($this->oField->IsIndirect() && $oItem->IsNew()) ? -1 * $oRemoteItem->GetKey() : $oItem->GetKey(),
|
||||
'target_id' => $oRemoteItem->GetKey(),
|
||||
'name' => $oItem->GetName(),
|
||||
'attributes' => array(),
|
||||
'limited_access' => $bLimitedAccessItem,
|
||||
'disabled' => true,
|
||||
'active' => false,
|
||||
'inactive' => true,
|
||||
'disabled' => true,
|
||||
'active' => false,
|
||||
'inactive' => true,
|
||||
'not-selectable' => true,
|
||||
);
|
||||
);
|
||||
|
||||
// Target object others attributes
|
||||
// TODO: Support for AttributeImage, AttributeBlob
|
||||
foreach ($this->oField->GetAttributesToDisplay(true) as $sAttCode)
|
||||
{
|
||||
if ($sAttCode !== 'id')
|
||||
{
|
||||
$aAttProperties = array(
|
||||
'att_code' => $sAttCode
|
||||
);
|
||||
// Link attributes to display
|
||||
$this->PrepareItem($oItem, $this->oField->GetLinkedClass(), $this->oField->GetLnkAttributesToDisplay(true), true, $aItemProperties, $oOutput);
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->oField->GetTargetClass(), $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
$aAttProperties['value'] = $oRemoteItem->Get($sAttCode . '_friendlyname');
|
||||
// Remote attributes to display
|
||||
$this->PrepareItem($oRemoteItem, $this->oField->GetTargetClass(), $this->oField->GetAttributesToDisplay(true), false, $aItemProperties, $oOutput);
|
||||
|
||||
// Checking if user can access object's external key
|
||||
$sObjectUrl = ApplicationContext::MakeObjectUrl($oAttDef->GetTargetClass(), $oRemoteItem->Get($sAttCode));
|
||||
if(!empty($sObjectUrl))
|
||||
{
|
||||
$aAttProperties['url'] = $sObjectUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttProperties['value'] = $oAttDef->GetAsHTML($oRemoteItem->Get($sAttCode));
|
||||
|
||||
if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
// Checking if user can access object
|
||||
$sObjectUrl = ApplicationContext::MakeObjectUrl(get_class($oRemoteItem), $oRemoteItem->GetKey());
|
||||
if(!empty($sObjectUrl))
|
||||
{
|
||||
$aAttProperties['url'] = $sObjectUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aItemProperties['attributes'][$sAttCode] = $aAttProperties;
|
||||
}
|
||||
}
|
||||
|
||||
// Remap objects to avoid added item to be considered as current item when form validation isn't valid
|
||||
// and form reconstruct
|
||||
$aItems[] = $aItemProperties;
|
||||
$aItemIds[$aItemProperties['id']] = array();
|
||||
if ($oItem->IsNew()) {
|
||||
$aAddedItemIds[-1 * $aItemProperties['id']] = array();
|
||||
$aAddedTargetIds[] = $oRemoteItem->GetKey();
|
||||
} else {
|
||||
$aItemIds[$aItemProperties['id']] = array();
|
||||
}
|
||||
}
|
||||
$oValueSet->rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param array $aAttributesCodesToDisplay
|
||||
* @param $oOutput
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function InjectRendererFileAssets(string $sClass, array $aAttributesCodesToDisplay, $oOutput)
|
||||
{
|
||||
$oItem = MetaModel::NewObject($sClass);
|
||||
|
||||
// Iterate throw attributes...
|
||||
foreach ($aAttributesCodesToDisplay as $sAttCode) {
|
||||
|
||||
// Retrieve attribute definition
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
|
||||
$oField = $oAttDef->MakeFormField($oItem);
|
||||
|
||||
$sFieldRendererClass = static::GetFieldRendererClass($oField);
|
||||
|
||||
if ($sFieldRendererClass !== null) {
|
||||
/** @var FieldRenderer $oFieldRenderer */
|
||||
$oFieldRenderer = new $sFieldRendererClass($oField);
|
||||
$oFieldOutput = $oFieldRenderer->Render();
|
||||
static::TransferFieldRendererGlobalOutput($oFieldOutput, $oOutput);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oItem
|
||||
* @param string $sClass
|
||||
* @param array $aAttributesCodesToDisplay
|
||||
* @param bool $bIsEditable
|
||||
* @param array $aItemProperties
|
||||
* @param $oOutput
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function PrepareItem(DBObject $oItem, string $sClass, array $aAttributesCodesToDisplay, bool $bIsEditable, array &$aItemProperties, $oOutput)
|
||||
{
|
||||
// Iterate throw attributes...
|
||||
foreach ($aAttributesCodesToDisplay as $sAttCode) {
|
||||
|
||||
if ($sAttCode !== 'id') {
|
||||
|
||||
// Prepare attribute properties
|
||||
$aAttProperties = array(
|
||||
'att_code' => $sAttCode,
|
||||
);
|
||||
|
||||
// Retrieve attribute definition
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
|
||||
// External key specific
|
||||
if ($bIsEditable) {
|
||||
|
||||
$oField = $oAttDef->MakeFormField($oItem);
|
||||
|
||||
$sFieldRendererClass = static::GetFieldRendererClass($oField);
|
||||
|
||||
if ($sFieldRendererClass !== null) {
|
||||
/** @var FieldRenderer $oFieldRenderer */
|
||||
$oFieldRenderer = new $sFieldRendererClass($oField);
|
||||
$oFieldOutput = $oFieldRenderer->Render();
|
||||
$aAttProperties['js_inline'] = $oFieldOutput->GetJs();
|
||||
$aAttProperties['css_inline'] = $oFieldOutput->GetCss();
|
||||
$aAttProperties['value'] = $oFieldOutput->GetHtml();
|
||||
}
|
||||
|
||||
} else if ($oAttDef->IsExternalKey()) {
|
||||
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
$aAttProperties['value'] = $oItem->Get($sAttCode.'_friendlyname');
|
||||
|
||||
// Checking if user can access object's external key
|
||||
$sObjectUrl = ApplicationContext::MakeObjectUrl($sClass, $oItem->Get($sAttCode));
|
||||
if (!empty($sObjectUrl)) {
|
||||
$aAttProperties['url'] = $sObjectUrl;
|
||||
}
|
||||
|
||||
} else { // Others attributes
|
||||
|
||||
$aAttProperties['value'] = $oAttDef->GetAsHTML($oItem->Get($sAttCode));
|
||||
|
||||
if ($oAttDef instanceof AttributeFriendlyName) {
|
||||
// Checking if user can access object
|
||||
$sObjectUrl = ApplicationContext::MakeObjectUrl($sClass, $oItem->GetKey());
|
||||
if (!empty($sObjectUrl)) {
|
||||
$aAttProperties['url'] = $sObjectUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aItemProperties['attributes'][$sAttCode] = $aAttProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer field renderer output to page output.
|
||||
*
|
||||
* @param \Combodo\iTop\Renderer\RenderingOutput $oFieldOutput
|
||||
* @param \Combodo\iTop\Renderer\RenderingOutput $oPageOutput
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function TransferFieldRendererGlobalOutput(RenderingOutput $oFieldOutput, RenderingOutput $oPageOutput)
|
||||
{
|
||||
foreach ($oFieldOutput->GetJsFiles() as $sJsFile) {
|
||||
$oPageOutput->AddJsFile($sJsFile);
|
||||
}
|
||||
foreach ($oFieldOutput->GetCssFiles() as $sCssFile) {
|
||||
$oPageOutput->AddCssFile($sCssFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field renderer class.
|
||||
*
|
||||
* @param \Combodo\iTop\Form\Field\Field $oField
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function GetFieldRendererClass(Field $oField): ?string
|
||||
{
|
||||
$aRegisteredFields = BsFieldRendererMappings::RegisterSupportedFields();
|
||||
$sFieldClass = get_class($oField);
|
||||
foreach ($aRegisteredFields as $aRegisteredField) {
|
||||
if ($aRegisteredField['field'] === $sFieldClass) {
|
||||
return $aRegisteredField['field_renderer'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user