Creating a custom WebCmsAsset
To create a custom WebCmsAsset
, we create a class which extends WebCmsAsset
. `WebCmsAsset`has two superclasses which require a method to be implemented:
-
WebCmsObjectInheritanceSuperClass
which definesgetObjectType()
-
WebCmsObjectSuperClass
which definesgetObjectCollectionId()
with which every object id of the class will be prefixed with.
Aside of these two methods, WebCmsAsset defines an abstract method getAssetType()
, which also needs to be implemented.
WebCmsAsset
uses joined inheritance, so don’t forget to add a @DiscriminatorValue
to the class, which typically is the same as the return value of getObjectType()
.
getObjectCollectionId()
returns the prefix of the asset that defines to which collection it belongs. For example, the collection id for a WebCmsPage
is wcm:asset:page
. A typical collection id starts with wcm:asset: followed by the object type.
Often, we create a WebCmsAssetType
for our asset, which our asset will hold and which will be the return value of getAssetType()
. However, it is not required to have an explicit asset type (unless you want to be able to import your custom asset through yaml imports and create several components by default from a template), in which case the method may return null
.
Creating a WebCmsAssetType
A WebCmsAssetType
extends WebCmsTypeSpecifier
- which in itself implements the two superclasses we’ve talked about earlier. This means that once again we have to implement a getObjectType()
and getObjectCollectionId()
method. By convention and to keep a clear overview, we advise you to use the same object type for both the custom asset and the custom asset type. The collection id is usually slightly different, as it represents a type, so it should not be in the same collection as our assets. If we once again take a look at WebCmsPage
and its WebCmsPageType
, we see that the collection id for WebCmsPageType
is wcm:type:page
. Typically the collection id for a WebCmsPage starts with wcm:type: followed by the collection id.
Note: the prefix wcm: is mostly used by objects provided by WebCmsModule, so please check that there’s no WebCmsAsset defined with the same collection type. It would definitely be a good idea to have your own prefix within your project.
An example AuthorAssetType
:
@NotThreadSafe
@Entity
@DiscriminatorValue(OBJECT_TYPE)
@Table(name = "example_author_asset_type")
@NoArgsConstructor
@Getter
@Setter
public class AuthorAssetType extends WebCmsAssetType<AuthorAssetType>
{
public static final String OBJECT_TYPE = "author";
public static final String COLLECTION_ID = "example:type:author";
@Override
public String getObjectType() {
return OBJECT_TYPE;
}
@Override
protected String getObjectCollectionId() {
return COLLECTION_ID;
}
}
For WebCmsModule to be able to use the WebCmsAssetType, we also need to register it to the WebCmsTypeRegistry. This usually happens as follows within an @Configuration class:
@Autowired
public void registerDefaultTypes( WebCmsTypeRegistry typeRegistry ) {
typeRegistry.register( AuthorAssetType.OBJECT_TYPE, AuthorAssetType.class, AuthorAssetType::new );
}
An example AuthorAsset
:
@NotThreadSafe
@Entity
@DiscriminatorValue(OBJECT_TYPE)
@Table(name = "example_author_asset")
@Getter
@Setter
@NoArgsConstructor
public class AuthorAsset extends WebCmsAsset<AuthorAsset>
{
/**
* Object type name (discriminator value).
*/
public static final String OBJECT_TYPE = "author";
/**
* Prefix that all asset ids for an author should have.
*/
public static final String COLLECTION_ID = "example:asset:author";
/**
* Name of the author.
*/
@NotBlank
@Length(max = 255)
@Column(name = "name")
private String name;
/**
* The job title of the author.
*/
@NotBlank
@Length(max = 255)
@Column(name = "job_title")
private String jobTitle;
@ManyToOne
@JoinColumn(name = "author_asset_type_id")
@NotNull
private AuthorAssetType authorType;
@Override
public WebCmsAssetType getAssetType() {
return authorType;
}
@Override
public String getObjectType() {
return OBJECT_TYPE;
}
@Override
protected String getObjectCollectionId() {
return COLLECTION_ID;
}
}
Aside of creating our custom WebCmsAsset
and its WebCmsAssetType
, do not forget to create their repositories, which should extends WebCmsObjectEntityRepository
.
Now we’ve created a custom WebCmsAsset
and WebCmsAssetType
which can be managed from the backend, should EntityModule and AdminWebModule be present.
However, managing the related components will not be possible from the administration interface. We simply need to enable the option:
@Autowired
public void enableComponentViews( WebCmsObjectComponentViewsConfiguration componentViewsConfiguration ){
componentViewsConfiguration.enable(AuthorAsset.class);
}
Importing a custom WebCmsAsset
To be able to import the custom asset we have just created we will require to create a custom importer, and should we want to create templates for our custom WebCmsAsset, we will also require an interceptor to copy the template to our asset.
Let’s start by creating an importer for our AuthorAsset
.
We’ll create a class that extends AbstractWebCmsAssetImporter
, which is a base class for importing a single asset type.
AbstractWebCmsDataImporter
extends AbstractWebCmsDataImporter
, which is the base class that supports the imports of WebCmsObject
s.
Several methods required by AbstractWebCmsDataImporter have a default implementation provided by AbstractWebCmsAssetImporter, which can be used to further customize the imports of your assets.
There is a single method left that has no default implementation, being createDto( WebCmsDataEntry data, <WebCmsAsset> existing, WebCmsDataAction action, Map<String, Object> values )
. All createDto( … )
is required to do is create a DTO object which can afterwards be used to set the imported properties, and be persisted to the database.
By default, the unique key to find a WebCmsObject is its objectId, found in the top level of the data entry we are importing.
Should you wish to use a different identifier for your asset in your imports, you can implement getExistingEntity( String entryKey, WebCmsDataEntry entryData, WebCmsDomain domain )
to specify which keys can be allowed and what the entry key represents. (e.g. the canonical path can be used as an entrykey in the case of a WebCmsPage
).
Aside of that, we also need to provide a constructor, matching the one of AbstractWebCmsAssetImporter
to where we define the data key that we want to use under one of the root keys.
Several data keys already exist, so once again, double check whether your key is unique.
Our base AuthorAssetImporter
would require nothing more than the following:
@Component
public class AuthorAssetImporter extends AbstractWebCmsAssetImporter<AuthorAsset>
{
private AuthorAssetRepository authorRepository;
public AuthorAssetImporter() {
super( "author", AuthorAsset.class );
}
@Override
protected Author createDto( WebCmsDataEntry data,
Author existing,
WebCmsDataAction action,
Map<String, Object> dataValues ) {
return existing != null ? existing.toDto() : new Author();
}
@Autowired
void setAuthorAssetRepository( AuthorAssetRepository authorAssetRepository ) {
this.authorAssetRepository = authorAssetRepository;
}
}
Next up is our interceptor.
When importing WebCmsObjects, we have several custom properties that can be imported, like wcm:components, wcm:types, …
We can also define a type (hence why we made AuthorAssetType
) which defines a template for our asset.
If we then import an asset with that type, the template will be copied over to our asset and the components will be created.
For this we need an interceptor, which extends EntityInterceptorAdaptor
, and where we tell the WebCmsDefaultComponentsService
to copy the template after our asset has been created.
@Component
@RequiredArgsConstructor
public class AuthorInterceptor extends EntityInterceptorAdapter<Author>
{
private final WebCmsDefaultComponentsService webCmsDefaultComponentsService;
@Override
public boolean handles( Class<?> entityClass ) {
return Author.class.isAssignableFrom( entityClass );
}
@Override
public void afterCreate( Author entity ) {
webCmsDefaultComponentsService.createDefaultComponents( entity, new HashMap<>() );
}
}