N°3203 - Datamodel: Add semantic for image & state attributes Part. I

This commit is contained in:
Molkobain
2020-11-02 14:51:25 +01:00
parent 7864461d85
commit 50421f4753
10 changed files with 154 additions and 28 deletions

View File

@@ -853,12 +853,28 @@ abstract class MetaModel
}
/**
* Return true if the $sClass has a state attribute defined
*
* @param string $sClass Datamodel class to check
*
* @return bool
* @throws \CoreException
* @since 3.0.0
*/
final public static function HasStateAttributeCode(string $sClass)
{
return !empty(self::GetStateAttributeCode($sClass));
}
/**
* Return the code of the attribute carrying the state of the instance of the class
*
* @param string $sClass
*
* @return string
* @throws \CoreException
*/
final public static function GetStateAttributeCode($sClass)
final public static function GetStateAttributeCode(string $sClass)
{
self::_check_subclass($sClass);
@@ -872,7 +888,7 @@ abstract class MetaModel
* @throws \CoreException
* @throws \Exception
*/
final public static function GetDefaultState($sClass)
final public static function GetDefaultState(string $sClass)
{
$sDefaultState = '';
$sStateAttrCode = self::GetStateAttributeCode($sClass);
@@ -884,6 +900,36 @@ abstract class MetaModel
return $sDefaultState;
}
/**
* Return true if the $sClass has an image attribute defined
*
* @param string $sClass
*
* @return bool
* @throws \CoreException
* @since 3.0.0
*/
final public static function HasImageAttributeCode(string $sClass)
{
return !empty(self::GetImageAttributeCode($sClass));
}
/**
* Return the code of the attribute carrying the image representing an instance of the class
*
* @param string $sClass Datamodel class to get the image attribute code for
*
* @return mixed
* @throws \CoreException
* @since 3.0.0
*/
final public static function GetImageAttributeCode(string $sClass)
{
self::_check_subclass($sClass);
return self::$m_aClassParams[$sClass]["image_attcode"];
}
/**
* @param string $sClass
*
@@ -3245,11 +3291,12 @@ abstract class MetaModel
public static function Init_Params($aParams)
{
// Check mandatory params
// Warning: Do not put image_attcode as a mandatory attribute or it will break all PHP datamodel classes
$aMandatParams = array(
"category" => "group classes by modules defining their visibility in the UI",
"key_type" => "autoincrement | string",
"name_attcode" => "define wich attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
"state_attcode" => "define wich attribute is representing the state (object lifecycle)",
"name_attcode" => "define which attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
"state_attcode" => "define which attribute is representing the state (object lifecycle)",
"reconc_keys" => "define the attributes that will 'almost uniquely' identify an object in batch processes",
"db_table" => "database table",
"db_key_field" => "database field which is the key",

View File

@@ -10,7 +10,8 @@ $ibo-title--medallion--background-color: $ibo-color-grey-100 !default;
$ibo-title--medallion--border: 2px solid $ibo-color-blue-grey-300 !default;
$ibo-title--medallion--border-radius: $ibo-border-radius-full !default;
$ibo-title--icon--size: 66.67% !default;
$ibo-title--icon--size--must-cover: 100% !default;
$ibo-title--icon--size--must-zoomout: 66.67% !default;
$ibo-title--status-dot--size: 10px !default;
$ibo-title--status-dot--spacing: 8px !default;
@@ -26,6 +27,8 @@ $ibo-title--status-dot--border-radius: $ibo-border-radius-full !default;
@extend %ibo-fully-centered-content;
width: $ibo-title--medallion--size;
height: $ibo-title--medallion--size;
min-width: $ibo-title--medallion--size;
min-height: $ibo-title--medallion--size;
overflow: hidden;
background-color: $ibo-title--medallion--background-color;
@@ -33,11 +36,14 @@ $ibo-title--status-dot--border-radius: $ibo-border-radius-full !default;
border-radius: $ibo-title--medallion--border-radius;
}
.ibo-title--icon {
width: $ibo-title--icon--size;
width: $ibo-title--icon--size--must-cover;
height: auto;
max-width: 100%;
max-height: 100%;
}
.ibo-title--icon--must-zoomout {
width: $ibo-title--icon--size--must-zoomout;
}
.ibo-title--emphasis {

View File

@@ -1040,8 +1040,7 @@ class ObjectController extends BrickController
$sHostId = $sObjectId;
// Security bypass for the image attribute of a class
// Note: This will be changed with a proper DM check when corresponding bug is being worked on
if(is_a($sObjectClass, 'Contact', true) && ($sObjectField === 'picture')){
if(MetaModel::GetImageAttributeCode($sObjectClass) === $sObjectField) {
$bCheckSecurity = false;
}
}

View File

@@ -984,6 +984,9 @@ public function PrefillSearchForm(&$aContextParam)
<attribute id="name"/>
</attributes>
</naming>
<semantic>
<image_attribute>icon</image_attribute>
</semantic>
<icon>images/service.png</icon>
<reconciliation>
<attributes>
@@ -1066,6 +1069,9 @@ public function PrefillSearchForm(&$aContextParam)
<attribute id="name"/>
</attributes>
</naming>
<semantic>
<image_attribute>icon</image_attribute>
</semantic>
<icon>images/service.png</icon>
<reconciliation>
<attributes>

View File

@@ -876,6 +876,9 @@ public function PrefillSearchForm(&$aContextParam)
<attribute id="name"/>
</attributes>
</naming>
<semantic>
<image_attribute>icon</image_attribute>
</semantic>
<icon>images/service.png</icon>
<reconciliation>
<attributes>
@@ -958,6 +961,9 @@ public function PrefillSearchForm(&$aContextParam)
<attribute id="name"/>
</attributes>
</naming>
<semantic>
<image_attribute>icon</image_attribute>
</semantic>
<icon>images/service.png</icon>
<reconciliation>
<attributes>

View File

@@ -514,6 +514,9 @@
<attribute id="name"/>
</attributes>
</naming>
<semantic>
<image_attribute>picture</image_attribute>
</semantic>
<icon>images/person.png</icon>
<reconciliation>
<attributes>

View File

@@ -997,6 +997,7 @@ EOF
$aClassParams['is_link'] = 'true';
}
// Naming
if ($oNaming = $oProperties->GetOptionalElement('naming'))
{
$oNameAttributes = $oNaming->GetUniqueElement('attributes');
@@ -1023,18 +1024,37 @@ EOF
$sNameAttCode = "''";
}
$aClassParams['name_attcode'] = $sNameAttCode;
$oLifecycle = $oClass->GetOptionalElement('lifecycle');
if ($oLifecycle)
{
$sStateAttCode = $oLifecycle->GetChildText('attribute');
}
else
{
$sStateAttCode = "";
// Semantic
// - Default attributes code
$sImageAttCode = "";
$sStateAttCode = "";
// - Parse optional semantic node
$oSemantic = $oProperties->GetOptionalElement('semantic');
if ($oSemantic) {
// Image attribute
$oImageAttribute = $oSemantic->GetOptionalElement('image_attribute');
if ($oImageAttribute) {
$sImageAttCode = $oImageAttribute->GetText();
}
// State attribute, only if not already found from lifecycle
// $oStateAttribute = $oSemantic->GetOptionalElement('state_attribute');
// if(empty($sStateAttCode) && $oStateAttribute) {
// $sStateAttCode = $oStateAttribute->GetText();
// }
}
$aClassParams['image_attcode'] = "'$sImageAttCode'";
$aClassParams['state_attcode'] = "'$sStateAttCode'";
// Lifecycle (overload any state attribute defined in the semantic node)
$oLifecycle = $oClass->GetOptionalElement('lifecycle');
if ($oLifecycle) {
$sStateAttCode = $oLifecycle->GetChildText('attribute');
$aClassParams['state_attcode'] = "'$sStateAttCode'";
}
// Reconcialiation
if ($oReconciliation = $oProperties->GetOptionalElement('reconciliation'))
{
$oReconcAttributes = $oReconciliation->getElementsByTagName('attribute');

View File

@@ -17,22 +17,37 @@ use Combodo\iTop\Application\UI\UIBlock;
class Title extends UIBlock
{
// Overloaded constants
/** @inheritDoc */
public const BLOCK_CODE = 'ibo-title';
/** @inheritDoc */
public const HTML_TEMPLATE_REL_PATH = 'components/title/layout';
/** @var string Icon should cover all the space, best for icons with filled background */
public const ENUM_ICON_COVER_METHOD_COVER = 'cover';
/** @var string Icon should be a litte zoomed out to cover almost all space, best for icons with transparent background and no margin around (eg. class icons) */
public const ENUM_ICON_COVER_METHOD_ZOOMOUT = 'zoomout';
/** @var string */
public const DEFAULT_ICON_COVER_METHOD = self::ENUM_ICON_COVER_METHOD_COVER;
/** @var string */
protected $sTitle;
/** @var int */
protected $iLevel;
/** @var string */
protected $sIconHtml;
protected $sIconUrl;
/** @var string How the icon should cover the medallion, see static::ENUM_ICON_COVER_METHOD_COVER, static::ENUM_ICON_COVER_METHOD_ZOOMOUT */
protected $sIconCoverMethod;
/**
* @inheritDoc
*/
public function __construct(string $sTitle = '', int $iLevel = 1, ?string $sId = null)
{
parent::__construct($sId);
$this->sTitle = $sTitle;
$this->iLevel = $iLevel;
$this->sIconHtml = null;
$this->sIconUrl = null;
$this->sIconCoverMethod = static::DEFAULT_ICON_COVER_METHOD;
}
/**
@@ -51,20 +66,26 @@ class Title extends UIBlock
return $this->iLevel;
}
public function SetIcon(string $sIconHtml): self
public function SetIcon(string $sIconUrl, string $sIconCoverMethod = self::DEFAULT_ICON_COVER_METHOD)
{
$this->sIconHtml = $sIconHtml;
$this->sIconUrl = $sIconUrl;
$this->sIconCoverMethod = $sIconCoverMethod;
return $this;
}
public function GetIcon(): string
public function GetIconUrl(): string
{
return $this->sIconHtml;
return $this->sIconUrl;
}
public function GetIconCoverMethod(): string
{
return $this->sIconCoverMethod;
}
public function HasIcon(): string
{
return !is_null($this->sIconHtml);
return !is_null($this->sIconUrl);
}
}

View File

@@ -23,13 +23,31 @@ class TitleFactory
public static function MakeForObjectDetails(DBObject $oObject, ?string $sId = null)
{
// TODO 3.0.0: Refactor all of this
$sObjIconUrl = $oObject->GetIcon(false);
$sObjClass = get_class($oObject);
$sObjClassName = MetaModel::GetName($sObjClass);
$sObjName = $oObject->GetName();
// Object icon
// - Default icon is the class icon
$sObjIconUrl = $oObject->GetIcon(false);
// Note: Class icons are a square image with no margin around, so they need to be zoomed out in the medallion
$sIconCoverMethod = Title::ENUM_ICON_COVER_METHOD_ZOOMOUT;
// - Use object image from seantic attribute only if it's not the default image
if(!$oObject->IsNew()){
$sImageAttCode = MetaModel::GetImageAttributeCode($sObjClass);
if(!empty($sImageAttCode)){
/** @var \ormDocument $oImage */
$oImage = $oObject->Get($sImageAttCode);
if(!$oImage->IsEmpty()){
$sObjIconUrl = $oImage->GetDisplayURL($sObjClass, $oObject->GetKey(), $sImageAttCode);
$sIconCoverMethod = Title::ENUM_ICON_COVER_METHOD_COVER;
}
}
}
$oTitle = new TitleForObjectDetails($sObjClassName, $sObjName, $sId);
$oTitle->SetIcon($sObjIconUrl);
$oTitle->SetIcon($sObjIconUrl, $sIconCoverMethod);
$sStatusAttCode = MetaModel::GetStateAttributeCode($sObjClass);
if (!empty($sStatusAttCode)) {

View File

@@ -2,7 +2,7 @@
<div class="ibo-title">
{% if oUIBlock.HasIcon() %}
<div class="ibo-title--medallion">
<img class="ibo-title--icon" src="{{ oUIBlock.GetIcon() }}" />
<img class="ibo-title--icon ibo-title--icon--must-{{ oUIBlock.GetIconCoverMethod() }}" src="{{ oUIBlock.GetIconUrl() }}" />
</div>
{% endif %}
<div class="ibo-title--content">