Completed
Push — feature-20rc1 ( 008ae2 )
by Rob
16:55
created

FileSystemLocator   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 2
dl 0
loc 125
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A locate() 0 14 3
A generateAbsolutePath() 0 8 2
A locateUsingRootPathsSearch() 0 10 3
A locateUsingRootPlaceholder() 0 14 4
A sanitizeRootPath() 0 8 3
A sanitizeAbsolutePath() 0 11 3
1
<?php
2
3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Liip\ImagineBundle\Imagine\Data\Loader\Locator;
13
14
use Liip\ImagineBundle\Exception\File\Loader\NotLoadableException;
15
use Liip\ImagineBundle\Exception\InvalidArgumentException;
16
17
class FileSystemLocator implements LocatorInterface
18
{
19
    /**
20
     * @var string[]
21
     */
22
    private $roots = [];
23
24
    /**
25
     * @param string[] $roots
26
     */
27
    public function __construct(array $roots = [])
28
    {
29
        $this->roots = array_map(function (string $root): string {
30
            return $this->sanitizeRootPath($root);
31
        }, $roots);
32
    }
33
34
    /**
35
     * @param string $path
36
     *
37
     * @throws NotLoadableException
38
     *
39
     * @return string
40
     */
41
    public function locate(string $path): string
42
    {
43
        if (null !== $absolute = $this->locateUsingRootPlaceholder($path)) {
44
            return $this->sanitizeAbsolutePath($absolute);
45
        }
46
47
        if (null !== $absolute = $this->locateUsingRootPathsSearch($path)) {
48
            return $this->sanitizeAbsolutePath($absolute);
49
        }
50
51
        throw new NotLoadableException(
52
            'Source image not resolvable "%s" in root path(s) "%s"', $path, implode(':', $this->roots)
53
        );
54
    }
55
56
    /**
57
     * @param string $root
58
     * @param string $path
59
     *
60
     * @return string|null
61
     */
62
    protected function generateAbsolutePath(string $root, string $path): ?string
63
    {
64
        if (false !== $absolute = realpath($root.DIRECTORY_SEPARATOR.$path)) {
65
            return $absolute;
66
        }
67
68
        return null;
69
    }
70
71
    /**
72
     * @param string $path
73
     *
74
     * @return string|null
75
     */
76
    private function locateUsingRootPathsSearch(string $path): ?string
77
    {
78
        foreach ($this->roots as $root) {
79
            if (null !== $absolute = $this->generateAbsolutePath($root, $path)) {
80
                return $absolute;
81
            }
82
        }
83
84
        return null;
85
    }
86
87
    /**
88
     * @param string $path
89
     *
90
     * @return string|null
91
     */
92
    private function locateUsingRootPlaceholder(string $path): ?string
93
    {
94
        if (0 !== mb_strpos($path, '@') || 1 !== preg_match('{^@(?<name>[^:]+):(?<path>.+)$}', $path, $match)) {
95
            return null;
96
        }
97
98
        if (isset($this->roots[$match['name']])) {
99
            return $this->generateAbsolutePath($this->roots[$match['name']], $match['path']);
100
        }
101
102
        throw new NotLoadableException(
103
            'Invalid root placeholder "@%s" for path "%s"', $match['name'], $match['path']
104
        );
105
    }
106
107
    /**
108
     * @param string $path
109
     *
110
     * @throws InvalidArgumentException
111
     *
112
     * @return string
113
     */
114
    private function sanitizeRootPath(string $path): string
115
    {
116
        if (!empty($path) && false !== $real = realpath($path)) {
117
            return $real;
118
        }
119
120
        throw new InvalidArgumentException('Root image path not resolvable "%s"', $path);
121
    }
122
123
    /**
124
     * @param string $path
125
     *
126
     * @throws NotLoadableException
127
     *
128
     * @return string
129
     */
130
    private function sanitizeAbsolutePath(string $path): string
131
    {
132
        foreach ($this->roots as $root) {
133
            if (0 === mb_strpos($path, $root)) {
134
                return $path;
135
            }
136
        }
137
138
        throw new NotLoadableException(sprintf('Source image invalid "%s" as it is outside of the defined root path(s) "%s"',
139
            $path, implode(':', $this->roots)));
140
    }
141
}
142