Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.62% covered (success)
93.62%
44 / 47
57.14% covered (warning)
57.14%
4 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Version_Loader
93.62% covered (success)
93.62%
44 / 47
57.14% covered (warning)
57.14%
4 / 7
20.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 get_class_map
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_psr4_map
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 find_class_file
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 load_filemap
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 select_newest_file
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 find_psr4_file
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
7
1<?php
2/* HEADER */ // phpcs:ignore
3
4/**
5 * This class loads other classes based on given parameters.
6 */
7class Version_Loader {
8
9    /**
10     * The Version_Selector object.
11     *
12     * @var Version_Selector
13     */
14    private $version_selector;
15
16    /**
17     * A map of available classes and their version and file path.
18     *
19     * @var array
20     */
21    private $classmap;
22
23    /**
24     * A map of PSR-4 namespaces and their version and directory path.
25     *
26     * @var array
27     */
28    private $psr4_map;
29
30    /**
31     * A map of all the files that we should load.
32     *
33     * @var array
34     */
35    private $filemap;
36
37    /**
38     * The constructor.
39     *
40     * @param Version_Selector $version_selector The Version_Selector object.
41     * @param array            $classmap The verioned classmap to load using.
42     * @param array            $psr4_map The versioned PSR-4 map to load using.
43     * @param array            $filemap The versioned filemap to load.
44     */
45    public function __construct( $version_selector, $classmap, $psr4_map, $filemap ) {
46        $this->version_selector = $version_selector;
47        $this->classmap         = $classmap;
48        $this->psr4_map         = $psr4_map;
49        $this->filemap          = $filemap;
50    }
51
52    /**
53     * Fetch the classmap.
54     *
55     * @since 3.1.0
56     * @return array<string, array>
57     */
58    public function get_class_map() {
59        return $this->classmap;
60    }
61
62    /**
63     * Fetch the psr-4 mappings.
64     *
65     * @since 3.1.0
66     * @return array<string, array>
67     */
68    public function get_psr4_map() {
69        return $this->psr4_map;
70    }
71
72    /**
73     * Finds the file path for the given class.
74     *
75     * @param string $class_name The class to find.
76     *
77     * @return string|null $file_path The path to the file if found, null if no class was found.
78     */
79    public function find_class_file( $class_name ) {
80        $data = $this->select_newest_file(
81            $this->classmap[ $class_name ] ?? null,
82            $this->find_psr4_file( $class_name )
83        );
84        if ( ! isset( $data ) ) {
85            return null;
86        }
87
88        return $data['path'];
89    }
90
91    /**
92     * Load all of the files in the filemap.
93     */
94    public function load_filemap() {
95        if ( empty( $this->filemap ) ) {
96            return;
97        }
98
99        foreach ( $this->filemap as $file_identifier => $file_data ) {
100            if ( empty( $GLOBALS['__composer_autoload_files'][ $file_identifier ] ) ) {
101                require_once $file_data['path'];
102
103                $GLOBALS['__composer_autoload_files'][ $file_identifier ] = true;
104            }
105        }
106    }
107
108    /**
109     * Compares different class sources and returns the newest.
110     *
111     * @param array|null $classmap_data The classmap class data.
112     * @param array|null $psr4_data The PSR-4 class data.
113     *
114     * @return array|null $data
115     */
116    private function select_newest_file( $classmap_data, $psr4_data ) {
117        if ( ! isset( $classmap_data ) ) {
118            return $psr4_data;
119        } elseif ( ! isset( $psr4_data ) ) {
120            return $classmap_data;
121        }
122
123        if ( $this->version_selector->is_version_update_required( $classmap_data['version'], $psr4_data['version'] ) ) {
124            return $psr4_data;
125        }
126
127        return $classmap_data;
128    }
129
130    /**
131     * Finds the file for a given class in a PSR-4 namespace.
132     *
133     * @param string $class_name The class to find.
134     *
135     * @return array|null $data The version and path path to the file if found, null otherwise.
136     */
137    private function find_psr4_file( $class_name ) {
138        if ( empty( $this->psr4_map ) ) {
139            return null;
140        }
141
142        // Don't bother with classes that have no namespace.
143        $class_index = strrpos( $class_name, '\\' );
144        if ( ! $class_index ) {
145            return null;
146        }
147        $class_for_path = str_replace( '\\', '/', $class_name );
148
149        // Search for the namespace by iteratively cutting off the last segment until
150        // we find a match. This allows us to check the most-specific namespaces
151        // first as well as minimize the amount of time spent looking.
152        for (
153            $class_namespace = substr( $class_name, 0, $class_index );
154            ! empty( $class_namespace );
155            $class_namespace = substr( $class_namespace, 0, strrpos( $class_namespace, '\\' ) )
156        ) {
157            $namespace = $class_namespace . '\\';
158            if ( ! isset( $this->psr4_map[ $namespace ] ) ) {
159                continue;
160            }
161            $data = $this->psr4_map[ $namespace ];
162
163            foreach ( $data['path'] as $path ) {
164                $path .= '/' . substr( $class_for_path, strlen( $namespace ) ) . '.php';
165                if ( file_exists( $path ) ) {
166                    return array(
167                        'version' => $data['version'],
168                        'path'    => $path,
169                    );
170                }
171            }
172        }
173
174        return null;
175    }
176}