Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Neos.Fusion.Form and how to extend them

Neos.Fusion.Form and how to extend them

Sitegeist

April 27, 2023
Tweet

More Decks by Sitegeist

Other Decks in Technology

Transcript

  1. Real Values.
    Neos.Fusion.Forms and how to extend them
    Neos Conference 2023
    Martin Ficzel
    PaperTiger - Oskar Nebelung PaperTiger - Emil Nebelung

    View Slide

  2. Real Values.
    Agenda
    Neos.Fusion.Forms
    and how to extend them
    ● Recap Fusion.Form & Runtime
    ● Demo - Sitegeist.PaperTiger
    ● Extension points used

    View Slide

  3. Real Values.
    Neos.Fusion.Form
    recap

    View Slide

  4. Real Values.
    FusionForm





    View Slide

  5. Real Values.
    Runtime Form - one step
    1. renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
    2.
    3. # the form process for rendering and validation
    4. process = Neos.Fusion.Form:Runtime.SingleStepProcess {
    5.
    6.
    # form content
    7.
    content = afx`...`
    8.
    9.
    # type mapping and validation
    10.
    schema = Neos.Fusion.Form:Runtime.SchemaCollection {
    11.
    firstName = …
    12.
    }
    13. }
    14.
    15. # action after the process is finished
    16. action = Neos.Fusion.Form:Runtime.Actions {
    17.
    email = …
    18. }
    1.
    2.
    4.
    5.
    3.

    View Slide

  6. Real Values.
    1. renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
    2.
    3. # the form process for rendering and validation
    4. process = Neos.Fusion.Form:Runtime.MultiStepProcess {
    5.
    6.
    step1 = Neos.Fusion.Form:Runtime.SingleStepProcess
    7.
    step2 = Neos.Fusion.Form:Runtime.SingleStepProcess
    8.
    9. }
    10.
    11. # action after the process is finished
    12. action = Neos.Fusion.Form:Runtime.Actions
    13. }
    Runtime Form - multi step
    1.
    2.

    View Slide

  7. Real Values.
    1. renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
    2.
    3. # the form process for rendering and validation
    4. process = Neos.Fusion.Form:Runtime.MultiStepProcess {
    5.
    6.
    step1 = Neos.Fusion.Form:Runtime.SingleStepProcess
    7.
    step2 = Neos.Fusion.Form:Runtime.SingleStepProcess
    8.
    9. }
    10.
    11. # action after the process is finished
    12. action = Neos.Fusion.Form:Runtime.Actions
    13. }
    Runtime Form - multi step
    1.
    2.
    ⚠ could be an anti-pattern ⚠

    View Slide

  8. Real Values.
    Runtime Form - multi step
    1. renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
    2.
    3. # the form process for rendering and validation
    4. process = Neos.Fusion.Form:Runtime.SingleStepProcess {
    5.
    6.
    # form content
    7.
    content = Vendor.Site:CustomDialogComponent
    8.
    9.
    # type mapping and validation
    10.
    schema = Neos.Fusion.Form:Runtime.SchemaCollection
    11. }
    12.
    13. # action after the process is finished
    14. action = Neos.Fusion.Form:Runtime.Actions
    15. }
    1.

    View Slide

  9. Real Values.
    Extensibility

    Fusion
    ● FieldTypes
    ● FieldContainers
    ○ LabelRenderer
    ○ ErrorRenderer
    PHP
    ● ActionInterface
    ● SchemaInterface
    ○ TypeConverterInterface
    ○ ValidatorInterface
    ● ProcessInterface

    View Slide

  10. Real Values.
    Documentation
    ● Neos.Demo - Contact Form
    ● docs.neos.io
    ● github.com/neos/fusion-form
    ● Talk @NeosCon online 2021

    View Slide

  11. Real Values.
    Sitegeist.PaperTiger
    Form Builder for NeosCMS

    View Slide

  12. Real Values.
    NodeBased Forms - prior art
    ● Node Based Form Packages
    ○ Neos.Fusion.Form.Builder (FusionRenderer)
    ○ ...
    ● Challenges
    ○ Generic Contents, Grids and Custom rendering
    ○ Deeply nested nodes and collections

    View Slide

  13. Real Values.
    Photo by Karsten Winegear - Unsplash

    View Slide

  14. Real Values.

    View Slide

  15. Real Values.

    View Slide

  16. Real Values.
    More Building
    Blocks!
    Photo by Garett Mizunaka - Unsplash

    View Slide

  17. Real Values.
    Form Builder Nodetype
    1. Sitegeist.PaperTiger:Form:
    2. ui:
    3. label: "Form Builder"
    4. icon: 'icon-list-alt'
    5. superTypes:
    6. Neos.Neos:Content: true
    7. childNodes:
    8. fields:
    9.
    # allow Sitegeist.PaperTiger:Field.Constraint
    10.
    type: Sitegeist.PaperTiger:Field.Collection
    11.
    12. actions:
    13.
    # allow Sitegeist.PaperTiger:Action.Constraint
    14.
    type: Sitegeist.PaperTiger:Action.Collection
    1.
    2.

    View Slide

  18. Real Values.
    Form Builder Nodetype
    1. prototype(Sitegeist.PaperTiger:Form) < prototype(Neos.Neos:ContentCompone
    2.
    3. renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
    4.
    5. process = Neos.Fusion.Form:Runtime.SingleStepProcess {
    6.
    7.
    # form content
    8.
    content = Sitegeist.PaperTiger:FieldCollection.Renderer
    9.
    10.
    # type mapping and validation
    11.
    schema = Sitegeist.PaperTiger:FieldCollection.Schema
    12. }
    13.
    14. # action after the process is finished
    15. action = Sitegeist.PaperTiger:ActionCollection.Definition
    16. }
    1.
    2.
    3.

    View Slide

  19. Real Values.
    1. Generic content in forms
    1. #
    2. # Allow text and image contents inside the form
    3. #
    4. 'Neos.Demo:Content.Text':
    5. superTypes:
    6. 'Sitegeist.PaperTiger:Field.Constraint': true

    View Slide

  20. Real Values.
    2. E-Mail Field
    ● NodeType based on Sitegeist.PaperTiger:Field
    ● NodeType:Name - Fusion prototype
    ● NodeType:Name.Schema - Fusion prototype

    View Slide

  21. Real Values.
    2. E-Mail Field
    ● NodeType based on Sitegeist.PaperTiger:Field
    ● NodeType:Name.Renderer - Fusion prototype
    ● NodeType:Name.Schema - Fusion prototype
    1. prototype(Sitegeist.PaperTiger:Field.Email) < prototype(Neos.Neos:Cont
    2. …
    3.
    4. renderer = afx`
    5. 6.
    field.name={q(node).property(identifier)}
    7.
    label={q(node).property('label')}
    8. >
    9.
    10.
    attributes.type="email"
    11.
    attributes.required={q(node).property('isRequired')}
    12.
    />
    13.
    14. `
    15. }

    View Slide

  22. Real Values.
    2. E-Mail Field
    ● NodeType based on Sitegeist.PaperTiger:Field
    ● NodeType:Name.Renderer - Fusion prototype
    ● NodeType:Name.Schema - Fusion prototype
    1. prototype(Sitegeist.PaperTiger:Field.Email.Schema) < prototype(Neos.Fu
    2. isRequired = ${q(node).property('isRequired')}
    3.
    4. renderer = ${Form.Schema.string().validator('Neos.Flow:EmailAddress
    5. re[email protected] = ${props.isRequired ? value.required :
    6. }

    View Slide

  23. Real Values.
    2. E-Mail Field
    ● NodeType based on Sitegeist.PaperTiger:Field
    ● NodeType:Name.Renderer - Fusion prototype
    ● NodeType:Name.Schema - Fusion prototype
    1. prototype(Sitegeist.PaperTiger:Field.Email.Schema) < prototype(Neos.Fu
    2. isRequired = ${q(node).property('isRequired')}
    3.
    4. renderer = ${Form.Schema.string().validator('Neos.Flow:EmailAddress
    5. re[email protected] = ${props.isRequired ? value.required :
    6. }
    ⚠ fe-validation != be-validation ⚠

    View Slide

  24. Real Values.
    3. Message Action
    ● Class implementing ActionInterface
    ● NodeType based on Sitegeist.PaperTiger:Action
    ● NodeType:Name.Preview - Fusion prototype
    ● NodeType:Name.Definition - Fusion prototype

    View Slide

  25. Real Values.
    3. Message Action
    ● NodeType based on Sitegeist.PaperTiger:Action
    ● NodeType:Name.Preview - Fusion prototype
    ● NodeType:Name.Definition - Fusion prototype
    1. prototype(Sitegeist.PaperTiger:Action.Message.Preview) < prototype(
    2. message = ${q(node).property('message')}
    3.
    4. renderer = afx`
    5. {props.message}
    6. `
    7. }

    View Slide

  26. Real Values.
    ● NodeType based on Sitegeist.PaperTiger:Action
    ● NodeType:Name.Preview - Fusion prototype
    ● NodeType:Name.Definition - Fusion prototype
    3. Message Action
    1. prototype(Sitegeist.PaperTiger:Action.Message.Definition) < prototy
    2. message = ${q(node).property('message')}
    3. [email protected] = Sitegeist.PaperTiger:Action.DataTemplate
    4.
    5. renderer = Sitegeist.PaperTiger:Action {
    6. type = 'Neos.Fusion.Form.Runtime:Message'
    7. options {
    8.
    message = ${props.message}
    9. }
    10. }
    11. }

    View Slide

  27. Real Values.
    even more
    ● Captcha Field
    ○ Sitegeist.FusionForm.FriendlyCaptcha
    ○ FriendlyCaptcha - Fieldtype
    ○ FriendlyCaptchaValidator
    ● Upload Field
    ○ Sitegeist.FusionForm.Upload
    ○ Cache & Multiple support
    ○ Fieldtype / TypeConverter / Validator
    ● E-Mail Action
    ○ Sitegeist.Neos.SymfonyMailer
    ○ SendMailAction

    View Slide

  28. Real Values.
    Sitegeist.PaperTiger
    ● Current version 0.30 …
    ● Opinionated and hard to replace
    ● No multisteps forms / No dependencies between fields
    sitegeist/Sitegeist.PaperTiger
    sitegeist/Sitegeist.FusionForm.FriendlyCaptcha
    sitegeist/Sitegeist.FusionForm.Upload
    sitegeist/Sitegeist.Neos.SymfonyMailer

    View Slide

  29. Real Values.
    Thank you!
    Slack: @kopfaufholz
    Fediverse: @[email protected]
    PaperTiger - Oskar Nebelung
    PaperTiger - Emil Nebelung

    View Slide