Passed
Branch coverage (932a0f)
by Fabian
03:04
created

RecursiveParentExceptionResolver   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 15
eloc 36
dl 0
loc 89
ccs 37
cts 37
cp 1
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
B resolveExceptionDirs() 0 38 9
A getEventDispatcher() 0 3 1
A getDirectoryContents() 0 10 3
A registerDefaultListeners() 0 5 1
A __construct() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Fabiang\ExceptionGenerator\Generator;
6
7
use DirectoryIterator;
8
use Fabiang\ExceptionGenerator\BreakListener\GitDirectoryListener;
9
use Fabiang\ExceptionGenerator\BreakListener\RootDirectoryListener;
10
use Fabiang\ExceptionGenerator\DirLoopListener\ExceptionDirListener;
11
use Fabiang\ExceptionGenerator\Event\FileEvent;
12
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
13
14
use function basename;
15
use function count;
16
use function dirname;
17
18
class RecursiveParentExceptionResolver
19
{
20
    private const VFSSTREAM_PREFIX = 'vfs:';
21
    private const VFSSTREAM_URL = self::VFSSTREAM_PREFIX . '//';
22
23
    /**
24
     * provides a namespace dpending on looped folders after searching for parent exceptions, which you should use
25
     */
26
    protected string $providedNamespace;
27
28 2
    public function __construct(protected EventDispatcherInterface $eventDispatcher)
29
    {
30 2
        $this->eventDispatcher = $eventDispatcher;
31 2
        $this->registerDefaultListeners();
32
    }
33
34
    /**
35
     * Register default listeners
36
     */
37 1
    private function registerDefaultListeners(): void
38
    {
39 1
        $this->eventDispatcher->addSubscriber(new GitDirectoryListener());
40 1
        $this->eventDispatcher->addSubscriber(new RootDirectoryListener());
41 1
        $this->eventDispatcher->addSubscriber(new ExceptionDirListener());
42
    }
43
44
    /**
45
     * Returns an array containing arrays with parent exception folder and its namespace
46
     */
47 2
    public function resolveExceptionDirs(string $path): ?array
48
    {
49 2
        $exceptionDirArray = null;
50 2
        $eventDispatcher   = $this->eventDispatcher;
51 2
        $loopedPaths[]     = basename($path);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$loopedPaths was never initialized. Although not strictly required by PHP, it is generally a good practice to add $loopedPaths = array(); before regardless.
Loading history...
52 2
        $path              = dirname($path);
53
54
        // loop as long a break listener doesn't stop propagation or we have empty directories
55
        // we iterate through directories up
56
        do {
57 2
            $directory = $this->getDirectoryContents($path);
58
59
            // loop over files/directories and check if the listener can find an exception directory
60 2
            foreach ($directory as $item) {
61 2
                $exceptionDirectoryEvent = new FileEvent($item);
62 2
                $eventDispatcher->dispatch($exceptionDirectoryEvent, 'dir.loop');
63
                //break early, cuz one exception directory can only appear once
64 2
                if ($exceptionDirectoryEvent->isPropagationStopped()) {
65 1
                    $exceptionDirArray[] = $exceptionDirectoryEvent->getParentExceptionDir();
66 1
                    break;
67
                }
68
            }
69
70
            // check for listeners that check if the path iteration loop should be stopped
71 2
            foreach ($directory as $item) {
72 2
                $breakEvent = new FileEvent($item);
73 2
                $eventDispatcher->dispatch($breakEvent, 'file.break');
74 2
                if (false !== $breakEvent->isPropagationStopped()) {
75 1
                    break 2;
76
                }
77
            }
78
79 1
            $path          = dirname($path) !== static::VFSSTREAM_PREFIX ? dirname($path) : static::VFSSTREAM_URL;
80 1
            $loopedPaths[] = basename($path);
81
            //break early cuz DirectoryIterator can't handle vfs root folder
82 1
        } while ((0 === count($directory) || ! $breakEvent->isPropagationStopped()) && $path !== static::VFSSTREAM_URL);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $breakEvent does not seem to be defined for all execution paths leading up to this point.
Loading history...
83
84 2
        return $exceptionDirArray;
85
    }
86
87
    /**
88
     * Get directory contents without dot files.
89
     *
90
     * @return array<int, DirectoryIterator>
91
     */
92 2
    private function getDirectoryContents(string $path): iterable
93
    {
94 2
        $directory = new DirectoryIterator($path);
95 2
        $items     = [];
96 2
        foreach ($directory as $item) {
97 2
            if (! $item->isDot()) {
98 2
                $items[] = clone $item;
99
            }
100
        }
101 2
        return $items;
102
    }
103
104 1
    public function getEventDispatcher(): EventDispatcherInterface
105
    {
106 1
        return $this->eventDispatcher;
107
    }
108
}
109