How to map a new custom MediaAsset field to allowed object
Customer might want to have an additional field in the media asset area for some purpose, which is also meaningful for the assigned objects (Item, Product, Variant, Structure Group). And he might also want to manipulate such media asset field directly from the assigned object for some cases, e.g. assigning such media asset field value to object per import. A possible solution is to create an additional MediaAsset field and then map this new field to the corresponding object, since there are some reserved fields predefined under the entity type "MediaAssetType" which can be easily used for customer's use case.
The following steps show you how to create and map a custom MediaAsset field, and such field can not be used as a primary key which has more constraints.
Add new MediaAsset field
Let us assume that a text field is desired, then the reserved field type "MediaAssetType.Res_Text100_01" can be taken for it.
Active the desired MediaAsset field type
First, active the reserved MediaAssetType.Res_Text100_01 field type in the repository:
Add a new MediaAsset field for the activated field type
Then, create a new field MediaAsset.Res_Text100_01 which has the field type MediaAssetType.Res_Text100_01:
<
field
identifier
=
"MediaAsset.Res_Text100_01"
category-ref
=
"master-data"
field-type-ref
=
"MediaAssetType.Res_Text100_01"
>
<
name
>%field.MediaAsset.Res_Text100_01.name</
name
>
<
description
>%field.MediaAsset.Res_Text100_01.description</
description
>
<
max
-length>260</
max
-length>
<
visible
-from-top>true</
visible
-from-top>
<
display
-by-default>true</
display
-by-default>
<
display
-by-default-from-top>true</
display
-by-default-from-top>
<
average
-length>25</
average
-length>
<
purpose
>1</
purpose
>
<
importPurpose
>1</
importPurpose
>
<
exportPurpose
>51</
exportPurpose
>
</
field
>
Map MediaAsset field to the objects of the field type "ArticleType"
For the previous versions, this step is only necessary, if customer needs the similar case like importing Item/Product2G/Variant with the above defined MediaAsset.Res_Text100_01 field value. Otherwise this step can be ignored, since the user can edit this field value in Desktop UI and Web UI without any mapping.
But from the following versions on, all custom fields should be mapped to the objects, otherwise they can not be edited in UI since UI changes on MediaAsset fields trigger a direct update for the assigned object.
8.1.1.04.12
8.1.1.07
10.0.0.01.05
10.0.0.02
10.1
Add mapped field type and field
Add a mapped ArticleMediaAssetMapType field type
Add a new field type ArticleMediaAssetMapType.Res_Text100_01 which will be mapped to MediaAssetType.Res_Text100_01:
<
field
-type
identifier
=
"ArticleMediaAssetMapType.Res_Text100_01"
>
<
object
-name>res_Text100_01</
object
-name>
<
class
-name>java.lang.String</
class
-name>
<
persistence
-class-name>java.lang.String</
persistence
-class-name>
<
fragment
-column-access>MediaAsset.Res_Text100_01</
fragment
-column-access>
<
max
-length>2000</
max
-length>
</
field
-type>
The "Object Name" property of the mapped media asset field type should be same as the one of the media asset field type!
E.g. ArticleMediaAssetMapType.Res_Text100_01 has a value "res_Text100_01" for the "Object Name" property, that is the same property value for the field type MediaAssetType.Res_Text100_01.
Add a corresponding ArticleMediaAssetMap field
Add a new field ArticleMediaAssetMap.Res_Text100_01:
<
field
identifier
=
"ArticleMediaAssetMap.Res_Text100_01"
category-ref
=
"assets"
field-type-ref
=
"ArticleMediaAssetMapType.Res_Text100_01"
supports-serviceapi
=
"true"
>
<
name
>%field.ArticleMediaAssetMap.Res_Text100_01.name</
name
>
<
description
>%field.ArticleMediaAssetMap.Res_Text100_01.description</
description
>
<
max
-length>260</
max
-length>
<
editable
>true</
editable
>
<
visible
>true</
visible
>
<
visible
-from-top>false</
visible
-from-top>
<
display
-by-default>false</
display
-by-default>
<
display
-by-default-from-top>false</
display
-by-default-from-top>
<
average
-length>25</
average
-length>
<
mergeable
>true</
mergeable
>
<
purpose
>1</
purpose
>
<
importPurpose
>1</
importPurpose
>
<
exportPurpose
>0</
exportPurpose
>
</
field
>
Add a corresponding field for other objects
Add such a field to Product2GMediaAssetMap and also to VariantMediaAssetMap if you are working with the three tier product paradigm.
It is similar to the ArticleMediaAssetMap.Res_Text100_01, e.g. a Product2GMediaAssetMap.Res_Text100_01 which has the same field type "ArticleMediaAssetMapType.Res_Text100_01".
Complete map logic with code
Set a NullPropertyMediator for the mapped field type
<
extension
point
=
"com.heiler.ppm.persistence.server.persister"
>
...
<
propertyMediator
class
=
"com.heiler.ppm.persistence.server.mediator.impl.NullPropertyMediator"
description
=
"Null Property Mediator for ArticleMediaAssetMapType.Res_Text100_01"
fieldTypeIdentifier
=
"ArticleMediaAssetMapType.Res_Text100_01"
id
=
"hpm.article.AMAM.Res_Text100_01"
>
</
propertyMediator
>
...
</
extension
>
Contribute own PropertyMediator to replace the standard one for the mapped MediaAssetProxy field
<
extension
point
=
"com.heiler.ppm.persistence.server.persister"
>
...
<
propertyMediator
class
=
"custom.mediaasset.core.mediator.CustomAMAMMediaAssetProxyPropertyMediator"
description
=
"Custom Property Mediator for ArticleMediaAssetMapType.MediaAssetProxy"
fieldTypeIdentifier
=
"ArticleMediaAssetMapType.MediaAssetProxy"
id
=
"hpm.custom.article.AMAM.MediaAssetProxy"
target-id
=
"hpm.article.AMAM.MediaAssetProxy"
>
</
propertyMediator
>
...
</
extension
>
The contributed class CustomAMAMMediaAssetProxyPropertyMediator should implement the interface methods like following:
read( MediatorSession session, PropertyData propertyData ): extend the similar logic also for the reserved fields. As a quick solution you can copy the code from AMAMMediaAssetProxyPropertyMediator and its super class EntityMAMMediaAssetProxyPropertyMediator, then call an own JPQL (similar to the com.heiler.ppm.mediaasset.db.query.MediaAssetJPQL.QUERY_SEL_MEDIAASSET_FIELDS_BY_ID) to read the corresponding value for all standard fields and also for the reserved fields, and store them in the business object (see EntityMAMMediaAssetProxyPropertyMediator.setMediaAssetFields(...)).
write( MediatorSession context, PropertyData propertyData, AttributeChange attributeChange ): same as the one of the standard AMAMMediaAssetProxyPropertyMediator, just copy it.
Add a PropertyPostSetter to transfer the field change
The field change should be transferred from mapped field type ArticleMediaAssetMapType.Res_Text100_01 to the field type MediaAssetType.Res_Text100_01.
<
operator
class
=
"custom.mediaasset.core.command.CustomArticleMediaAssetMapPostSetter"
description
=
"Mirrors the custom ArticleMediaAssetMap fields in the MediaAssetProxy"
id
=
"CustomAMAMPostSetter"
name
=
"CustomAMAMPostSetter"
type
=
"PropertyPostSetter"
>
...
<
repository
-identifier
identifier
=
"ArticleMediaAssetMapType.Res_Text100_01"
type
=
"FIELD_TYPE"
>
</
repository
-identifier>
<
target
-command
type
=
"PutCommand"
/>
...
</
operator
>
The class CustomArticleMediaAssetMapPostSetter should be an implementation of the interface PropertyPostSetter and transfer the field change from the mapped field type ArticleMediaAssetMapType.Res_Text100_01 to the MediaAsset field type MediaAssetType.Res_Text100_01. As a concrete example please visit the standard source code com.heiler.ppm.mediaasset.core.internal.command.ArticleMediaAssetMapPostSetter.
Map field to the object of the field type "StructureGroupType" (optional)
It is only necessary, if customer needs the case like importing structure group directly with the above defined MediaAsset.Res_Text100_01 field value. Otherwise this step can be ignored, since the user can edit this field value in Desktop UI and Web UI.
But from the following versions on, all custom fields should be mapped to the objects, otherwise they can not be edited in UI since UI changes on MediaAsset fields trigger a direct update for the assigned object.
8.1.1.04.12
8.1.1.07
10.0.0.01.05
10.0.0.02
10.1
Add mapped field type and field
Add a mapped StructureGroupMediaAssetMapType field type
It is similar to ArticleMediaAssetMapType.Res_Text100_01, e.g. a new field type "StructureGroupMediaAssetMapType.Res_Text100_01".
Add a corresponding StructureGroupMediaAssetMap field
It is similar to the ArticleMediaAssetMap.Res_Text100_01 field, e.g. StructureGroupMediaAssetMap.Res_Text100_01 which has the field type "StructureGroupMediaAssetMapType.Res_Text100_01".
Complete map logic with code
Set a NullPropertyMediator for the mapped field type
It is similar to the one for ArticleMediaAssetMapType.Res_Text100_01.
Contribute own PropertyMediator to replace the standard one for the mapped MediaAssetProxy field
It is similar to the one for ArticleMediaAssetMapType.MediaAssetProxy.
Add a PropertyPostSetter to transfer the field change
The field change should be transferred from mapped field type StructureGroupMediaAssetMapType.Res_Text100_01 to the field type MediaAssetType.Res_Text100_01.
It is similar to the above described CustomAMAMPostSetter.
Enable custom field in the Web
To show the new custom field in the P360 Web UI under the Media tab of the selected object (Item/Product/Variant/Structure Group), it should be added in the media.variants.xml like following:
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
standalone
=
"yes"
?>
<
formDefinitions
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation
=
"FormDefinitions.xsd"
>
<
definition
position
=
"2147483647"
rootEntity
=
"MediaAsset"
>
<
column
>
<
fieldGroup
>
<
field
identifier
=
"MediaAsset.Name"
/>
<
field
identifier
=
"MediaAsset.Type"
/>
<
field
identifier
=
"MediaAsset.Res_Text100_01"
/>
</
fieldGroup
>
<
fieldGroup
displaySectionWidget
=
"true"
subEntityId
=
"MediaAssetLang"
>
<
field
identifier
=
"MediaAssetLang.Description"
/>
<
field
identifier
=
"MediaAssetLang.AlternateText"
/>
<
logicalKey
identifier
=
"MediaAssetLangType.LK.Language"
value
=
"English"
/>
</
fieldGroup
>
</
column
>
</
definition
>
</
formDefinitions
>
Map a new custom MediaAssetLang field
The above described steps are for mapping a custom MediaAsset field, and it is also feasible to map a custom MediaAssetLang field by similar steps.
For example, if a custom MediaAssetLang field is desired to be mapped to item, then the following steps should be done:
Active a desired reserved MediaAssetLang field type (e.g. MediaAssetLangType.Res_Text100_01)
Add a new MediaAssetLang field for the activated field type (e.g. MediaAssetLang.Res_Text100_01)
Add a mapped ArticleMediaAssetLangType field type (e.g. ArticleMediaAssetLangType.Res_Text100_01)
Add a corresponding ArticleMediaAssetLang field (e.g. ArticleMediaAssetLang.Res_Text100_01)
It is unnecessary to set a NullPropertyMediator for the mapped MediaAssetLang field type (e.g. ArticleMediaAssetLangType.Res_Text100_01), since there is already a contributed NullSubMediator for the entity type ArticleMediaAssetLangType
Contribute (or adjust if it is created for a custom MediaAsset field) own PropertyMediator by loading the field value with enhanced JPQL
Add a PropertyPostSetter to transfer the field change from the mapped field type (e.g. ArticleMediaAssetLangType.Res_Text100_01) to the field type (e.g. MediaAssetLangType.Res_Text100_01)
Enable custom MediaAssetLang field in the Web