Builder::buildFinder()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 14
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\Oms\Business\OrderStateMachine;
9
10
use LogicException;
11
use SimpleXMLElement;
12
use Spryker\Zed\Oms\Business\Exception\StatemachineException;
13
use Spryker\Zed\Oms\Business\Process\EventInterface;
14
use Spryker\Zed\Oms\Business\Process\ProcessInterface;
15
use Spryker\Zed\Oms\Business\Process\StateInterface;
16
use Spryker\Zed\Oms\Business\Process\TransitionInterface;
17
use Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface;
18
use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface;
19
use Spryker\Zed\Oms\OmsConfig;
20
use Symfony\Component\Finder\Finder as SymfonyFinder;
21
22
class Builder implements BuilderInterface
23
{
24
    /**
25
     * @var \SimpleXMLElement
26
     */
27
    protected $rootElement;
28
29
    /**
30
     * @var array<\Spryker\Zed\Oms\Business\Process\ProcessInterface>
31
     */
32
    protected static $processBuffer = [];
33
34
    /**
35
     * @var \Spryker\Zed\Oms\Business\Process\EventInterface
36
     */
37
    protected $event;
38
39
    /**
40
     * @var \Spryker\Zed\Oms\Business\Process\StateInterface
41
     */
42
    protected $state;
43
44
    /**
45
     * @var \Spryker\Zed\Oms\Business\Process\TransitionInterface
46
     */
47
    protected $transition;
48
49
    /**
50
     * @var \Spryker\Zed\Oms\Business\Process\ProcessInterface
51
     */
52
    protected $process;
53
54
    /**
55
     * @var array|string
56
     */
57
    protected $processDefinitionLocation;
58
59
    /**
60
     * @var string
61
     */
62
    protected $subProcessPrefixDelimiter;
63
64
    /**
65
     * @var \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface
66
     */
67
    protected ProcessCacheReaderInterface $processCacheReader;
68
69
    /**
70
     * @var \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface
71
     */
72
    protected ProcessCacheWriterInterface $processCacheWriter;
73
74
    /**
75
     * @var \Spryker\Zed\Oms\OmsConfig
76
     */
77
    protected OmsConfig $config;
78
79
    /**
80
     * @param \Spryker\Zed\Oms\Business\Process\EventInterface $event
81
     * @param \Spryker\Zed\Oms\Business\Process\StateInterface $state
82
     * @param \Spryker\Zed\Oms\Business\Process\TransitionInterface $transition
83
     * @param \Spryker\Zed\Oms\Business\Process\ProcessInterface $process
84
     * @param array|string $processDefinitionLocation
85
     * @param \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface $processCacheReader
86
     * @param \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface $processCacheWriter
87
     * @param \Spryker\Zed\Oms\OmsConfig $config
88
     * @param string $subProcessPrefixDelimiter
89
     */
90
    public function __construct(
91
        EventInterface $event,
92
        StateInterface $state,
93
        TransitionInterface $transition,
94
        ProcessInterface $process,
95
        $processDefinitionLocation,
96
        ProcessCacheReaderInterface $processCacheReader,
97
        ProcessCacheWriterInterface $processCacheWriter,
98
        OmsConfig $config,
99
        $subProcessPrefixDelimiter = ' - '
100
    ) {
101
        $this->event = $event;
102
        $this->state = $state;
103
        $this->transition = $transition;
104
        $this->process = $process;
105
        $this->processCacheReader = $processCacheReader;
106
        $this->processCacheWriter = $processCacheWriter;
107
        $this->config = $config;
108
        $this->subProcessPrefixDelimiter = $subProcessPrefixDelimiter;
109
110
        $this->setProcessDefinitionLocation($processDefinitionLocation);
111
    }
112
113
    /**
114
     * @param string $processName
115
     * @param bool $regenerateCache
116
     *
117
     * @return \Spryker\Zed\Oms\Business\Process\ProcessInterface
118
     */
119
    public function createProcess($processName, bool $regenerateCache = false): ProcessInterface
120
    {
121
        if (isset(static::$processBuffer[$processName])) {
122
            return static::$processBuffer[$processName];
123
        }
124
125
        if (!$this->config->isProcessCacheEnabled()) {
126
            $mainProcess = $this->createMainProcess($processName);
127
128
            static::$processBuffer[$processName] = $mainProcess;
129
130
            return static::$processBuffer[$processName];
131
        }
132
133
        $isProcessCached = $this->processCacheReader->hasProcess($processName);
134
135
        if ($isProcessCached) {
136
            $process = $this->processCacheReader->getProcess($processName);
137
        }
138
139
        if (!$isProcessCached || $regenerateCache) {
140
            $process = $this->createMainProcess($processName);
141
            $this->processCacheWriter->cacheProcess($process, $processName);
142
        }
143
144
        static::$processBuffer[$processName] = $process;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $process does not seem to be defined for all execution paths leading up to this point.
Loading history...
145
146
        return static::$processBuffer[$processName];
147
    }
148
149
    /**
150
     * @param string $processName
151
     *
152
     * @return \Spryker\Zed\Oms\Business\Process\ProcessInterface
153
     */
154
    protected function createMainProcess(string $processName): ProcessInterface
155
    {
156
        $this->rootElement = $this->loadXmlFromProcessName($processName);
157
158
        $this->mergeSubProcessFiles();
159
160
        /** @var array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap */
161
        $processMap = [];
162
163
        [$processMap, $mainProcess] = $this->createSubProcess($processMap);
164
165
        $stateToProcessMap = $this->createStates($processMap);
166
167
        $this->createSubProcesses($processMap);
168
169
        $eventMap = $this->createEvents();
170
171
        $this->createTransitions($stateToProcessMap, $processMap, $eventMap);
172
173
        return $mainProcess->warmupCache();
174
    }
175
176
    /**
177
     * @return void
178
     */
179
    protected function mergeSubProcessFiles()
180
    {
181
        foreach ($this->rootElement->children() as $xmlProcess) {
182
            $processFile = $this->getAttributeString($xmlProcess, 'file');
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

182
            $processFile = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlProcess, 'file');
Loading history...
183
            $processName = $this->getAttributeString($xmlProcess, 'name');
184
            $processPrefix = $this->getAttributeString($xmlProcess, 'prefix');
185
186
            if ($processFile) {
187
                $xmlSubProcess = $this->loadXmlFromFileName(str_replace(' ', '_', $processFile));
188
189
                if ($processName) {
190
                    $xmlSubProcess->children()->process[0]['name'] = $processName;
0 ignored issues
show
Bug introduced by
The property process does not seem to exist on SimpleXMLElement.
Loading history...
191
                }
192
193
                $this->recursiveMerge($xmlSubProcess, $this->rootElement, $processPrefix);
194
            }
195
        }
196
    }
197
198
    /**
199
     * @param \SimpleXMLElement $fromXmlElement
200
     * @param \SimpleXMLElement $intoXmlNode
201
     * @param string|null $prefix
202
     *
203
     * @return void
204
     */
205
    protected function recursiveMerge($fromXmlElement, $intoXmlNode, $prefix = null)
206
    {
207
        /** @var array<\SimpleXMLElement> $xmlElements */
208
        $xmlElements = $fromXmlElement->children();
209
        if (!$xmlElements) {
210
            return;
211
        }
212
213
        foreach ($xmlElements as $xmlElement) {
214
            $xmlElement = $this->prefixSubProcessElementValue($xmlElement, $prefix);
215
            $xmlElement = $this->prefixSubProcessElementAttributes($xmlElement, $prefix);
216
217
            $child = $intoXmlNode->addChild($xmlElement->getName(), $xmlElement);
218
            $attributes = $xmlElement->attributes();
219
            foreach ($attributes as $k => $v) {
220
                $child->addAttribute($k, $v);
221
            }
222
223
            $this->recursiveMerge($xmlElement, $child, $prefix);
224
        }
225
    }
226
227
    /**
228
     * @param \SimpleXMLElement $xmlElement
229
     * @param string|null $prefix
230
     *
231
     * @return \SimpleXMLElement
232
     */
233
    protected function prefixSubProcessElementValue(SimpleXMLElement $xmlElement, $prefix = null)
234
    {
235
        if ($prefix === null) {
236
            return $xmlElement;
237
        }
238
239
        $namespaceDependentElementNames = ['source', 'target', 'event'];
240
241
        if (in_array($xmlElement->getName(), $namespaceDependentElementNames)) {
242
            $xmlElement[0] = $prefix . $this->subProcessPrefixDelimiter . $xmlElement[0];
243
        }
244
245
        return $xmlElement;
246
    }
247
248
    /**
249
     * @param \SimpleXMLElement $xmlElement
250
     * @param string|null $prefix
251
     *
252
     * @return \SimpleXMLElement
253
     */
254
    protected function prefixSubProcessElementAttributes(SimpleXMLElement $xmlElement, $prefix = null)
255
    {
256
        if ($prefix === null) {
257
            return $xmlElement;
258
        }
259
260
        $namespaceDependentElementNames = ['state', 'event'];
261
262
        if (in_array($xmlElement->getName(), $namespaceDependentElementNames)) {
263
            $xmlElement->attributes()['name'] = $prefix . $this->subProcessPrefixDelimiter . $xmlElement->attributes()['name'];
264
        }
265
266
        return $xmlElement;
267
    }
268
269
    /**
270
     * @param string $fileName
271
     *
272
     * @return \SimpleXMLElement
273
     */
274
    protected function loadXmlFromFileName($fileName)
275
    {
276
        $definitionFile = $this->locateProcessDefinition($fileName);
277
278
        return $this->loadXml($definitionFile->getContents());
279
    }
280
281
    /**
282
     * @param string $fileName
283
     *
284
     * @return \Symfony\Component\Finder\SplFileInfo
285
     */
286
    private function locateProcessDefinition($fileName)
287
    {
288
        $finder = $this->buildFinder($fileName);
289
290
        /** @phpstan-var \Symfony\Component\Finder\SplFileInfo */
291
        return current(iterator_to_array($finder->getIterator()));
292
    }
293
294
    /**
295
     * @param string $processName
296
     *
297
     * @return \SimpleXMLElement
298
     */
299
    protected function loadXmlFromProcessName($processName)
300
    {
301
        return $this->loadXmlFromFileName($processName . '.xml');
302
    }
303
304
    /**
305
     * @param string $xml
306
     *
307
     * @return \SimpleXMLElement
308
     */
309
    protected function loadXml($xml)
310
    {
311
        return new SimpleXMLElement($xml);
312
    }
313
314
    /**
315
     * @return array
316
     */
317
    protected function createEvents()
318
    {
319
        $eventMap = [];
320
321
        foreach ($this->rootElement as $xmlProcess) {
322
            if (!isset($xmlProcess->events)) {
323
                continue;
324
            }
325
326
            $xmlEvents = $xmlProcess->events->children();
327
            foreach ($xmlEvents as $xmlEvent) {
328
                $event = clone $this->event;
329
                $eventId = $this->getAttributeString($xmlEvent, 'name');
0 ignored issues
show
Bug introduced by
It seems like $xmlEvent can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

329
                $eventId = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlEvent, 'name');
Loading history...
330
                $event->setCommand($this->getAttributeString($xmlEvent, 'command'));
331
                $event->setManual($this->getAttributeBoolean($xmlEvent, 'manual'));
0 ignored issues
show
Bug introduced by
It seems like $xmlEvent can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...::getAttributeBoolean() does only seem to accept SimpleXMLElement, 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

331
                $event->setManual($this->getAttributeBoolean(/** @scrutinizer ignore-type */ $xmlEvent, 'manual'));
Loading history...
332
                $event->setOnEnter($this->getAttributeBoolean($xmlEvent, 'onEnter'));
333
                $event->setTimeout($this->getAttributeString($xmlEvent, 'timeout'));
334
                $event->setTimeoutProcessor($this->getAttributeString($xmlEvent, 'timeoutProcessor'));
335
                if ($eventId === null) {
336
                    continue;
337
                }
338
339
                $event->setName($eventId);
340
                $eventMap[$event->getName()] = $event;
341
            }
342
        }
343
344
        return $eventMap;
345
    }
346
347
    /**
348
     * @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap
349
     *
350
     * @return array
351
     */
352
    protected function createSubProcess(array $processMap)
353
    {
354
        $mainProcess = null;
355
        $xmlProcesses = $this->rootElement->children();
356
357
        /** @var \SimpleXMLElement $xmlProcess */
358
        foreach ($xmlProcesses as $xmlProcess) {
359
            $process = clone $this->process;
360
            $processName = $this->getAttributeString($xmlProcess, 'name');
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

360
            $processName = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlProcess, 'name');
Loading history...
361
            $process->setName($processName);
362
            $processMap[$processName] = $process;
363
            $process->setIsMain($this->getAttributeBoolean($xmlProcess, 'main'));
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...::getAttributeBoolean() does only seem to accept SimpleXMLElement, 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

363
            $process->setIsMain($this->getAttributeBoolean(/** @scrutinizer ignore-type */ $xmlProcess, 'main'));
Loading history...
364
365
            $process->setFile($this->getAttributeString($xmlProcess, 'file'));
366
367
            if ($process->getIsMain()) {
368
                $mainProcess = $process;
369
            }
370
        }
371
372
        return [$processMap, $mainProcess];
373
    }
374
375
    /**
376
     * @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap
377
     *
378
     * @return void
379
     */
380
    protected function createSubProcesses(array $processMap)
381
    {
382
        foreach ($this->rootElement as $xmlProcess) {
383
            $processName = $this->getAttributeString($xmlProcess, 'name');
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

383
            $processName = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlProcess, 'name');
Loading history...
384
385
            $process = $processMap[$processName];
386
387
            if ($xmlProcess->subprocesses) {
388
                $xmlSubProcesses = $xmlProcess->subprocesses->children();
389
390
                foreach ($xmlSubProcesses as $xmlSubProcess) {
391
                    $subProcessName = (string)$xmlSubProcess;
392
                    $subProcess = $processMap[$subProcessName];
393
                    $process->addSubProcess($subProcess);
394
                }
395
            }
396
        }
397
    }
398
399
    /**
400
     * @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap
401
     *
402
     * @return array<\Spryker\Zed\Oms\Business\Process\ProcessInterface>
403
     */
404
    protected function createStates(array $processMap)
405
    {
406
        $stateToProcessMap = [];
407
408
        $xmlProcesses = $this->rootElement->children();
409
        foreach ($xmlProcesses as $xmlProcess) {
410
            $processName = $this->getAttributeString($xmlProcess, 'name');
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

410
            $processName = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlProcess, 'name');
Loading history...
411
            $process = $processMap[$processName];
412
413
            if ($xmlProcess->states) {
414
                $xmlStates = $xmlProcess->states->children();
415
                /** @var \SimpleXMLElement $xmlState */
416
                foreach ($xmlStates as $xmlState) {
417
                    $state = clone $this->state;
418
                    $state->setName($this->getAttributeString($xmlState, 'name'));
419
                    $state->setDisplay($this->getAttributeString($xmlState, 'display'));
420
                    $state->setReserved($this->getAttributeBoolean($xmlState, 'reserved'));
0 ignored issues
show
Bug introduced by
It seems like $xmlState can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...::getAttributeBoolean() does only seem to accept SimpleXMLElement, 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

420
                    $state->setReserved($this->getAttributeBoolean(/** @scrutinizer ignore-type */ $xmlState, 'reserved'));
Loading history...
421
                    $state->setProcess($process);
422
423
                    /** @var array $stateFlag */
424
                    $stateFlag = $xmlState->flag;
425
                    if ($stateFlag) {
426
                        $flags = $xmlState->children();
0 ignored issues
show
Bug introduced by
The method children() does not exist on null. ( Ignorable by Annotation )

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

426
                        /** @scrutinizer ignore-call */ 
427
                        $flags = $xmlState->children();

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...
427
                        foreach ($flags->flag as $flag) {
428
                            $state->addFlag((string)$flag);
429
                        }
430
                    }
431
432
                    $process->addState($state);
433
                    $stateToProcessMap[$state->getName()] = $process;
434
                }
435
            }
436
        }
437
438
        return $stateToProcessMap;
439
    }
440
441
    /**
442
     * @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $stateToProcessMap
443
     * @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap
444
     * @param array<\Spryker\Zed\Oms\Business\Process\EventInterface> $eventMap
445
     *
446
     * @throws \LogicException
447
     *
448
     * @return void
449
     */
450
    protected function createTransitions(array $stateToProcessMap, array $processMap, array $eventMap)
451
    {
452
        foreach ($this->rootElement as $xmlProcess) {
453
            if ($xmlProcess->transitions) {
454
                $xmlTransitions = $xmlProcess->transitions->children();
455
456
                $processName = $this->getAttributeString($xmlProcess, 'name');
0 ignored issues
show
Bug introduced by
It seems like $xmlProcess can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...r::getAttributeString() does only seem to accept SimpleXMLElement, 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

456
                $processName = $this->getAttributeString(/** @scrutinizer ignore-type */ $xmlProcess, 'name');
Loading history...
457
458
                foreach ($xmlTransitions as $xmlTransition) {
459
                    $transition = clone $this->transition;
460
461
                    $transition->setCondition($this->getAttributeString($xmlTransition, 'condition'));
462
463
                    $transition->setHappy($this->getAttributeBoolean($xmlTransition, 'happy'));
0 ignored issues
show
Bug introduced by
It seems like $xmlTransition can also be of type null; however, parameter $xmlElement of Spryker\Zed\Oms\Business...::getAttributeBoolean() does only seem to accept SimpleXMLElement, 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

463
                    $transition->setHappy($this->getAttributeBoolean(/** @scrutinizer ignore-type */ $xmlTransition, 'happy'));
Loading history...
464
465
                    $sourceName = (string)$xmlTransition->source;
466
467
                    if (!isset($stateToProcessMap[$sourceName])) {
468
                        throw new LogicException(sprintf('Source: %s does not exist.', $sourceName));
469
                    }
470
471
                    $sourceProcess = $stateToProcessMap[$sourceName];
472
                    $sourceState = $sourceProcess->getState($sourceName);
473
                    $transition->setSource($sourceState);
474
                    $sourceState->addOutgoingTransition($transition);
475
476
                    $targetName = (string)$xmlTransition->target;
477
478
                    if (!isset($stateToProcessMap[$targetName])) {
479
                        throw new LogicException('Target: "' . $targetName . '" does not exist from source: "' . $sourceName . '"');
480
                    }
481
                    $targetProcess = $stateToProcessMap[$targetName];
482
                    $targetState = $targetProcess->getState($targetName);
483
                    $transition->setTarget($targetState);
484
                    $targetState->addIncomingTransition($transition);
485
486
                    if (isset($xmlTransition->event)) {
487
                        $eventId = (string)$xmlTransition->event;
488
489
                        if (!isset($eventMap[$eventId])) {
490
                            throw new LogicException('Event: "' . $eventId . '" does not exist from source: "' . $sourceName . '"');
491
                        }
492
493
                        $event = $eventMap[$eventId];
494
                        $event->addTransition($transition);
495
                        $transition->setEvent($event);
496
                    }
497
498
                    $processMap[$processName]->addTransition($transition);
499
                }
500
            }
501
        }
502
    }
503
504
    /**
505
     * @param \SimpleXMLElement $xmlElement
506
     * @param string $attributeName
507
     *
508
     * @return string|null
509
     */
510
    protected function getAttributeString(SimpleXMLElement $xmlElement, $attributeName)
511
    {
512
        $string = (string)$xmlElement->attributes()[$attributeName];
513
        $string = ($string === '') ? null : $string;
514
515
        return $string;
516
    }
517
518
    /**
519
     * @param \SimpleXMLElement $xmlElement
520
     * @param string $attributeName
521
     *
522
     * @return bool
523
     */
524
    protected function getAttributeBoolean(SimpleXMLElement $xmlElement, $attributeName)
525
    {
526
        return (string)$xmlElement->attributes()[$attributeName] === 'true';
527
    }
528
529
    /**
530
     * @param array|string|null $processDefinitionLocation
531
     *
532
     * @return void
533
     */
534
    private function setProcessDefinitionLocation($processDefinitionLocation)
535
    {
536
        $this->processDefinitionLocation = $processDefinitionLocation;
537
    }
538
539
    /**
540
     * @param string $fileName
541
     *
542
     * @return \Symfony\Component\Finder\Finder
543
     */
544
    protected function buildFinder($fileName)
545
    {
546
        $finder = $this->getFinder();
547
        $finder->in($this->processDefinitionLocation);
548
        if (strpos($fileName, '/') !== false) {
549
            $finder->path($this->createSubProcessPathPattern($fileName));
550
            $finder->name(basename($fileName));
551
        } else {
552
            $finder->name($fileName);
553
        }
554
555
        $this->validateFinder($finder, $fileName);
556
557
        return $finder;
558
    }
559
560
    /**
561
     * @return \Symfony\Component\Finder\Finder
562
     */
563
    protected function getFinder()
564
    {
565
        return new SymfonyFinder();
566
    }
567
568
    /**
569
     * @param \Symfony\Component\Finder\Finder $finder
570
     * @param string $fileName
571
     *
572
     * @throws \Spryker\Zed\Oms\Business\Exception\StatemachineException
573
     *
574
     * @return void
575
     */
576
    protected function validateFinder(SymfonyFinder $finder, $fileName)
577
    {
578
        if ($finder->count() > 1) {
579
            throw new StatemachineException(
580
                sprintf(
581
                    '"%s" found in more then one location. Could not determine which one to choose. Please check your process definition location',
582
                    $fileName,
583
                ),
584
            );
585
        }
586
587
        if ($finder->count() === 0) {
588
            throw new StatemachineException(
589
                sprintf(
590
                    'Could not find "%s". Please check your process definition location',
591
                    $fileName,
592
                ),
593
            );
594
        }
595
    }
596
597
    /**
598
     * @param string $fileName
599
     *
600
     * @return string
601
     */
602
    protected function createSubProcessPathPattern($fileName)
603
    {
604
        return '/\b' . preg_quote(dirname($fileName), '/') . '\b/';
605
    }
606
}
607