Magnolia 6.0 reached end of life on June 26, 2019. This branch is no longer supported, see End-of-life policy.
This is the second part of the tutorial about how to use Magnolia content types.
In this part, you will define relationships between different content types, try out the multiple
property and learn to handle complex use cases using submodels. You will see how you can store data in different languages and how to set up security for a production environment.
The Magnolia Content Types module is currently available as a Developer Preview. The full version is still under development.
This developer preview brings several powerful features. Please try it out and feel free to send us your feedback and suggestions based on your experience.
We are working to finalize the module as soon as possible.
In order to promote their tour guides, the travel agency Magnolia Travels decides to provide information about which office each tour guide works out of and what vehicles are available for tourists. For example, the tour office in Ho Chi Minh City currently owns five Yamaha Nuovo 135 bikes.
In the first part of the tutorial, we created a content type for tour guides. In this part, we will define two additional content types in the same domain:
A tour office has one or more tour guides. In addition, each tour office has one or more tour vehicles available.
In the next section, we will define content types and app descriptions for the tour vehicles and the tour offices. Later on, we will define the relationships between different content types and extend the content types.
Add the content type definitions and app descriptors for the tour vehicles and the tour offices to the light module content-type-examples
.
The new content types require a name
property; we will use the automatically created name property to define the name property.
A tour vehicle has a name, vehicle type, number of seats and description.
datasource: workspace: tourvehicles namespaces: mt: https://www.magnolia-travel.com/jcr/1.0/mt autoCreate: true model: nodeType: mt:tourVehicle properties: - name: vehicleType - name: numberOfSeats type: Double - name: description
A tour office has a name, country, city and address. It may link to tour vehicles and to tour guides.
datasource: workspace: touroffices rootPath: / namespaces: mt: https://www.magnolia-travel.com/jcr/1.0/mt autoCreate: true model: nodeType: mt:tourOffice properties: - name: city - name: address - name: country # - name: tourGuides # - name: allVehicles
Your light module should now have the following structure:
content-type-examples/ ├── apps/ │ ├── tourGuides-app.yaml │ ├── tourOffices-app.yaml │ └── tourVehicles-app.yaml ├── contentTypes/ │ ├── tourGuide.yaml │ ├── tourOffice.yaml │ └── tourVehicle.yaml └── i18n └── content-type-examples-backend_en.properties
Since you have created new apps, you also need new user interface labels. Update your messages file /content-type-examples/i18n/content-type-examples-backend_en.properties
to use the following version:
In order to test the new apps you just added, you need app launcher tiles to start them. Add one tile for each app as shown in part I of the tutorial.
Alternatively, add the property defaultGroup
to the path /modules/ui-admincentral/config/appLauncherLayout
and give it the value edit
. (See App launcher layout).
To see the app launcher changes, log out and log in again.
Test the new apps work by creating some tour offices and vehicles.
You can define relations between different content types. An item of type A can have zero to many links to items of type B. This is called a 0-n relationship.
In this section we define a relation between tour offices and tour guides. An office may have one or many tour guides.
We will also use the multiple
property to make it possible to add more than one tour guide to a given office.
An office may have more than one tour guide. Edit the model
property of the tourOffice
content type:
model: nodeType: mt:tourOffice properties: - name: city - name: address - name: country - name: tourGuides type: tourGuide multiple: true
tourGuides
, we define its type
as tourGuide
. This value is the name of an existing content type.multiple
property with the value true
makes it possible to add more than one tour guide.Open the tourOffices-app
app with the app launcher tile and add a tour guide to a tour office.
Submodels are useful whenever you need a group of fields more than once. A content type model definition can contain a list of submodel definitions within the subModels
property. Submodels can be used only within the content type where they have been defined.
We defined the content type for tour vehicles at the beginning of this part of the tutorial. A tour vehicle has the properties: name, vehicle type, number of seats and description.
Now we will extend the tour office to make it possible to add tour vehicles to it. We need to be able to specify the number of different vehicles. For example, the tour office in Ho Chi Minh City currently owns five Yamaha Nuovo 135 bikes.
To map this case, we add a submodel to the tourOffice
content type.
Keep in mind that a submodel definition is very similar to a model definition and that a model definition can contain a list of submodels.
Here is a fragment which shows a submodel:
subModels: - name: vehicleGroup properties: - name: vehicle type: tourVehicle - name: amount type: Double
vehicleGroup
.vehicle
– Its type is tourVehicle,
which is the name of the content type tourVehicle
.amount
– A number to indicate how many different vehicles are available.After you define the submodel, you must add a property in the model with type: <submodel-name>
.
This is the updated model
of the tourOffice
content type definition with the submodel added:
model: nodeType: mt:tourOffice properties: - name: city - name: address - name: country - name: tourGuides type: tourGuide multiple: true - name: allVehicles type: vehicleGroup multiple: true subModels: - name: vehicleGroup properties: - name: vehicle type: tourVehicle - name: amount type: Double
name
is vehicleGroup
(arbitrary).allVehicles
.type
has the value vehicleGroup
, which is the name of a submodel.multiple
enables you to choose more than one of the submodel vehicleGroup
.Now the tour offices app is ready to handle vehicles as described in the use case:
tourOffice
content type definitionWe've looked at how to link from one content type to another. You can also link from a content type to an already existing app—such as the Assets app—which is not based on a content type definition.
To demonstrate this, we will extend the tour guide content type (and its app) with a new image
property to assign an asset (an image) to a tour guide.
To do so:
Add a new property to the model definition of the content type. Give it an arbitrary name. Here we use image
:
model: nodeType: mt:tourVehicle properties: - name: vehicleType - name: numberOfSeats type: Double - name: description - name: image
Override the defaults of the field that were generated for the property:
!with-type:tourVehicle name: tourVehicles-app # subApps: detail: editor: form: tabs: default: fields: - name: description fieldType: richText # ... - name: image fieldType: link targetWorkspace: dam appName: assets label: Select image identifierToPathConverter: class: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator contentPreviewDefinition: contentPreviewClass: info.magnolia.dam.app.ui.field.DamFilePreviewComponent
Setting the fieldType
and defining a Link field in the app descriptor is a feasible way to link to any content app.
To link to an asset, instead of defining the link field in the app descriptor (as showed above) - use type: asset
in the content type definition. In this case there is no more need to override the field in the app descriptor.
model: nodeType: mt:tourVehicle properties: - name: image type: asset
This is what the adapted tourVehicles-app
looks like:
The properties of a content type item can be stored in multiple different languages.
If localization and internationalization (i18n) are completely new to you, we suggest you read the Language section of this documentation.
Here is an overview of how you enable multilanguage content:
i18n=true
in the properties of the model definition.To try out this feature, change the tourVehicle
content type so that we can store the different language content for the description
property.
/config/server/i18n/authoring
. This allows editors to enter the same content in multiple languages.Node name | Value |
---|---|
server | |
i18n | |
system | |
content | |
authoring | |
class | info.magnolia.cms.i18n.DefaultI18nContentSupport |
enabled | true |
Properties:
enabled | required , default is Enables multilanguage content entry. |
class | required A class that implements I18NAuthoringSupport such as:
|
By default, the Magnolia instance is already configured for the
authoring
property.
i18n
property in model propertiesYou must enable localization of content type items for each property.
Here is an example showing only the description
property enabled for multilanguage support:
datasource: # ... model: nodeType: mt:tourVehicle properties: - name: vehicleType - name: numberOfSeats type: Double - name: description i18n: true - name: image
If you are using the magnolia-community-demo-webapp
as indicated in part I of the tutorial, your Magnolia instance already has a site with properly defined locales.
If you have no site definition, configure a site where you define at least its i18n
node as shown below.
In this section, we look at how to set up security for content types and their apps in a production environment. We cover both JCR access security and app security.
In a local development environment, you can use the superuser
user. Superuser has the permissions required to manage the content types and related apps that you built during this tutorial. In a production environment, you should create users with specific roles and deactivate the superuser account.
In this tutorial, we will create the ct-examples-editor
role to edit the content type items on the author instance.
The content type items are stored in the JCR.
ct-examples-editor
role on the author instanceAdd a role with read and write permissions for the JCR workspaces: tourguides
, touroffices
and tourvehicles
.
superuser
) with permission to write on the userroles
workspace.ct-examples-editor
tourguides
, touroffices
and tourvehicles
. with the following settings: The system automatically creates another ACL for the workspace
userroles
. This ACL makes sure that the new role can read its own role definition on the workspace which stores the roles.
Here is a screenshot from the JCR ACLs for the ct-examples-editor
role:
ct-examples-editor
role to eric
the editorIn a production environment, you have different users editing content such as tour guides, tour offices, tour vehicles and others. These users do not have the superuser role.
The magnolia-community-demo-webapp
we are using emulates a production environment. It already contains a user named eric
that has several roles to edit different types of content.
To assign the new ct-examples-editor
role to eric
the editor:
superuser
) with permission to write on the userroles
workspace.eric
and click Edit user.ct-examples-editor
role in the left Other available roles column and move it using the >>
button to the right Granted roles column.Log out and in again as the user eric
with the password eric
.
Eric cannot see the app launcher tiles for the apps tourGuides-app
, tourOffices-app
and tourVehicles-app
yet. You must enable the tour apps for Eric; you will learn how do this in the App security section.
In a production environment, you would also create a role to grant read access for the new workspaces tourguides
, touroffices
and tourvehicles
. Read only access would be assigned to the special system user anonymous
. This would make sure that anonymous website visitors on the public instance would see content, once rendered, from those workspaces.
How to create this role and how to render the content types item on a website are not within the scope of this tutorial.
Without any further configuration, by default, only the superuser
role is granted access to an app.
The app descriptor, which defines an app, has a property named permissions
. In this property, you can add a list of roles for which you want to grant app access.
Add the following code snippet to the very bottom of the YAML files for the apps tourGuides-app
, tourOffices-app
and tourVehicles-app
:
permissions: roles: [ct-examples-editor]
Log out and in again as the user eric
(you assigned the role ct-examples-editor
to Eric earlier).
Eric the editor can now use all three apps: tourGuides-app
, tourOffices-app
and tourVehicles-app
. He can add, edit and delete content items in the JCR workspaces: tourguides
, touroffices
and tourvehicles
.
Congratulations.
You have built a complete set of content types including complex types with submodels. You have created the apps to manage the content items for these content types. You have defined relationships between content types and other, non content type-based apps. Finally, you have learned to properly adjust security settings.
The next logical step would be to set up your Magnolia system to display the tour guides, the tour vehicles and the tour offices on your public instances for your website visitors. This could be done in different ways.
Some suggestions:
Headless consumption of the content types
Develop a mobile phone app to present the data consumed from Magnolia via REST using PhoneGap, Ionic or similar frameworks.
Embed content type items as components into pages