Metadata overriding
What is metadata overriding?
In order to better explain this concept, we are going to use an example with 3 modules :
- The
Salesmodule is a generic module centered around sales. - The
CarRentalmodule is a module specialized in the management of vehicle rentals that is base on theSalesmodule. - The
EuropaCarmodule created to meet the specific needs of the EuropaCar company that is based on theCarRentalmodule.
Schema :
graph BT;
CarRental[Car rental module]--Depends on-->Sales[Sales module];
EuropaCar[EuropaCar specific module]--Depends on-->CarRental;
The Sales module includes a Customer entity with a several standard properties. In the cluster directory, this results in the following files :
modules/Sales/metadata/Entities/Customer.yml :
Description: Customer
KeyProperties:
- CustomerId
TableName: Customer
modules/Sales/metadata/EntityProperties/Customer.yml :
- Name: CompanyName
Caption: Company
Required: true
- Name: CustomerId
Caption: Id
Required: true
- Name: Phone
Caption: Phone
In Neos, a child module can natively enrich a parent module by completing it. If we add the EMail property to the Customer entity and assign it to the CarRental module, when saving, the following file will be generated in addition to the previous ones:
modules/CarRental/metadata/EntityProperties/Customer.yml :
- Name: EMail
Caption: EMail
The added property is persisted in the CarRental module and the Sales module has not changed. Other clusters using the Sales module will not be impacted by this added property for vehicle rental.
Now, in the context of vehicle rental, if we want the caption of the CompanyName property to be Renter instead of Company, we find ourselves in a different case.
If we directly modify the caption in Neos Studio, the modules/Sales/metadata/EntityProperties/Customer.yml file will be modified and will contain:
- Name: CompanyName
Caption: Renter
Required: true
- Name: CustomerId
Caption: Id
Required: true
- Name: Phone
Caption: Phone
This is not what we want because in this case any other cluster that uses the Sales module will end up with a label specific to the vehicle rental business.
Note
If the Sales module is referenced as a dependency, it will be read-only and it will not be possible to save a change to the CompanyName property anyway.
This is where metadata overriding is useful as it allows to redefine metadata properties belonging to a parent module.
The redefinition is stored in the child module (CarRental in the case described above) and does not generate any changes in the base module.
How to use metadata overriding?
You must start by setting the module in which you want to redefinition to be stored as the working module. To define the working module, see this article).
Then, in the same screen where you defined the working module, you can activate Allow override.
Note
The option is not checked by default because this concept needs to be well understood before using it and it must remain occasional in most cases.
After enabling redefinition, if you change the caption of the CompanyName property and look at the changes applied in your cluster directory, you will find the following newly created file :
**modules/CarRental/metadata/EntityProperties/@Customer.yml** :
- Name: CompanyName
Caption: Renter
This file is an override file. It differs from classic files by having a @ at the beginning of its name and by the fact that it only contains the keys of the overridden elements and the redefined properties.
How to know what is redefined in Neos Studio?
The current Neos Studio version only offers the implementation of the redefinition principle. It is not currently possible to distinguish standard properties from redefined properties, nor to view the base value of a redefined property.
In order to list the redefinitions, it is necessary to search for files starting with @ in the metadata directories of the cluster.
Can anything be overridden ?
The redefinitions are managed by the Neos YAML persistence engine that technically allows to redefine every metadata. However, there are many cases where an override will not work and will generated errors (for example, changing the type of an entity property). Redefinition should therefore be used with great caution.
Can redefinitions be cumulated?
Yes this is possible. If we take the example of this article, it is possible to redefine once more the CompanyName property caption in the EuropaCar module to Client. This will generate the following file:
**modules/EuropaCar/metadata/EntityProperties/@Customer.yml** :
- Name: CompanyName
Caption: Client
The redefinitions are applied successively in the order of dependency of the modules. When the CarRental and EuropaCar modules are present, Caption will have the value Client. When only the CarRental module is present, Caption will have the value Renter.
How to delete an override?
Redefinitions are removed simply by putting the original value back and saving. This will remove the corresponding override from the redefinition file and delete the redefinition file if does not contain any other override. It is of course also possible to directly edit or delete the redefinition file to achieve the same result.
How to vizualize the overrides ?
When a working module is set, a button is displayed in the Neos Studio toolbar to visualize only the overrides in the tree view. This allows to quickly identify the metadata overridden by the working module. The button is only visible when the working module is set.
You can also visualize the overrides in the metadata with the entry "Overridden metadata" in the menu list of Neos Studio. By default, the list displays all the overridden metadata without the overridden server code or the overridden report. To see the overridden server code or the overridden report, you must check the 'Includes external overrides' checkbox in the filter bar.
How to compare an override with an external tool?
From a row of the "Overridden metadata" list, the "Show details" and "Edit value" windows open the values in the diff or merge tool configured in git. The tool runs on the machine that runs Neos Studio.
| Action | Compared values |
|---|---|
| "Display differences (external tool)" > "Base value vs overridden value" | The base value and the overridden value |
| "Display differences (external tool)" > "Reference value vs base value" | The reference value and the base value |
| "Display differences (external tool)" > "Reference value vs overridden value" | The reference value and the overridden value |
| "Merge help (external tool)" | The reference value, the overridden value and the base value |
The actions that use the reference value are only displayed when the "Path to the directory containing the reference modules" filter is filled in. An empty value is compared as an empty file.
Configure the diff tool
Neos Studio reads two keys of the git configuration:
diff.guitool: the name of the tool, for examplewinmerge.difftool.<tool>.cmd: the command that starts the tool. Neos Studio runs it the waygit difftooldoes: the first part of the command is the executable, the following parts are its arguments, and$LOCALand$REMOTEare replaced by the two files to compare.
The command must:
- start with the full path of the executable, between double quotes when it contains spaces,
- contain both
$LOCALand$REMOTE, otherwise the tool opens empty and Neos Studio displays an error, - for a script such as the
codecommand of Visual Studio Code, name its extension (code.cmd), because the executable is started without a shell.
difftool.<tool>.path is not used by Neos Studio.
Example with WinMerge, in the .gitconfig file of the user profile:
[diff]
guitool = winmerge
[difftool "winmerge"]
cmd = \"C:/Program Files/WinMerge/WinMergeU.exe\" -e -u \"$LOCAL\" \"$REMOTE\"
Example with Visual Studio Code:
[diff]
guitool = vscode
[difftool "vscode"]
cmd = \"C:/Program Files/Microsoft VS Code/bin/code.cmd\" --wait --diff \"$LOCAL\" \"$REMOTE\"
Run git config --get-regexp diff.* to check the values that Neos Studio reads.
Configure the merge tool
"Merge help (external tool)" works the same way with merge.guitool and mergetool.<tool>.cmd. $LOCAL is replaced by the reference value, $BASE by the overridden value, $REMOTE by the base value, and $MERGED by an empty value. The command must contain at least $LOCAL and $REMOTE.
[merge]
guitool = winmerge
[mergetool "winmerge"]
cmd = \"C:/Program Files/WinMerge/WinMergeU.exe\" -e -u \"$LOCAL\" \"$BASE\" \"$REMOTE\"
When the configuration is incomplete or the executable cannot be started, Neos Studio displays a message naming the git key to fix.