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
  2. Real Values. Agenda Neos.Fusion.Forms and how to extend them •

    Recap Fusion.Form & Runtime • Demo - Sitegeist.PaperTiger • Extension points used
  3. Real Values. FusionForm <Neos.Fusion.Form:Form form.target.action="save" form.data.customer={customer}> <Neos.Fusion.Form:FieldContainer field.name="customer[name]" label="Name"> <Neos.Fusion.Form:Input/>

    </Neos.Fusion.Form:FieldContainer> <Neos.Fusion.Form:FieldContainer field.name="customer[email]" label="EMail"> <Neos.Fusion.Form:Input field.name="customer[email]" attributes.type="email </Neos.Fusion.Form:FieldContainer> <Neos.Fusion.Form:Button>Submit</Neos.Fusion.Form:Button> </Neos.Fusion.Form:Form> Photo by Marisol Benitez - Unsplash 1. 3. 2.
  4. 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.
  5. 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.
  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. ⚠ could be an anti-pattern ⚠
  7. 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.
  8. Real Values. Extensibility Fusion • FieldTypes • FieldContainers ◦ LabelRenderer

    ◦ ErrorRenderer PHP • ActionInterface • SchemaInterface ◦ TypeConverterInterface ◦ ValidatorInterface • ProcessInterface
  9. Real Values. Documentation • Neos.Demo - Contact Form • docs.neos.io

    • github.com/neos/fusion-form • Talk @NeosCon online 2021
  10. 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
  11. 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.
  12. 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.
  13. 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
  14. Real Values. 2. E-Mail Field • NodeType based on Sitegeist.PaperTiger:Field

    • NodeType:Name - Fusion prototype • NodeType:Name.Schema - Fusion prototype
  15. 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. <Sitegeist.PaperTiger:FieldContainer 6. field.name={q(node).property(identifier)} 7. label={q(node).property('label')} 8. > 9. <Neos.Fusion.Form:Input 10. attributes.type="email" 11. attributes.required={q(node).property('isRequired')} 12. /> 13. </Sitegeist.PaperTiger:FieldContainer> 14. ` 15. }
  16. 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. [email protected] = ${props.isRequired ? value.required : 6. }
  17. 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. [email protected] = ${props.isRequired ? value.required : 6. } ⚠ fe-validation != be-validation ⚠
  18. Real Values. 3. Message Action • Class implementing ActionInterface •

    NodeType based on Sitegeist.PaperTiger:Action • NodeType:Name.Preview - Fusion prototype • NodeType:Name.Definition - Fusion prototype
  19. 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. }
  20. 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. }
  21. 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
  22. 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