Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
57 / 57
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
1 / 1
ClassMapper
100.00% covered (success)
100.00%
57 / 57
100.00% covered (success)
100.00%
9 / 9
31
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 addSource
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 getSources
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasSource
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 clearSources
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 generateClassMap
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
8
 getClassMap
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 writeToFile
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 discoverFiles
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
9
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Loader;
15
16/**
17 * Mapper class
18 *
19 * @category   Pop
20 * @package    Pop\Loader
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    3.1.0
25 */
26class ClassMapper
27{
28
29    /**
30     * Source directories
31     * @var array
32     */
33    protected $sources = [];
34
35    /**
36     * Class map
37     * @var array
38     */
39    protected $map = [];
40
41    /**
42     * Files
43     * @var array
44     */
45    protected $files = [];
46
47    /**
48     * Constructor
49     *
50     * Instantiate the class mapper object
51     *
52     * @param  mixed $source
53     */
54    public function __construct($source = null)
55    {
56        if (null !== $source) {
57            $this->addSource($source);
58            $this->generateClassMap();
59        }
60    }
61
62    /**
63     * Add source directory or directories
64     *
65     * @param  mixed $source
66     * @throws Exception
67     * @return ClassMapper
68     */
69    public function addSource($source)
70    {
71        if (!is_array($source)) {
72            $source = [$source];
73        }
74
75        foreach ($source as $src) {
76            if (!file_exists($src)) {
77                throw new Exception('Error: That source folder does not exist.');
78            }
79            if (!$this->hasSource($src)) {
80                $this->sources[] = $src;
81            }
82        }
83
84        return $this;
85    }
86
87    /**
88     * Get sources
89     *
90     * @return array
91     */
92    public function getSources()
93    {
94        return $this->sources;
95    }
96
97    /**
98     * Determine if a source directory has been added
99     *
100     * @param  string  $source
101     * @return boolean
102     */
103    public function hasSource($source)
104    {
105        return in_array($source, $this->sources);
106    }
107
108    /**
109     * Clear sources
110     *
111     * @return ClassMapper
112     */
113    public function clearSources()
114    {
115        $this->sources = [];
116        return $this;
117    }
118
119    /**
120     * Generate a class map
121     *
122     * @return ClassMapper
123     */
124    public function generateClassMap()
125    {
126        $this->discoverFiles();
127
128        foreach ($this->files as $file) {
129            $classMatch        = [];
130            $namespaceMatch    = [];
131            $classFileContents = file_get_contents($file);
132
133            preg_match('/^(abstract|interface|trait|class)(.*)$/m', $classFileContents, $classMatch);
134            preg_match('/^namespace(.*)$/m', $classFileContents, $namespaceMatch);
135
136            if (isset($classMatch[0])) {
137                if (strpos($classMatch[0], 'abstract') !== false) {
138                    $class = str_replace('abstract class ', '', $classMatch[0]);
139                } else if (strpos($classMatch[0], 'interface') !== false) {
140                    $class = str_replace('interface ', '', $classMatch[0]);
141                } else if (strpos($classMatch[0], 'trait') !== false) {
142                    $class = str_replace('trait ', '', $classMatch[0]);
143                } else {
144                    $class = str_replace('class ', '', $classMatch[0]);
145                }
146
147                if (strpos($class, ' ') !== false) {
148                    $class = substr($class, 0, strpos($class, ' '));
149                }
150
151                $class = trim($class);
152                if (isset($namespaceMatch[0])) {
153                    $class = trim(str_replace(';', '', str_replace('namespace ', '', $namespaceMatch[0]))) . '\\' . $class;
154                }
155
156                $this->map[$class] = str_replace('\\', '/', $file);
157            }
158        }
159
160        return $this;
161    }
162
163    /**
164     * Get the class map
165     *
166     * @return array
167     */
168    public function getClassMap()
169    {
170        return $this->map;
171    }
172
173    /**
174     * Write a class map to an output file
175     *
176     * @param  string $output
177     * @return ClassMapper
178     */
179    public function writeToFile($output)
180    {
181        $code = '<?php' . PHP_EOL . PHP_EOL . 'return [';
182
183        $i = 1;
184        foreach ($this->map as $class => $file) {
185            $comma = ($i < count($this->map)) ? ',' : null;
186            $code .= PHP_EOL . '    \'' . $class . '\' => \'' . $file . '\'' . $comma;
187            $i++;
188        }
189
190        $code .= PHP_EOL . '];' . PHP_EOL;
191
192        file_put_contents($output, $code);
193
194        return $this;
195    }
196
197    /**
198     * Discover files from source directory
199     *
200     * @return void
201     */
202    protected function discoverFiles()
203    {
204        foreach ($this->sources as $source) {
205            $objects = new \RecursiveIteratorIterator(
206                new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST
207            );
208            foreach ($objects as $fileInfo) {
209                if (($fileInfo->getFilename() != '.') && ($fileInfo->getFilename() != '..')) {
210                    $f = null;
211                    if (!$fileInfo->isDir()) {
212                        $f = realpath($fileInfo->getPathname());
213                    }
214                    if (($f !== false) && (null !== $f) && (substr(strtolower($f), -4) == '.php')) {
215                        $this->files[] = $f;
216                    }
217                }
218            }
219        }
220    }
221
222}