AppIterator::getMetaCollection()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 1
dl 0
loc 18
ccs 11
cts 11
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource;
6
7
use BEAR\Resource\Exception\ResourceDirException;
8
use Iterator;
9
use Override;
10
use RecursiveDirectoryIterator;
11
use RecursiveIteratorIterator;
12
use ReflectionClass;
13
use SplFileInfo;
14
15
use function array_diff_key;
16
use function array_key_exists;
17
use function array_keys;
18
use function array_values;
19
use function assert;
20
use function class_exists;
21
use function file_exists;
22
use function get_declared_classes;
23
use function str_contains;
24
25
/**
26
 * @psalm-import-type ResourceClassName from Types
27
 * @implements Iterator<string, Meta>
28
 */
29
final class AppIterator implements Iterator
30
{
31 2
    private int $i = 0;
32
33 2
    /** @var array<string, Meta> */
34 1
    private array $metaCollection = [];
35
36 2
    /** @var list<string> */
0 ignored issues
show
Bug introduced by
The type BEAR\Resource\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37 2
    private array $keys = [];
38 2
39
    /** @throws ResourceDirException */
40 2
    public function __construct(string $resourceDir)
41 2
    {
42 2
        if (! file_exists($resourceDir)) {
43
            throw new ResourceDirException($resourceDir);
44
        }
45
46
        $iterator = new RecursiveIteratorIterator(
47 1
            new RecursiveDirectoryIterator($resourceDir),
48
            RecursiveIteratorIterator::SELF_FIRST,
49 1
        );
50
        $this->metaCollection = $this->getMetaCollection($iterator);
51
        $this->keys = array_keys($this->metaCollection);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_keys($this->metaCollection) of type array is incompatible with the declared type BEAR\Resource\list of property $keys.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
52
    }
53
54
    /**
55 1
     * {@inheritDoc}
56
     */
57 1
    #[Override]
58 1
    public function current(): Meta
59
    {
60
        return $this->metaCollection[$this->keys[$this->i]];
61
    }
62
63 1
    /**
64
     * {@inheritDoc}
65 1
     */
66
    #[Override]
67
    public function next(): void
68
    {
69
        ++$this->i;
70
    }
71 1
72
    /**
73 1
     * {@inheritDoc}
74
     */
75
    #[Override]
76
    public function key(): string
77
    {
78
        return $this->keys[$this->i]; // @codeCoverageIgnore
79 1
    }
80
81 1
    /**
82 1
     * {@inheritDoc}
83
     */
84 2
    #[Override]
85
    public function valid(): bool
86 2
    {
87 2
        return array_key_exists($this->i, $this->keys);
88
    }
89 2
90 2
    /**
91
     * {@inheritDoc}
92 2
     */
93 2
    #[Override]
94 1
    public function rewind(): void
95
    {
96 1
        $this->i = 0;
97 1
    }
98
99
    /**
100 2
     * @param Iterator<SplFileInfo> $iterator
101
     *
102
     * @return array<string, Meta>
103 2
     */
104
    private function getMetaCollection(Iterator $iterator): array
105 2
    {
106 2
        $metaCollection = [];
107 2
        foreach ($iterator as $item) {
108
            if ($this->isNotPhp($item)) {
109 2
                continue;
110
            }
111
112 2
            $resourceClass = $this->getResourceClassName($item);
113
            if ($resourceClass === '' || ! class_exists($resourceClass)) {
114 2
                continue;
115 2
            }
116
117 2
            $meta = new Meta($resourceClass);
118 2
            $metaCollection[$meta->uri] = $meta;
119 2
        }
120
121 2
        return $metaCollection;
122
    }
123
124 2
    private function isNotPhp(SplFileInfo $item): bool
125
    {
126 2
        $isPhp = $item->isFile()
127 1
            && $item->getExtension() === 'php'
128 1
            && (! str_contains($item->getBasename('.php'), '.'));
129 1
130
        return ! $isPhp;
131
    }
132
133 1
    /** @return ResourceClassName|'' */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ResourceClassName|'' at position 2 could not be parsed: Unknown type name '''' at position 2 in ResourceClassName|''.
Loading history...
134
    private function getResourceClassName(SplFileInfo $file): string
135
    {
136
        $pathName = $file->getPathname();
137
        $declaredClasses = get_declared_classes();
138
        assert(file_exists($pathName));
139
        include_once $pathName;
140
        $newClasses = array_values(array_diff_key(get_declared_classes(), $declaredClasses));
141
142
        return $this->getName($newClasses);
143
    }
144
145
    /**
146
     * @param array<class-string> $newClasses
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
147
     *
148
     * @return ResourceClassName|''
0 ignored issues
show
Documentation Bug introduced by
The doc comment ResourceClassName|'' at position 2 could not be parsed: Unknown type name '''' at position 2 in ResourceClassName|''.
Loading history...
149
     */
150
    private function getName(array $newClasses): string
151
    {
152
        foreach ($newClasses as $newClass) {
153
            $parent = (new ReflectionClass($newClass))->getParentClass();
154
            if ($parent && $parent->name === ResourceObject::class) {
155
                /** @var ResourceClassName $newClass */
156
                return $newClass;
157
            }
158
        }
159
160
        return '';
161
    }
162
}
163