|  | 
|  | 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