Hello, fellow Neosians,
since the topic is gaining momentum and especially regarding the upcoming media sprint (albeit happening next year), I’d like to share some modeling thoughts, compare them to your own ideas on this and start a discussion.
Status Quo
Currently, we have Asset entities in various forms. They encapsulate a PersistentResource representing the actual file, wherever it might be stored, and add a limited set of metadata properties. Images can be processed with adjustments like cropping, creating ImageVariants; those are referenced in node properties. Images, ImageVariants, and PDF documents etc. can be rendered as Thumbnails as preview or responsive images. Assets can be put in Collections and be assigned to Tags. They might come from different AssetSources and their resources from the different ResourceStorages.
What’s Missing
Asset metadata cannot (easily) be extended; there are packages leveraging AOP for this but understanding and using this as well as adjusting the respective Media module views is cumbersome.
It also can hardly be translated and even if achieved somehow is a hard cut in editor experience.
References from nodes to assets are hard to keep track of, even in Neos 9.
Evaluating PDF content, e.g. for building a comprehensive search index, always requires some kind of hacky workaround.
The implementation of asset sources can be hard depending on how well the other end matches our (limited) model.
How the CR can help
Basically all above requirements are met by using the Neos9 CR - with a few caveats described later
The Model
As an example, I’ll use one of my favorite assets, Dvořák’s symphony no. 9.
Renditions
Our example asset might come in various forms. It might be uploaded as a lossless recording, an mp3 version of that, the cover of the CD or record or the musical score. There might be a 480x320 responsive preview of a cropped image of the first page of the inlay booklet of a CD of a specific recording.
I like to call those forms an asset comes in Renditions, created by renderers. Conceptually, they replace both ImageVariants and Thumbnails (and quite some Asset instances as well I suppose). Renditions may be nested, e.g. a 480x320 px resize rendition of a centered crop rendition of an original image.
Renderers
Renderers are basically just functions: PDF in → JPG out, JPG in → optimized WEBP out etc. They would be implemented as classes and be replaceable by configuration (or called directly), making plugin packages like moc/imageoptimizer or sitegeist/iconoclasm either obsolete or much easier to implement.
Introducing “Fat Nodes” for Assets
Technically, renditions could be modelled as nodes, but that puts pressure on the CR that I think can be reduced by the following approach. It’s an optimization already, though.
Given we have our asset, there might be a single asset node of type Neos.Media:Asset.MusicComposition (as in MusicComposition - Schema.org Type). It can have arbitrary properties, be varied / translated in any way we’re used to in Neos. One central property would be the renditions property. It is of type Renditions and contains Rendition value objects at different paths. They reference a PersistentResource ID and rendition-specific metadata (a resize rendition might be interested in width and height, a crop rendition in coordinates and sizes, a PDF preview rendition in the page number). The rendition’s path segment for the rendition tree would be some kind of ID identifying the rendition by type or parameters.
So if we want said 480x320px image resource, we could call $assetNode->getProperty(‘renditions’)->get(‘inlayBookletImage/manual4To3Crop/480p’); for example.
To create such a rendition via the Neos UI image editor, we would select the inlay booklet image and do the cropping. It is then saved in the asset node at rendition path inlayBookletImage/manual4To3Crop. In the (e.g. TextWithImage) node the crop was made, the image property is actually a reference pointing to the asset. To be able to resolve the selected rendition, the rendition’s path is written as a property to the reference edge connecting content node and asset node. This way both integration code and inspector editor can still know what exact rendition to use. Meanwhile, we have a reference relation that can be resolved both ways. (E.g. to some day replace the AssetUsageProjection once we have a proper way to deal with inline text links / images).
When packages like sitegeist/kaleidoscope (or the media package itself) do responsive image things, they can then use the rendition referenced in the content node, create a resize rendition if missing and save it back to the asset, and then use it.
When an asset’s resource is replaced, we can simply traverse rendition tree and re-render them as their respective creation information is stored as well.
Structuring Assets
One feature we often miss in our projects are folders or similar. Given the CR’s support for hierarchical structures, we can configure this on project level via NodeTypes without further ado.
Collections and Tags and their behavior can similarly be provided by the Media package as core node types.
UI
Having a flexible structure for both assets and their storage means we need editing capabilities matching this flexibility. It could work similar to what the inspector does, but with more available UI space.
Asset Sources
While PersistentResources can keep their resourceCollection mechanism and stay unrelated to the CR, we need a new concept for asset sources. Having implemented one for MS SharePoint, I noticed that implementing the ContentSubgraphInterface would have been a far better match to the API (assets over there behave very similar to nodes, and both hierarchy and references exist) than the current AssetSourceInterface etc.
So the idea would be to have different content repositories for asset sources with different implementations of CR interfaces like the ContentSubgraph - provided by adapters. We’d need a readonly mode for CRs to match the functionality, but that shouldn’t be too hard.
Caveats
There are some drawbacks that must be adressed, mostly regarding performance. This includes functionality like sorting assets by title, finding assets / renditions by their resource’s sha1, finding unused resources etc.
Maybe JSONB indexes in Postgres or custom tables might help here.