RecursiveParentExceptionResolver   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
eloc 35
dl 0
loc 84
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 8
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 2
    public function __construct(protected EventDispatcherInterface $eventDispatcher)
24
    {
25 2
        $this->eventDispatcher = $eventDispatcher;
26 2
        $this->registerDefaultListeners();
27
    }
28
29
    /**
30
     * Register default listeners
31
     */
32 1
    private function registerDefaultListeners(): void
33
    {
34 1
        $this->eventDispatcher->addSubscriber(new GitDirectoryListener());
35 1
        $this->eventDispatcher->addSubscriber(new RootDirectoryListener());
36 1
        $this->eventDispatcher->addSubscriber(new ExceptionDirListener());
37
    }
38
39
    /**
40
     * Returns an array containing arrays with parent exception folder and its namespace
41
     */
42 2
    public function resolveExceptionDirs(string $path): ?array
43
    {
44 2
        $exceptionDirArray = null;
45 2
        $eventDispatcher   = $this->eventDispatcher;
46 2
        $loopedPaths       = [basename($path)];
47 2
        $path              = dirname($path);
48
49
        // loop as long a break listener doesn't stop propagation or we have empty directories
50
        // we iterate through directories up
51
        do {
52 2
            $directory = $this->getDirectoryContents($path);
53
54
            // loop over files/directories and check if the listener can find an exception directory
55 2
            foreach ($directory as $item) {
56 2
                $exceptionDirectoryEvent = new FileEvent($item);
57 2
                $eventDispatcher->dispatch($exceptionDirectoryEvent, 'dir.loop');
58
                //break early, cuz one exception directory can only appear once
59 2
                if ($exceptionDirectoryEvent->isPropagationStopped()) {
60 1
                    $exceptionDirArray[] = $exceptionDirectoryEvent->getParentExceptionDir();
61 1
                    break;
62
                }
63
            }
64
65
            // check for listeners that check if the path iteration loop should be stopped
66 2
            foreach ($directory as $item) {
67 2
                $breakEvent = new FileEvent($item);
68 2
                $eventDispatcher->dispatch($breakEvent, 'file.break');
69 2
                if (true === $breakEvent->isPropagationStopped()) {
70 1
                    break 2;
71
                }
72
            }
73
74 1
            $path          = dirname($path) !== static::VFSSTREAM_PREFIX ? dirname($path) : static::VFSSTREAM_URL;
75 1
            $loopedPaths[] = basename($path);
76
            //break early cuz DirectoryIterator can't handle vfs root folder
77 1
        } while (0 === count($directory) || $path !== static::VFSSTREAM_URL);
78
79 2
        return $exceptionDirArray;
80
    }
81
82
    /**
83
     * Get directory contents without dot files.
84
     *
85
     * @return array<int, DirectoryIterator>
86
     */
87 2
    private function getDirectoryContents(string $path): iterable
88
    {
89 2
        $directory = new DirectoryIterator($path);
90 2
        $items     = [];
91 2
        foreach ($directory as $item) {
92 2
            if (! $item->isDot()) {
93 2
                $items[] = clone $item;
94
            }
95
        }
96 2
        return $items;
97
    }
98
99 1
    public function getEventDispatcher(): EventDispatcherInterface
100
    {
101 1
        return $this->eventDispatcher;
102
    }
103
}
104