|
| 1 | +# Generator |
| 2 | + |
| 3 | +The code generator provides the runtime environment for various components. These can be interconnected via a |
| 4 | +configuration. Thus, individual operational sequences can be provided and combined. By this modular structure the code |
| 5 | +generator can be individually extended and configured by developers. |
| 6 | + |
| 7 | +The library consists of four subpackages. These define the runtime environment for the code generation. |
| 8 | +The subpackage `Workflow` is responsible for processing the individual workflows. The configuration of the runtime environment |
| 9 | +takes over the subpackage `Config`. The configuration is read from the subpackage `Console` via a command line interface. |
| 10 | +The `Code` subpackage contains classes for file and namespace resolution. |
| 11 | + |
| 12 | +## Workflow |
| 13 | + |
| 14 | +The figure beneath shows the classes from the `Workflow` package. The class `WorkflowEngine` processes a list of |
| 15 | +classes in a specified order which implement the `Description` interface. The processing is started by the `run()` method. |
| 16 | +The first parameter `workflowContext` is of type `WorkflowContext`. The second parameter `componentDescriptions` is a list |
| 17 | +of objects of type `Description`. A standard implementation of the `WorkflowContext` interface is the class |
| 18 | +`WorkflowContextMap`. It allows to manage the input and output data of the individual components. The `get()` method |
| 19 | +provides associative access to the respective slot data. The `slotName` parameter is of type `String` and corresponds |
| 20 | +to the slot name under which the desired slot data can be found. The `put()` method stores the slot data. The first |
| 21 | +parameter `slotName` of type `String` corresponds to the slot name, under which the data can be retrieved later. The |
| 22 | +second parameter `slotValue` of type `mixed` corresponds to the slot data to be stored. The slot data is stored in the |
| 23 | +`map` attribute under the given slot name. The `getByDescription()` method returns all input data required for calling |
| 24 | +a component from the `WorkflowContext` object. The parameter description is of the type `DescriptionWithInputSlot`. The |
| 25 | +return value is of type `array`. |
| 26 | + |
| 27 | +Several interfaces are available for the description of a component. The interface `Description` must be implemented |
| 28 | +by all classes that describe a component for the code generator. The `component()` method returns the component. A |
| 29 | +component can be a function or a class. This is indicated by the pseudo-type `callable`. If a component is defined as a |
| 30 | +class, it must provide a `__invoke()` method. This method is automatically executed when an object is called as a function. |
| 31 | +An interface is not possible here because the components can have different input parameters and otherwise there would |
| 32 | +be no function support. The `DescriptionWithInputSlot` interface is available for the description of required input data. |
| 33 | +The `inputSlots()` method returns a list with slot names for the required input data when the component is called. The |
| 34 | +`DescriptionWithOutputSlot` interface is available for describing the output data. The `outputSlot()` method returns the |
| 35 | +slot name under which the output data of the component is stored. The two interfaces `DescriptionWithInputSlot` and |
| 36 | +`DescriptionWithOutputSlot` can be used to describe components that have only input or only output data. Since components |
| 37 | +usually have both input and output data, there is the class `ComponentDescriptionWithSlot`. The constructor has three |
| 38 | +parameters. The first parameter `component` is of type `callable` and corresponds to the component to be executed. The |
| 39 | +second parameter `outputSlot` is of type `string` and corresponds to the slot name under which the output data is |
| 40 | +stored. The third parameter `inputSlots` is a list of element type `String` and contains the slot names for the required input |
| 41 | +data of the component. The `ComponentDescriptionWithSlot` class inherits from the `DescriptionTrait`, `InputSlotTrait` and |
| 42 | +`OutputSlotTrait` classes. These classes each provide the methods for the implemented interfaces. For components with |
| 43 | +input data only, there is the class `ComponentDescriptionWithInputSlotOnly`. This inherits from the classes |
| 44 | +`DescriptionTrait` and `InputSlotTrait`. |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +## Code |
| 49 | + |
| 50 | +The figure beneath shows the classes from the package `Code`. To generate classes it is necessary to know the package, |
| 51 | +the namespace and the file path. The `ClassInfo` interface defines the necessary methods. The `getPackagePrefix()` method |
| 52 | +returns the package prefix. This is prefixed to every class name. The `getSourceFolder()` method returns the path to the |
| 53 | +code directory. The `getClassNamespaceFromPath()` method is used to determine the namespace using the passed path. The |
| 54 | +`getFullyQualifiedClassNameNameFromFilename()` method returns the class name including namespace based on the file name. |
| 55 | +The `getClassNamespace()` method returns the class namespace from FQCN. The `getClassName()` method returns the class |
| 56 | +name from FQCN. The `getPath()` method returns the path which is extracted from class name by using package prefix and |
| 57 | +source folder. The `getFilenameFromPathAndName()` method returns the file name based on the passed path and name. The |
| 58 | +`getPathAndNameFromFilename()` method returns the path and name as a list based on the passed file name. The |
| 59 | +`isValidPath()` method checks whether the passed path or file name belongs to this namespace or package. |
| 60 | + |
| 61 | +A standard implementation of the `ClassInfo` interface is provided by the class `Psr4Info`. The constructor |
| 62 | +has four parameters. The first parameter `sourceFolder` is of type String and corresponds to the path of the code directory. |
| 63 | +The second parameter `packagePrefix` is of type String and corresponds to the package prefix. The third parameter |
| 64 | +`filterDirectoryToNamespace` is of type callable and a filter for the conversion of a directory path into a namespace. |
| 65 | +The fourth parameter `filterNamespaceToDirectory` is of type callable and a filter for the conversion of a namespace into |
| 66 | +a directory path. Using the static `fromComposer()` method, an instance of the class `Psr4Info` will be created based |
| 67 | +on the Composer configuration. Composer is a package manager for PHP. The first parameter `classLoader` is of type `ClassLoader` |
| 68 | +from the external package `Composer::Autoload`. The third parameter `filterDirectoryToNamespace` is of type callable |
| 69 | +and a filter for the conversion of a directory path into a namespace. The fourth parameter `filterNamespaceToDirectory` |
| 70 | +is of type callable and a filter for the conversion of a namespace into a directory path. The fourth parameter `exclude` |
| 71 | +is of type String and specifies which path should be ignored. The class `ClassInfoList` stores a list of objects of |
| 72 | +type `ClassInfo` in the attribute `list`. These are passed to the constructor. More can be added using the |
| 73 | +`addClassInfo()` method. The `classInfoForPath()` method returns the appropriate `ClassInfo` object based on the |
| 74 | +provided path. The `classInfoForFilename()` method returns the matching `ClassInfo` object based on the provided filename. |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +## Config |
| 79 | + |
| 80 | +The figure beneath shows the classes from the package `Config`. The code generator supports different |
| 81 | +types of configuration via the interface `Config`. The `consoleCommands()` method can return a list of CLI commands for |
| 82 | +the code generator CLI. The `WorkflowConfig` interface is available for the configuration of components. It implements the interface |
| 83 | +`Config`. The descriptions of the components can be retrieved using the `componentDescriptions()` method. The return |
| 84 | +value is a list with element type `Description` from the package `Workflow`. A standard implementation of the |
| 85 | +`WorkflowConfig` interface is realized by the class `Workflow`. The constructor expects a list with element type |
| 86 | +`Description` from the package `Workflow`. Several workflows can be combined via the `WorkflowCollection` interface. |
| 87 | +It implements the interfaces `Config` and `Iterator`. The interface `Iterator` allows the iteration via individual |
| 88 | +component descriptions. A standard implementation of the interface `WorkflowCollection` is realized by the class |
| 89 | +`WorkflowList`. The constructor expects a list with element type `WorkflowConfig`. |
| 90 | + |
| 91 | +To be able to read the configuration from different sources, the interface `Resolver` exists. This interface defines the |
| 92 | +`resolve()` method with a parameter. The parameter `workflowContext` is of type `WorkflowContext` from the package |
| 93 | +`Workflow`. The input parameter `workflowContext` can be used by the respective configuration to provide necessary data |
| 94 | +for starting the code generation. The return value is of type `Config`. A standard implementation of the `Resolver` |
| 95 | +interface is realized by the class `FilePhpResolver`. The path to the configuration file is passed to the constructor |
| 96 | +and stored in the `file` attribute. When the `resolve()` method is called, this file is read in and the corresponding |
| 97 | +configuration is returned to the caller. |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | +## Console |
| 102 | + |
| 103 | +To execute the code generator, a command line interface is available in the package `Console`. The figure beneath shows the |
| 104 | +procedure for starting the code generator. You can see a `workflowCommand` object of the type `WorkflowCommand`. First, |
| 105 | +the `loadWorkflowContext()` method of the `workflowCommand` object is called. This returns an object of type |
| 106 | +`WorkflowContext` from the package `Workflow` back. The return value is stored in the local attribute |
| 107 | +`workflowContext`. Next, the `loadConfig()` method of the `workflowCommand` object is called. As argument the local |
| 108 | +attribute `workflowContext` is passed to it. The return value of this method is an object of type `Config` from the |
| 109 | +package `Config`. This is stored in the local attribute `config`. |
| 110 | + |
| 111 | +The following checks what type of configuration the local config attribute is. If this is the type `WorkflowConfig` |
| 112 | +from the package `Config`, the `executeWorkflow()` method of the `workflowCommand` object is called. The local |
| 113 | +attributes `config` and `workflowContext` are passed to it in the listed order. This method is described in detail in the |
| 114 | +interaction reference *Execute Workflow*. If the local attribute `config` is of type `WorkflowCollection` from the package |
| 115 | +`Config`, iteration is first performed over this attribute. At the beginning of each loop pass, the current object is |
| 116 | +fetched from the list and stored in the local attribute `workflowConfig`. Next, the `executeWorkflow()` method of the |
| 117 | +`workflowCommand` object is called. This will call the local attribute `workflowConfig` of the current loop pass and the |
| 118 | +local attribute `workflowContext` in the listed order. At the end of each iteration the internal pointer is set to the |
| 119 | +next element in the list. The iteration is done until there is no next element in the list. If the local attribute |
| 120 | +`config` is neither of type `WorkflowConfig` nor `WorkflowCollection`, an exception is raised via the `RuntimeException` class. |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | +How to start the workflows is shown in the figure beneath. The `executeWorkflow()` method of the `workflowCommand` object |
| 125 | +first calls the `componentDescriptions()` method of the `config` object. The return value is a list of objects of type |
| 126 | +`Description` from the package `Workflow` and is stored in the local attribute `descriptions`. Next, a |
| 127 | +`workflowEngine` object of type `WorkflowEngine` from the package `Workflow` is created. Afterwards, the `workflowCommand` |
| 128 | +object calls its `run()` method. The `workflowContext` object and the local attribute `descriptions` are passed to this |
| 129 | +method in the listed order. This method is described in detail in the interaction reference *Run workflow engine*. |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | +The figure beneath shows the processing of the working steps. First, the list of the input parameter `descriptions` is |
| 134 | +iterated. At the beginning of each loop pass, the current description object is fetched from the list and stored in the |
| 135 | +local attribute `description`. The `workflowEngine` object next calls for each `description` object its `component()` method. |
| 136 | +The result is a `component` object, which is stored in the local attribute `component` and called later. Afterwards, it is |
| 137 | +checked whether the `description` object is of the `DescriptionWithInputSlot` type. This is described in more detail in |
| 138 | +the interaction reference *Instance of DescriptionWithInputSlot*. The next step is to check whether the description |
| 139 | +object is of type `DescriptionWithOutputSlot`. This is described in detail in the interaction reference |
| 140 | +*Instance of DescriptionWithOutputSlot*. At the end of each iteration the internal pointer is set to the next element |
| 141 | +in the list. The iteration is done until there is no next element in the list. |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | +The figure beneath shows the process if the description object is of type `DescriptionWithInputSlot` from the package |
| 146 | +`Workflow`. In this case, input parameters are required when calling the local attribute `component`. Therefore, the |
| 147 | +`workflowEngine` object calls the `getByDescription()` method of the `workflowContext` object. The local attribute |
| 148 | +`description` is passed as argument to this method. Based on this, a list with the necessary input data is returned |
| 149 | +from the `workflowContext` object and stored in the local attribute `inputData`. Next, the local attribute `component` is |
| 150 | +called. The UML stereotype *<<invoke>>* indicates that the local attribute `component` is called like a function. Each |
| 151 | +element in the list of the local attribute `inputData` is passed as one argument. This allows, despite the dynamic call, |
| 152 | +the definition of parameters with corresponding types for the `__invoke()` method in the respective class or for a |
| 153 | +function. The return value is stored in the local attribute `slotValue`. If the description object is not of type |
| 154 | +`DescriptionWithInputSlot`, the local attribute `component` is called without any arguments. The return value is stored |
| 155 | +in the local attribute `slotValue`. |
| 156 | + |
| 157 | + |
| 158 | + |
| 159 | +The figure beneath shows the process, if the description object is of type `DescriptionWithOutputSlot` from |
| 160 | +the package `Workflow`. The `outputSlot()` method of the `description` object is called here. The return value is the slot |
| 161 | +name under which the data is stored in the `workflowContext` object. This is stored in the local attribute `slotName`. |
| 162 | +Next, the `put()` method of the `workflowContext` object is called. The local attributes `slotName` and `slotValue` are |
| 163 | +passed to it in the listed order. |
| 164 | + |
| 165 | + |
0 commit comments