1: <?php
2: /**
3: * This file is part of the Autarky package.
4: *
5: * (c) Andreas Lutro <anlutro@gmail.com>
6: *
7: * For the full copyright and license information, please view the LICENSE
8: * file that was distributed with this source code.
9: */
10:
11: namespace Autarky\Files;
12:
13: /**
14: * Class that resolves possible paths based on various factors.
15: */
16: class PathResolver
17: {
18: /**
19: * Main paths.
20: *
21: * @var string[]
22: */
23: protected $paths;
24:
25: /**
26: * External paths mounted onto locations on the main path.
27: *
28: * @var string[][]
29: */
30: protected $mounts;
31:
32: /**
33: * Constructor
34: *
35: * @param string|array $pathOrPaths
36: */
37: public function __construct($pathOrPaths = [])
38: {
39: $this->paths = (array) $pathOrPaths;
40: }
41:
42: /**
43: * Add a main path.
44: *
45: * @param string $path
46: */
47: public function addPath($path)
48: {
49: $this->paths[] = $path;
50: }
51:
52: /**
53: * Mount a path onto a location.
54: *
55: * @param string $location
56: * @param string $path
57: */
58: public function mount($location, $path)
59: {
60: $this->mounts[$location][] = $path;
61: }
62:
63: /**
64: * Resolve possible paths for a relative path.
65: *
66: * @param string $path
67: *
68: * @return array
69: */
70: public function resolve($path)
71: {
72: $paths = [];
73:
74: foreach ($this->paths as $configuredPath) {
75: $paths[] = $configuredPath.'/'.$path;
76: }
77:
78: $parts = explode('/', $path);
79:
80: // this doesn't change behaviour but will save some performance
81: if (count($parts) == 1) {
82: return $paths;
83: }
84:
85: $current = '';
86: $mountPaths = [];
87: foreach ($parts as $part) {
88: if ($current) {
89: $current .= '/'.$part;
90: } else {
91: $current = $part;
92: }
93:
94: if (isset($this->mounts[$current])) {
95: foreach ($this->mounts[$current] as $mount) {
96: // relative to mount directory
97: $relativePath = str_replace($current, '', $path);
98: $mountPaths[] = $mount.$relativePath;
99: }
100: }
101: }
102:
103: return array_merge($mountPaths, $paths);
104: }
105:
106: /**
107: * Based on a set of basenames (filename without extension) and a set of
108: * possible extensions, find the files that exist.
109: *
110: * @param string|string[] $basenameOrNames
111: * @param string|string[] $extensionOrExtensions
112: *
113: * @return string[]
114: */
115: public function locate($basenameOrNames, $extensionOrExtensions)
116: {
117: $basenames = (array) $basenameOrNames;
118: $extensions = (array) $extensionOrExtensions;
119:
120: $located = [];
121:
122: foreach ($basenames as $basename) {
123: foreach ($extensions as $ext) {
124: $path = $basename.$ext;
125: if (file_exists($path)) {
126: $located[] = $path;
127: }
128: }
129: }
130:
131: return $located;
132: }
133: }
134: