Skip to content

Conversation

@jramke
Copy link
Contributor

@jramke jramke commented Nov 23, 2025

Hi,

this PR introduces a new metadata property for ArgumentDefinitions.

The purpose of this property is to make it easier to extend Fluid. Especially when using components and a custom component renderer. It provides a place for arbitrary data you can pass along with an argument, so we can avoid using "private" underscore variables that are now deprecated.

The f:argument ViewHelper also supports it but the metadata does nothing out of the box so its not documented.

To give a better idea why this could be useful i want to share my use case. Im building fluid-primitives and need to expose selected arguments of a component to the client side so they can be picked up when initializing the js for the components. For example a defaultOpen for a Tooltip component. Currently i needed to create a custom __propsMarkedForClient variable that i could then use during the component rendering to expose the props to the client side as a JSON object in the document head, so they can be easily accessed without the need of an html element with data-attributes.

Example usage:

<f:argument name="defaultOpen" type="boolean" optional="{true}" metadata="{client: true}" />

I believe this new metadata property provides a cleaner, more extensible solution for this and similar scenarios. It could also help to bridge the gap between Fluid components and other templating engines a little more. As described here.

I'd be happy if this could make it upstream, maybe also as a backport for v4

Best regards
Joost

@s2b
Copy link
Contributor

s2b commented Nov 28, 2025

Hi, and thank you for your contribution. I think I understand your use case, and possibly other use cases as well. However, I'm a bit hesitant to introduce yet another untyped generic PHP array, in this case with some magic properties, into Fluid.

I'm still in the early steps of thinking this through, but I was wondering if something like a "scope" might sense instead, where you could specify what the target/purpose of an argument is: relevant for client, relevant for HTML tag (passthrough) or similar?

Before we create a generic API that is accessible by template authors directly, I'd like to at least discuss more specific alternatives that could solve actual problems out-of-the-box.

What do you think?

@jramke
Copy link
Contributor Author

jramke commented Nov 28, 2025

Hi, i totally understand your hesitation.

Something like a "scope" sounds nice, i initially thought this would be a little bit to specific to my usecase but i think more people will run into the issue that they need props from fluid components during js runtime/initialization when building more than just a card component.

Maybe with a scope prop from the core directly, also a first hand logic could be provided to retrieve these props on the client. So the user dont need to bind these props manually via data-attributes to html elements or similar and instead they are exposed automatically maybe similar like im doing it with the HydrationRegistry in my ext currently.

On the other hand i dont know if a scope prop is the correct way/name. I often use the props, that are exposed to the client, also in fluid templates to set initial state/styles to prevent flickers on js initialization. So maybe that could cause confusion if they are available in both?

In my case next to the client flag, i would also have another use case for the metadata prop and that would be a context flag. Like for example the accordion component where the accordion.item has a value prop that is exposed to the components context so childs of each item have access to their current value.

@s2b
Copy link
Contributor

s2b commented Nov 29, 2025

I see your points here... maybe "tags" or "groups" or something similar would make more sense? You could apply one or multiple tags to an argument definition, which could later be used to obtain specific attributes by tag. That would mean that only an array of strings string[] could be provided, not an arbitrary data structure.

@jramke jramke changed the title feat: introduce new metadata property for ArgumentDefinitions feat: introduce new tags property for ArgumentDefinitions Nov 29, 2025
@jramke
Copy link
Contributor Author

jramke commented Nov 29, 2025

I think tags would be a nice option. I updated the pr :)

@s2b
Copy link
Contributor

s2b commented Dec 18, 2025

I've been thinking about this a bit more. First about the data structure and naming: I currently lean towards a more verbose definition, which enforces a data structure on the first level, but could be extended with arbitrary data if necessary, something like this:

<f:argument name="defaultOpen" type="boolean">
    <f:annotation.exposeToClient />
</f:argument>

I also think this should at least come with an API to fetch those groups of arguments, which could then be used both by ViewHelpers and in components. Something like this:

interface ArgumentsBagInterface
{
    public function getByAnnotation(string $annotation): ArgumentsBag;
    /** @return array<string, ArgumentsBag> */
    public function getAnnotated(): array;
    public function get(string $name): mixed;
}

This would also allow us to annotate undefined arguments automatically, see #1265.

WDYT?

@jramke
Copy link
Contributor Author

jramke commented Dec 20, 2025

Hi, i think annotation is indeed a better naming.

The API seems nice but i have some questions:

Is the exposeToClient part from the f:annotation ViewHelper some arbitrary value or does this require a Annotation\ExposeToClientViewHelper class?

And how is the annotation then registered inside the ViewHelper?

The ArgumentsBag seems very cool. But what did you mean with "annotate undefined arguments automatically"?

@s2b
Copy link
Contributor

s2b commented Dec 20, 2025

The implementation details aren't clear yet, but I think this would be a separate ViewHelper per annotation. Or we can think of some other magic to do this dynamically.

What I meant by automatic annotation was that arguments that are passed to the component, but were not registered in its definition, would automatically get "additionalArgument" (or similar) as annotation.

@jramke
Copy link
Contributor Author

jramke commented Dec 20, 2025

Ah ok. I think to make this annotation ViewHelper usable we would need this magic to make this dynamically, however i have no idea how.
In this step im thinking if its worth it to go the verbose way with another viewhelper here at all, because what are possible ways to extend or add data in the annotations viewhelper? I thought about conditionally setting something based on other arguments value but it would have to be done in the nodeInitializedEvent and there is no information about the runtime value of other arguments.

The additionalArguments handling via the annotation seems nice.

@s2b
Copy link
Contributor

s2b commented Jan 5, 2026

I think that there could be various use cases, both for validation and data providing. Since the annotations would be added to the ArgumentDefinition, you would have access to them in various places, such as the argument processor API. So it could be possible to add custom validation rules there (e. g. does an object have a certain property, or for TYPO3: Does the provided record object represent a certain CType).

<f:argument name="record" type="TYPO3\CMS\Core\Domain\RecordInterface">
    <f:annotation.assertRecordType type="tt_content.textmedia" />
</f:argument>

I also don't see a problem with a custom ViewHelper per annotation. Fluid (or EXT:fluid in TYPO3) could ship some of these by default and other extensions could add more. And each annotation ViewHelper could specify its own API.

@jramke
Copy link
Contributor Author

jramke commented Jan 5, 2026

Well actually I also don't know what exactly was my concern, thinking of this again it definitely makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants