Renderer Refactoring » History » Version 10
Philipp Gröbelbauer, 12.06.2024 12:29
1 | 1 | Philipp Gröbelbauer | h1. Renderer Refactoring |
---|---|---|---|
2 | |||
3 | 8 | Philipp Gröbelbauer | {{toc}} |
4 | 7 | Philipp Gröbelbauer | |
5 | 1 | Philipp Gröbelbauer | Branch: https://git.math.uzh.ch/typo3/qfq/-/tree/F17252_Renderer_Refactoring |
6 | |||
7 | h2. Motivation |
||
8 | 2 | Philipp Gröbelbauer | |
9 | 1 | Philipp Gröbelbauer | To achieve a more modern look and feel, QFQ Forms should support Bootstrap 5 in addition to the previously used Bootstrap 3. |
10 | However, implementing this functionality into the current codebase while still practicing "clean code" is not possible. |
||
11 | Therefore the current code is being refactored to support future expansion. |
||
12 | |||
13 | h2. Concept |
||
14 | 2 | Philipp Gröbelbauer | |
15 | 1 | Philipp Gröbelbauer | Previously, preparation and rendering of the form with all its form elements was handled in AbstractBuildForm.php and BuildFormBootstrap.php. |
16 | The new concept introduces many new classes, making the code much more modular. |
||
17 | Most notably: *Separating Configuration and Rendering of Form and FormElements* ! |
||
18 | By doing this, new Renderer Classes can be implemented in the future, which use the same AbstractFormElement objects to render the element in a different way (e.g. Bootstrap 5). |
||
19 | |||
20 | 4 | Philipp Gröbelbauer | h3. Class diagram |
21 | 1 | Philipp Gröbelbauer | |
22 | 4 | Philipp Gröbelbauer | See the class diagram below: |
23 | |||
24 | 1 | Philipp Gröbelbauer | !renderer_class_diagram_update_2024.drawio.png! |
25 | 4 | Philipp Gröbelbauer | |
26 | h3. Sequence Diagram Form and FormElement Instantiation |
||
27 | |||
28 | tbd |
||
29 | |||
30 | h3. Sequence Diagram Rendering |
||
31 | |||
32 | The diagram below describes the rendering process. |
||
33 | |||
34 | * The BaseRenderer (or any specific implementation of it) takes the previously instantiated Form object that describes all aspects of the form that is to be rendered. |
||
35 | |||
36 | 6 | Philipp Gröbelbauer | !renderer_sequence_diagram_update_2024.drawio.png! |
37 | 9 | Philipp Gröbelbauer | |
38 | |||
39 | h2. Dev Guide |
||
40 | |||
41 | This section should answer common questions on how to use the refactored code and how to expand upon it. |
||
42 | |||
43 | h3. Adding a New Form Element |
||
44 | |||
45 | This chapter describes how new form elements can be added into QFQ in the new model. |
||
46 | In this example we are assuming a new FormElement "Chat" should be implemented in QFQ. |
||
47 | Follow these steps: |
||
48 | |||
49 | 10 | Philipp Gröbelbauer | h4. Create a FormElement class |
50 | |||
51 | Create a new class ChatFormElement in the folder Core>Form>FormElement. |
||
52 | 9 | Philipp Gröbelbauer | This class needs to extend AbstractFormElement and should call the parent's construct method when instantiated, as seen in the screenshot below. |
53 | If the form element you want to introduce is a ContainerFormElement, then extend ContainerFormElement instead of AbstractFormElement! |
||
54 | |||
55 | 1 | Philipp Gröbelbauer | !clipboard-202406121148-aqvlm.png! |
56 | |||
57 | 10 | Philipp Gröbelbauer | The job of this class is to prepare and process all data that is needed to display the element. |
58 | *This class must not return any HTML or make assumptions about the way in which the element will be displayed! It exists completely outside of the choice of BS3/BS5/etc.* |
||
59 | |||
60 | Preparation and processing of data can be done after calling parent::process. |
||
61 | |||
62 | |||
63 | h4. Add the new class to FeFactory |
||
64 | |||
65 | Add a new CASE block to the SWITCH statement in FeFactory.php. |
||
66 | 9 | Philipp Gröbelbauer | This way the factory will return an object of your newly created class when needed. |
67 | 1 | Philipp Gröbelbauer | It is best to add a new constant in Constants.php that defines the new FE type. In this example the constant FE_TYPE_CHAT is simply defined as 'chat'. |
68 | |||
69 | !clipboard-202406121152-vlscn.png! |
||
70 | |||
71 | 10 | Philipp Gröbelbauer | h4. Set up the BaseRenderer |
72 | |||
73 | Create a class ChatRenderer in the folder Core>Renderer>FormElement>Base. |
||
74 | It needs to extend the class FormElementRenderer. |
||
75 | This new class is supposed to render a chat element completely independent of the used CSS Framework. |
||
76 | 1 | Philipp Gröbelbauer | In practice, this class might stay empty. |
77 | |||
78 | !clipboard-202406121158-y2gwo.png! |
||
79 | 10 | Philipp Gröbelbauer | |
80 | Next up, *edit the file Core>Renderer>FormElement>BaseRenderer.php* . |
||
81 | |||
82 | Add a new protected field "chatRenderer" of type ?FormElementRenderer to it. |
||
83 | !clipboard-202406121208-jwvbi.png! |
||
84 | |||
85 | In the constructor of BaseRenderer, instantiate an object ob your previously created ChatRenderer class and assign it to the new field. |
||
86 | |||
87 | !clipboard-202406121212-07qxh.png! |
||
88 | |||
89 | In the SWITCH statement of the renderFormElement function, add a new CASE block for your new FE. |
||
90 | This ensures that the BaseRenderer will be using your ChatRenderer class to render objects of the type ChatFormElement. |
||
91 | |||
92 | !clipboard-202406121213-kzi43.png! |
||
93 | |||
94 | |||
95 | |||
96 | h4. Create Specific Renderers |
||
97 | |||
98 | The Chat Form Element will have the same look |