Completed
Push — master ( 914ff2...7a37f7 )
by Ben
23:32 queued 08:34
created

Resolver::findPrefix()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
c 0
b 0
f 0
rs 9.2
cc 4
eloc 7
nc 3
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Benrowe\Fqcn;
6
7
use Composer\Autoload\ClassLoader;
8
9
/**
10
 * Class Resolver
11
 *
12
 * @package Benrowe\Fqcn
13
 */
14
class Resolver
15
{
16
    /**
17
     * @var ClassLoader
18
     */
19
    private $composer;
20
21
    /**
22
     * @var array
23
     */
24
    private $extensions = ['.php'];
25
26
    /**
27
     * Resolver constructor.
28
     *
29
     * @param ClassLoader $composer
30
     * @param array       $extensions
31
     */
32
    public function __construct(ClassLoader $composer, $extensions = null)
0 ignored issues
show
Unused Code introduced by
The parameter $extensions is not used and could be removed.

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

Loading history...
33
    {
34
        $this->composer = $composer;
35
    }
36
37
    /**
38
     * Resolve a psr4 based namespace to an absolute directory
39
     *
40
     * @param string $namespace
41
     * @return array
42
     * @throws Exception
43
     */
44
    public function resolveDirectory(string $namespace): array
45
    {
46
        $namespace = $this->normalise($namespace);
47
48
        $prefixes = $this->composer->getPrefixesPsr4();
49
        $prefix   = $this->findPrefix($namespace, array_keys($prefixes));
50
        if (!$prefix) {
51
            throw new Exception('Could not find registered psr4 prefix that matches '.$namespace);
52
        }
53
54
        $discovered = [];
55
        foreach ($prefixes[$prefix] as $path) {
56
            $path = $this->findAbsolutePathForPsr4($namespace, $prefix, $path);
57
            // convert the rest of the relative path, from the prefix into a directory slug
58
            if ($path && is_dir($path)) {
59
                $discovered[] =  $path;
60
            }
61
        }
62
        return $discovered;
63
    }
64
65
    /**
66
     * @param string $namespace
67
     * @param array  $prefixes
68
     * @return string
69
     */
70
    private function findPrefix(string $namespace, array $prefixes): string
71
    {
72
        $prefixResult = '';
73
74
        // find the best matching prefix!
75
        foreach ($prefixes as $prefix) {
76
            if (substr($namespace, 0, strlen($prefix)) == $prefix &&
77
                strlen($prefix) > strlen($prefixResult)
78
            ) {
79
                $prefixResult = $prefix;
80
            }
81
        }
82
        return $prefixResult;
83
    }
84
85
    /**
86
     * Convert the supplied namespace string into a standard format
87
     *
88
     * Example:
89
     * Psr4\Prefix\
90
     * Something\
91
     *
92
     * @param string $namespace
93
     * @return string
94
     * @throws Exception
95
     */
96
    private function normalise(string $namespace): string
97
    {
98
99
        $tidy = trim($namespace, '\\');
100
        if (!$tidy) {
101
            throw new Exception('Invalid namespace', 100);
102
        }
103
104
        return $tidy . '\\';
105
    }
106
107
    /**
108
     * Get an absolute path for the provided namespace, based on a existing directory and its psr4 prefix
109
     *
110
     * @param string $namespace
111
     * @param string $psr4Prefix the psr4 prefix
112
     * @param string $psr4Path and it's related path
113
     * @return string the absolute directory path the provided namespace, given the correct prefix and path
114
     *                empty string if path cant be resolved
115
     */
116
    private function findAbsolutePathForPsr4(string $namespace, string $psr4Prefix, string $psr4Path): string
117
    {
118
        $relFqn = trim(substr($namespace, strlen($psr4Prefix)), '\\/');
119
        $path =
120
            $psr4Path .
121
            DIRECTORY_SEPARATOR .
122
            strtr($relFqn, [
123
                '\\' => DIRECTORY_SEPARATOR,
124
                '//' => DIRECTORY_SEPARATOR
125
            ]);
126
        $path = realpath($path);
127
128
        return $path ?: '';
129
    }
130
}
131