Skip to content

Commit a2bd7e4

Browse files
authored
Merge pull request #1 from open-code-modeling/feature/documentation
Add documentation
2 parents e071f83 + 6a8350d commit a2bd7e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1705
-38
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ vendor/
66
composer.lock
77
.idea
88
.php_cs.cache
9+
docs/html

CHANGELOG.md

+61
Original file line numberDiff line numberDiff line change
@@ -1 +1,62 @@
11
# Changelog
2+
3+
All notable changes to this project will be documented in this file, in reverse chronological order by release.
4+
5+
## TBA
6+
7+
### Added
8+
9+
* Nothing
10+
11+
### Deprecated
12+
13+
* Nothing
14+
15+
### Removed
16+
17+
* Nothing
18+
19+
### Fixed
20+
21+
* Nothing
22+
23+
## 0.2.0 (2020-09-05)
24+
25+
### Added
26+
27+
* Documentation (code / markdown docs)
28+
29+
### Deprecated
30+
31+
The following classes are deprecated and support will be removed in next version.
32+
33+
* Class `\OpenCodeModeling\CodeGenerator\Config\ArrayConfig` use `\OpenCodeModeling\CodeGenerator\Config\Workflow` instead
34+
* Class `\OpenCodeModeling\CodeGenerator\Config\Component` use `\OpenCodeModeling\CodeGenerator\Config\WorkflowConfig` instead
35+
* Class `\OpenCodeModeling\CodeGenerator\Config\ComponentCollection` use `\OpenCodeModeling\CodeGenerator\Config\WorkflowCollection` instead
36+
* Class `\OpenCodeModeling\CodeGenerator\Config\ComponentList` use `\OpenCodeModeling\CodeGenerator\Config\WorkflowList` instead
37+
38+
### Removed
39+
40+
* Nothing
41+
42+
### Fixed
43+
44+
* Add console commands from each workflow config
45+
46+
## 0.1.0 (2020-09-04)
47+
48+
### Added
49+
50+
* Initial release
51+
52+
### Deprecated
53+
54+
* Nothing
55+
56+
### Removed
57+
58+
* Nothing
59+
60+
### Fixed
61+
62+
* Nothing

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# PHP Code Generator
22

3-
Generates code depending on a workflow.
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.
46

57
## Installation
68

79
```bash
810
$ composer require open-code-modeling/php-code-generator --dev
911
```
12+
13+
## Documentation
14+
15+
Documentation is [in the docs tree](docs/book/), and can be compiled using [bookdown](http://bookdown.io).

bookdown.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"title": "PHP Code Generator",
3+
"content": [
4+
{"intro": "README.md"},
5+
{"changelog": "CHANGELOG.md"},
6+
{"generator": "docs/book/generator/bookdown.json"}
7+
],
8+
"theme": {
9+
"toc": {
10+
"collapsibleFromLevel": 2
11+
}
12+
},
13+
"template": "bookdown/themes",
14+
"tocDepth": 2,
15+
"target": "./docs/html",
16+
"numbering": false,
17+
"extensions": {
18+
"commonmark": [
19+
"Webuni\\CommonMark\\TableExtension\\TableExtension",
20+
"Webuni\\CommonMark\\AttributesExtension\\AttributesExtension"
21+
]
22+
}
23+
}

docs/book/01-generator.md

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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+
![Code Generator Workflow](./images/workflow.svg)
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+
![Code Generator Workflow](./images/code.svg)
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+
![Code Generator Workflow](./images/codegen-config.svg)
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+
![Code Generator Workflow](./images/codegen-cli.svg)
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+
![Code Generator Workflow](./images/codegen-cli_001.svg)
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+
![Code Generator Workflow](./images/codegen-workflow-engine.svg)
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+
![Code Generator Workflow](./images/codegen-workflow-engine_001.svg)
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+
![Code Generator Workflow](./images/codegen-workflow-engine_002.svg)

docs/book/02-configuration.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Configuration
2+
3+
The code generator CLI can be started through the `bin/ocmcg` executable. This prints the available CLI commands.
4+
The CLI command `ocmcg:workflow:run` executes the code generation depending on the configuration file. The default
5+
configuration file name is `open-code-modeling.php.dist` which should be located in the root folder of the application
6+
/ repository.
7+
8+
This file gets the variable `$workflowContext` provided to configure needed slot data for the code generation e. g.
9+
paths or global data. You have to return an instance of a class which implements `OpenCodeModeling\CodeGenerator\Config\Config`
10+
interface.
11+
12+
The following example add some slot data to the workflow context (`$workflowContext->put()`).
13+
```
14+
/** @var CodeGenerator\Workflow\WorkflowContext $workflowContext */
15+
$workflowContext->put('xml_filename', 'data/domain.xml');
16+
17+
$config = new CodeGenerator\Config\ComponentList(
18+
...[
19+
new CodeGenerator\Config\ComponentConfig(
20+
CodeGenerator\Transformator\StringToFile::workflowComponentDescription(
21+
Inspectio\WorkflowConfigFactory::SLOT_GRAPHML_XML,
22+
'xml_filename'
23+
)
24+
),
25+
]
26+
);
27+
28+
$config->addConsoleCommands(new Inspectio\Console\XmlGenerateAllCommand());
29+
30+
return $config;
31+
```

docs/book/03-cli.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Code Generator CLI
2+
3+
TODO CLI call example

docs/book/bookdown.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"title": "Generator",
3+
"content": [
4+
{"generator": "01-generator.md"},
5+
{"configuration": "02-configuration.md"},
6+
{"cli": "03-cli.md"}
7+
],
8+
"theme": {
9+
"toc": {
10+
"collapsibleFromLevel": 1
11+
}
12+
},
13+
"template": "bookdown/themes",
14+
"tocDepth": 1,
15+
"target": "./html",
16+
"numbering": false,
17+
"extensions": {
18+
"commonmark": [
19+
"Webuni\\CommonMark\\TableExtension\\TableExtension",
20+
"Webuni\\CommonMark\\AttributesExtension\\AttributesExtension"
21+
]
22+
}
23+
}

0 commit comments

Comments
 (0)