Make autogenerated FusionCode for NodeTypes extensible

Currently the automagically generated FusionCode for each NodeType is neither really extensible nor well documented. That leads to some confusion for new users and also makes defining of nodeTypes sometimes difficult.

Currently the generator can only be exchanged globally. That leads to the situation that it is not easily possible to extend the generated prototypes for a package but leave external code like Neos.Nodetypes intact. I think Neos would benefit from an option to control the generators used for each NodeType more fine grained.

Aproach 1 : Settings.yaml

To achieve this i suggest to add a setting to control the used generator based on the superTypes of the given Node.

TYPO3:
  Neos:
    typoScript:
      autogenerators:
        superTypes:
          TYPO3.Neos:Document: 
            generator: \TYPO3\Neos\Domain\Service\DocumentPrototypeGenerator
          TYPO3.Neos:Content: 
            generator: \TYPO3\Neos\Domain\Service\ContentPrototypeGenerator
          Vendor.Site:Content:
            generator: \Vendor\Site\Service\ContentPrototypeGenerator
            @position: 'start'      	

For each NodeType the first matching autogenerator is would be applied. That way the default behavior would be the same but it will become easy to extend or to override.

Aproach 2 : NodeTypes.yaml

Another possible approach could put the control into the nodeType or a superType

## default 
TYPO3.Neos:Content:
  typoscriptAutogenerator: '\TYPO3\Neos\Domain\Service\DefaultContentPrototypeGenerator'
TYPO3.Neos:Document:
  typoscriptAutogenerator: '\TYPO3\Neos\Domain\Service\DefaultDocumentPrototypeGenerator'

## custom generator 
Vendor.Site:Content.Example1:
  typoscriptAutogenerator: '\Vendor\Site\Service\ContentPrototypeGenerator'

## use no generator
Vendor.Site:Content.Example2:
  typoscriptAutogenerator: ~

## default ... same result as always
Vendor.Site:Content.Example3:
  superTypes:
    TYPO3.Neos:Content:  true
  # typoscriptAutogenerator ... is inherited from super type

By documenting any of both aproaches this the hidden magic would become visible magic and hopefullly will result in less confusion.

3 Likes

I personally prefer the second approach via nodeTypes.yaml since this would make the feature visible in the nodeType documentation.

1 Like

I really like the proposal! The NodeTypes.yaml approach looks a lot better to me too.
But the API side may need polishing.
E.g. I would call it not ```````typoscriptAutogenerator` but rather @prototypeGenerator (or prototypeGeneratorClass?) or something.
The default generator mechanism may be set on TYPO3.Neos:Node level, and would be easy to override if needed.

Offcourse the name of the nodeType-option is just a first suggestion.

I also like the idea but I think it should be separate from the NodeType definition (which is currently unrelated to typoscript/fusion, isn’t it?)

Well it is related since there is fusion-code created for each NodeType. This connection is often confusing for newbies and i hope that by making the autogenerator-option visible in the nodeType it will be much easier to explain this connection.

Sure. What I meant is: The CR can be used without Fusion so IMO that configuration should not be part of the CR schema.

Yes, it’s quite confusing indeed… To be honest: I’m not sure though whether this new feature will solve this issue because in reality those autogenerators will be configured in a base type mostly, thus invisible to the user.

But I’m not saying that it wouldn’t be useful and more explicit of course. I’m just not sure wether it really belongs to the node type’s definition. But lets see what others think.

Regarding the confusion with this, I still stumble upon this quite often and I hope that we can improve the situation with some (built-in?) tooling (like Christians TS inspector)

1 Like

That is true … maybe it makes sense from the cr-side to add a section additionalOptions of schema-type any similar to the EditorOptions. That way the path could something like “NodeType.additionalOptions.neos.fusion.generator”

One of my personal itches is that my nodetypes often do’nt rely on TYPO3.TypoScript:Template anymore since i use less and less fluid. So i always end up writing the following lines to most of my prototypes.

prototype(Vendor.Site:Content.Type) >
prototype(Vendor.Site:Content.Type) < prototype (TYPO3.TypoScript:Tag) {
     ...

I’m not sure whether that improves it tbh.
But after all we also have Neos/UI specific parts within the NodeType definition so maybe it doesn’t really matter

Maaaaybe we should reconsider the whole idea of auto-generated prototypes…
I don’t have a good idea for a replacement but it might be worth thinking about it

2 Likes

It is certainly confusing to the user how it is now. Partly due to not being clearly documented and no existing TypoScript debugging tool. It was recently made possible to extend at all (without AOP) with the introduction of a interface that could be overridden.

I’d prefer putting the configuration in the NodeTypes configuration and the logic in the Neos package (which it is already), so neither Fusion nor CR know anything about this convenience “glue”.

Would certainly be nice to avoid resetting every TypoScript object from a Template and it would make it easier for people to have document node types generated in their preferred way since there are several practices to this.

3 Likes

I know … there even is an interface \TYPO3\Neos\Domain\Service\DefaultPrototypeGeneratorInterface but since you can only define a single implementation it is difficult to use since you probaly do not want to alter the autocreated fusion-code for Neos.NodeTypes. So you could use that as long as the generated code for the base Nodes stays exactly the same.

I basically suggest to use the same interface but allow to configure multiple implementations.

That’s a Factory :wink:

Any way, I like the proposal, and if I remember correctly we have an “options” key in the Schema to store configuration options not directly related to the CR (so i think we just to avoid a first level property)

I like the proposal too, just thinking about “the first matching wins”. What would that mean? The first in the supertype hierarchy? And how would we find that? Couldn’t this become really unpredictable?

@radmiraal regarding “the first matching wins” … that would only apply if that would be configured via settings. I personal prefer to implement it with a setting in NodeTypes.yaml. That also seems to be the consensus here.

I will prepare a PR in the next time.

we have an “options” key in the Schema to store configuration options not directly related to the CR

That is a good idea … so i will use options.prototypeGenerator for the first PR.

Hey @mficzel,

where is the “options” key used so far? Just asking :slight_smile: I’d prefer if we make the the key somehow related to Fusion, e.g. “options.fusionPrototypeGenerator”.

All the best,
Sebastian

No clue where options is already used in the schema it is just a dictionary … but “options.fusionPrototypeGenerator” is fine aswell.

Hey,

I just checked it; seems this is used for pluginViews:

options:
    pluginViews:
        UserFeed:
            label: 'Neos.Demo:NodeTypes.Flickr:options.pluginViews.userFeed'
            controllerActions:
                Neos\Demo\Controller\FlickrController:
                    - userStream

I am personally still undecided if we should make it a top-level property inside the schema or not.
:slight_smile:

All the best, Sebastian

Are you sure? I think you’d need a fallback logic even if it’s configured within the NodeTypes configuration (similar to the fallback logic with constraints). But it should be doable ofc

Re the option name, please make sure to include fusion in it to avoid confusion