Issues (2551)

src/Impl/AbstractDefinitionDeployer.php (10 issues)

1
<?php
2
3
namespace Jabe\Impl;
4
5
use Jabe\ProcessEngineException;
6
use Jabe\Impl\Cfg\{
7
    IdGeneratorInterface,
8
    ProcessEngineConfigurationImpl
9
};
10
use Jabe\Impl\Cmd\CommandLogger;
11
use Jabe\Impl\Context\Context;
12
use Jabe\Impl\Core\Model\Properties;
13
use Jabe\Impl\Interceptor\CommandContext;
14
use Jabe\Impl\Persistence\Deploy\DeployerInterface;
15
use Jabe\Impl\Persistence\Deploy\Cache\DeploymentCache;
16
use Jabe\Impl\Persistence\Entity\{
17
    DeploymentEntity,
18
    ResourceEntity
19
};
20
21
abstract class AbstractDefinitionDeployer implements DeployerInterface
22
{
23
    public const DIAGRAM_SUFFIXES = [ "png", "jpg", "gif", "svg" ];
24
25
    //private final CommandLogger LOG = ProcessEngineLogger.CMD_LOGGER;
26
27
    protected $idGenerator;
28
29
    public function getIdGenerator(): IdGeneratorInterface
30
    {
31
        return $this->idGenerator;
32
    }
33
34
    public function setIdGenerator(IdGeneratorInterface $idGenerator): void
35
    {
36
        $this->idGenerator = $idGenerator;
37
    }
38
39
    public function deploy(DeploymentEntity $deployment): void
40
    {
41
        //LOG.debugProcessingDeployment(deployment.getName());
42
        $properties = new Properties();
43
        $definitions = $this->parseDefinitionResources($deployment, $properties);
44
        $this->ensureNoDuplicateDefinitionKeys($definitions);
45
        $this->postProcessDefinitions($deployment, $definitions, $properties);
46
    }
47
48
    protected function parseDefinitionResources(DeploymentEntity $deployment, Properties $properties): array
49
    {
50
        $definitions = [];
51
        foreach ($deployment->getResources() as $resource) {
52
            //LOG.debugProcessingResource(resource.getName());
53
            if ($this->isResourceHandled($resource)) {
54
                $definitions = array_merge($definitions, $this->transformResource($deployment, $resource, $properties));
55
            }
56
        }
57
        return $definitions;
58
    }
59
60
    protected function isResourceHandled(ResourceEntity $resource): bool
61
    {
62
        $resourceName = $resource->getName();
63
64
        foreach ($this->getResourcesSuffixes() as $suffix) {
65
            if (str_ends_with($resourceName, $suffix)) {
66
                return true;
67
            }
68
        }
69
70
        return false;
71
    }
72
73
    /**
74
     * @return array the list of resource suffixes for this cacheDeployer
75
     */
76
    abstract protected function getResourcesSuffixes(): array;
77
78
    protected function transformResource(DeploymentEntity $deployment, ResourceEntity $resource, Properties $properties): array
79
    {
80
        $resourceName = $resource->getName();
81
        $definitions = $this->transformDefinitions($deployment, $resource, $properties);
82
83
        foreach ($definitions as $definition) {
84
            $definition->setResourceName($resourceName);
85
86
            $diagramResourceName = $this->getDiagramResourceForDefinition($deployment, $resourceName, $definition, $deployment->getResources());
87
            if ($diagramResourceName !== null) {
88
                $definition->setDiagramResourceName($diagramResourceName);
89
            }
90
        }
91
92
        return $definitions;
93
    }
94
95
    /**
96
     * Transform the resource entity into definition entities.
97
     *
98
     * @param deployment the deployment the resources belongs to
99
     * @param resource the resource to transform
100
     * @return a list of transformed definition entities
101
     */
102
    abstract protected function transformDefinitions(DeploymentEntity $deployment, ResourceEntity $resource, Properties $properties): array;
103
104
    /**
105
     * Returns the default name of the image resource for a certain definition.
106
     *
107
     * It will first look for an image resource which matches the definition
108
     * specifically, before resorting to an image resource which matches the file
109
     * containing the definition.
110
     *
111
     * Example: if the deployment contains a BPMN 2.0 xml resource called
112
     * 'abc.bpmn20.xml' containing only one process with key 'myProcess', then
113
     * this method will look for an image resources called 'abc.myProcess.png'
114
     * (or .jpg, or .gif, etc.) or 'abc.png' if the previous one wasn't found.
115
     *
116
     * Example 2: if the deployment contains a BPMN 2.0 xml resource called
117
     * 'abc.bpmn20.xml' containing three processes (with keys a, b and c),
118
     * then this method will first look for an image resource called 'abc.a.png'
119
     * before looking for 'abc.png' (likewise for b and c).
120
     * Note that if abc.a.png, abc.b.png and abc.c.png don't exist, all
121
     * processes will have the same image: abc.png.
122
     *
123
     * @return string null if no matching image resource is found.
124
     */
125
    protected function getDiagramResourceForDefinition(DeploymentEntity $deployment, string $resourceName, DefinitionEntity $definition, array $resources): ?string
0 ignored issues
show
The parameter $deployment is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

125
    protected function getDiagramResourceForDefinition(/** @scrutinizer ignore-unused */ DeploymentEntity $deployment, string $resourceName, DefinitionEntity $definition, array $resources): ?string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
126
    {
127
        foreach ($this->getDiagramSuffixes() as $diagramSuffix) {
128
            $definitionDiagramResource = $this->getDefinitionDiagramResourceName($resourceName, $definition, $diagramSuffix);
129
            $diagramForFileResource = $this->getGeneralDiagramResourceName($resourceName, $definition, $diagramSuffix);
130
            if (array_key_exists($definitionDiagramResource, $resources)) {
131
                return $definitionDiagramResource;
132
            } elseif (array_key_exists($diagramForFileResource, $resources)) {
133
                return $diagramForFileResource;
134
            }
135
        }
136
        // no matching diagram found
137
        return null;
138
    }
139
140
    protected function getDefinitionDiagramResourceName(string $resourceName, DefinitionEntity $definition, string $diagramSuffix): string
141
    {
142
        $fileResourceBase = $this->stripDefinitionFileSuffix($resourceName);
143
        $definitionKey = $definition->getKey();
144
        return $fileResourceBase . $definitionKey . "." . $diagramSuffix;
145
    }
146
147
    protected function getGeneralDiagramResourceName(string $resourceName, DefinitionEntity $definition, string $diagramSuffix): string
0 ignored issues
show
The parameter $definition is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

147
    protected function getGeneralDiagramResourceName(string $resourceName, /** @scrutinizer ignore-unused */ DefinitionEntity $definition, string $diagramSuffix): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
148
    {
149
        $fileResourceBase = $this->stripDefinitionFileSuffix($resourceName);
150
151
        return $fileResourceBase . $diagramSuffix;
152
    }
153
154
    protected function stripDefinitionFileSuffix(string $resourceName): string
155
    {
156
        foreach ($this->getResourcesSuffixes() as $suffix) {
157
            if (str_ends_with($resourceName, $suffix)) {
158
                return substr($resourceName, 0, strlen($resourceName) - strlen($suffix));
159
            }
160
        }
161
        return $resourceName;
162
    }
163
164
    protected function getDiagramSuffixes(): array
165
    {
166
        return self::DIAGRAM_SUFFIXES;
167
    }
168
169
    protected function ensureNoDuplicateDefinitionKeys(array $definitions): void
170
    {
171
        $keys = [];
172
173
        foreach ($definitions as $definition) {
174
            $key = $definition->getKey();
175
176
            if (in_array($key, $keys)) {
177
                throw new ProcessEngineException("The deployment contains definitions with the same key '" . $key . "' (id attribute), this is not allowed");
178
            }
179
180
            $keys[] = $key;
181
        }
182
    }
183
184
    protected function postProcessDefinitions(DeploymentEntity $deployment, array $definitions, Properties $properties): void
185
    {
186
        if ($deployment->isNew()) {
187
            // if the deployment is new persist the new definitions
188
            $this->persistDefinitions($deployment, $definitions, $properties);
189
        } else {
190
            // if the current deployment is not a new one,
191
            // then load the already existing definitions
192
            $this->loadDefinitions($deployment, $definitions, $properties);
193
        }
194
    }
195
196
    protected function persistDefinitions(DeploymentEntity $deployment, array $definitions, Properties $properties): void
197
    {
198
        foreach ($definitions as $definition) {
199
            $definitionKey = $definition->getKey();
200
            $tenantId = $deployment->getTenantId();
201
202
            $latestDefinition = $this->findLatestDefinitionByKeyAndTenantId($definitionKey, $tenantId);
203
204
            $this->updateDefinitionByLatestDefinition($deployment, $definition, $latestDefinition);
205
206
            $this->persistDefinition($definition);
207
            $this->registerDefinition($deployment, $definition, $properties);
208
        }
209
    }
210
211
    protected function updateDefinitionByLatestDefinition(DeploymentEntity $deployment, DefinitionEntity $definition, DefinitionEntity $latestDefinition): void
212
    {
213
        $definition->setVersion($this->getNextVersion($deployment, $definition, $latestDefinition));
214
        $definition->setId($this->generateDefinitionId($deployment, $definition, $latestDefinition));
215
        $definition->setDeploymentId($deployment->getId());
216
        $definition->setTenantId($deployment->getTenantId());
217
    }
218
219
    protected function loadDefinitions(DeploymentEntity $deployment, array $definitions, Properties $properties): void
220
    {
221
        foreach ($definitions as $definition) {
222
            $deploymentId = $deployment->getId();
223
            $definitionKey = $definition->getKey();
224
225
            $persistedDefinition = $this->findDefinitionByDeploymentAndKey($deploymentId, $definitionKey);
0 ignored issues
show
It seems like $deploymentId can also be of type null; however, parameter $deploymentId of Jabe\Impl\AbstractDefini...ionByDeploymentAndKey() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

225
            $persistedDefinition = $this->findDefinitionByDeploymentAndKey(/** @scrutinizer ignore-type */ $deploymentId, $definitionKey);
Loading history...
226
            $this->handlePersistedDefinition($definition, $persistedDefinition, $deployment, $properties);
227
        }
228
    }
229
230
    protected function handlePersistedDefinition(
231
        DefinitionEntity $definition,
232
        ?DefinitionEntity $persistedDefinition,
233
        DeploymentEntity $deployment,
234
        Properties $properties
235
    ): void {
236
        $this->persistedDefinitionLoaded($deployment, $definition, $persistedDefinition);
0 ignored issues
show
It seems like $persistedDefinition can also be of type null; however, parameter $persistedDefinition of Jabe\Impl\AbstractDefini...istedDefinitionLoaded() does only seem to accept Jabe\Impl\DefinitionEntity, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

236
        $this->persistedDefinitionLoaded($deployment, $definition, /** @scrutinizer ignore-type */ $persistedDefinition);
Loading history...
237
        $this->updateDefinitionByPersistedDefinition($deployment, $definition, $persistedDefinition);
0 ignored issues
show
It seems like $persistedDefinition can also be of type null; however, parameter $persistedDefinition of Jabe\Impl\AbstractDefini...ByPersistedDefinition() does only seem to accept Jabe\Impl\DefinitionEntity, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

237
        $this->updateDefinitionByPersistedDefinition($deployment, $definition, /** @scrutinizer ignore-type */ $persistedDefinition);
Loading history...
238
        $this->registerDefinition($deployment, $definition, $properties);
239
    }
240
241
    protected function updateDefinitionByPersistedDefinition(DeploymentEntity $deployment, DefinitionEntity $definition, DefinitionEntity $persistedDefinition): void
242
    {
243
        $definition->setVersion($persistedDefinition->getVersion());
244
        $definition->setId($persistedDefinition->getId());
245
        $definition->setDeploymentId($deployment->getId());
246
        $definition->setTenantId($persistedDefinition->getTenantId());
247
    }
248
249
    /**
250
     * Called when a previous version of a definition was loaded from the persistent store.
251
     *
252
     * @param deployment the deployment of the definition
253
     * @param definition the definition entity
254
     * @param persistedDefinition the loaded definition entity
255
     */
256
    protected function persistedDefinitionLoaded(DeploymentEntity $deployment, DefinitionEntity $definition, DefinitionEntity $persistedDefinition): void
257
    {
258
        // do nothing;
259
    }
260
261
    /**
262
     * Find a definition entity by deployment id and definition key.
263
     * @param deploymentId the deployment id
264
     * @param definitionKey the definition key
265
     * @return DefinitionEntity the corresponding definition entity or null if non is found
266
     */
267
    abstract protected function findDefinitionByDeploymentAndKey(string $deploymentId, string $definitionKey): DefinitionEntity;
268
269
    /**
270
     * Find the last deployed definition entity by definition key and tenant id.
271
     *
272
     * @return DefinitionEntity the corresponding definition entity or null if non is found
273
     */
274
    abstract protected function findLatestDefinitionByKeyAndTenantId(string $definitionKey, ?string $tenantId): DefinitionEntity;
275
276
    /**
277
     * Persist definition entity into the database.
278
     * @param definition the definition entity
279
     */
280
    abstract protected function persistDefinition(DefinitionEntity $definition): void;
281
282
    protected function registerDefinition(DeploymentEntity $deployment, DefinitionEntity $definition, Properties $properties): void
283
    {
284
        $deploymentCache = $this->getDeploymentCache();
285
286
        // Add to cache
287
        $this->addDefinitionToDeploymentCache($deploymentCache, $definition);
288
289
        $this->definitionAddedToDeploymentCache($deployment, $definition, $properties);
290
291
        // Add to deployment for further usage
292
        $deployment->addDeployedArtifact($definition);
293
    }
294
295
    /**
296
     * Add a definition to the deployment cache
297
     *
298
     * @param deploymentCache the deployment cache
299
     * @param definition the definition to add
300
     */
301
    abstract protected function addDefinitionToDeploymentCache(DeploymentCache $deploymentCache, DefinitionEntity $definition): void;
302
303
    /**
304
     * Called after a definition was added to the deployment cache.
305
     *
306
     * @param deployment the deployment of the definition
307
     * @param definition the definition entity
308
     */
309
    protected function definitionAddedToDeploymentCache(DeploymentEntity $deployment, DefinitionEntity $definition, Properties $properties): void
310
    {
311
        // do nothing
312
    }
313
314
    /**
315
     * per default we increment the latest definition version by one - but you
316
     * might want to hook in some own logic here, e.g. to align definition
317
     * versions with deployment / build versions.
318
     */
319
    protected function getNextVersion(DeploymentEntity $deployment, DefinitionEntity $newDefinition, DefinitionEntity $latestDefinition): int
0 ignored issues
show
The parameter $newDefinition is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

319
    protected function getNextVersion(DeploymentEntity $deployment, /** @scrutinizer ignore-unused */ DefinitionEntity $newDefinition, DefinitionEntity $latestDefinition): int

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $deployment is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

319
    protected function getNextVersion(/** @scrutinizer ignore-unused */ DeploymentEntity $deployment, DefinitionEntity $newDefinition, DefinitionEntity $latestDefinition): int

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
320
    {
321
        $result = 1;
322
        if ($latestDefinition !== null) {
323
            $latestVersion = $latestDefinition->getVersion();
324
            $result = $latestVersion + 1;
325
        }
326
        return $result;
327
    }
328
329
    /**
330
     * create an id for the definition. The default is to ask the IdGenerator
331
     * and add the definition key and version if that does not exceed 64 characters.
332
     * You might want to hook in your own implementation here.
333
     */
334
    protected function generateDefinitionId(DeploymentEntity $deployment, DefinitionEntity $newDefinition, DefinitionEntity $latestDefinition): string
0 ignored issues
show
The parameter $deployment is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

334
    protected function generateDefinitionId(/** @scrutinizer ignore-unused */ DeploymentEntity $deployment, DefinitionEntity $newDefinition, DefinitionEntity $latestDefinition): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $latestDefinition is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

334
    protected function generateDefinitionId(DeploymentEntity $deployment, DefinitionEntity $newDefinition, /** @scrutinizer ignore-unused */ DefinitionEntity $latestDefinition): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
335
    {
336
        $nextId = $this->idGenerator->getNextId();
337
338
        $definitionKey = $newDefinition->getKey();
339
        $definitionVersion = $newDefinition->getVersion();
340
341
        $definitionId = $definitionKey
342
            . ":" . $definitionVersion
343
            . ":" . $nextId;
344
345
        // ACT-115: maximum id length is 64 characters
346
        if (strlen($definitionId) > 64) {
347
            $definitionId = $nextId;
348
        }
349
        return $definitionId;
350
    }
351
352
    protected function getProcessEngineConfiguration(): ?ProcessEngineConfigurationImpl
353
    {
354
        return Context::getProcessEngineConfiguration();
355
    }
356
357
    protected function getCommandContext(): ?CommandContext
358
    {
359
        return Context::getCommandContext();
360
    }
361
362
    protected function getDeploymentCache(): DeploymentCache
363
    {
364
        return $this->getProcessEngineConfiguration()->getDeploymentCache();
0 ignored issues
show
The method getDeploymentCache() does not exist on Jabe\Impl\Cfg\ProcessEngineConfigurationImpl. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

364
        return $this->getProcessEngineConfiguration()->/** @scrutinizer ignore-call */ getDeploymentCache();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
365
    }
366
}
367