Completed
Push — renovate/mocha-8.x ( 07030e...e8e64c )
by
unknown
28:17 queued 19:09
created

Version_Loader   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

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

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A find_class_file() 0 11 3
A load_filemap() 0 13 4
B find_psr4_file() 0 39 7
A select_newest_file() 0 13 4
1
<?php
2
/* HEADER */ // phpcs:ignore
3
4
/**
5
 * This class loads other classes based on given parameters.
6
 */
7
class 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
	 * Finds the file path for the given class.
54
	 *
55
	 * @param string $class_name The class to find.
56
	 *
57
	 * @return string|null $file_path The path to the file if found, null if no class was found.
58
	 */
59
	public function find_class_file( $class_name ) {
60
		$data = $this->select_newest_file(
61
			isset( $this->classmap[ $class_name ] ) ? $this->classmap[ $class_name ] : null,
62
			$this->find_psr4_file( $class_name )
63
		);
64
		if ( ! isset( $data ) ) {
65
			return null;
66
		}
67
68
		return $data['path'];
69
	}
70
71
	/**
72
	 * Load all of the files in the filemap.
73
	 */
74
	public function load_filemap() {
75
		if ( empty( $this->filemap ) ) {
76
			return;
77
		}
78
79
		foreach ( $this->filemap as $file_identifier => $file_data ) {
80
			if ( empty( $GLOBALS['__composer_autoload_files'][ $file_identifier ] ) ) {
81
				require_once $file_data['path'];
82
83
				$GLOBALS['__composer_autoload_files'][ $file_identifier ] = true;
84
			}
85
		}
86
	}
87
88
	/**
89
	 * Compares different class sources and returns the newest.
90
	 *
91
	 * @param array|null $classmap_data The classmap class data.
92
	 * @param array|null $psr4_data The PSR-4 class data.
93
	 *
94
	 * @return array|null $data
95
	 */
96
	private function select_newest_file( $classmap_data, $psr4_data ) {
97
		if ( ! isset( $classmap_data ) ) {
98
			return $psr4_data;
99
		} elseif ( ! isset( $psr4_data ) ) {
100
			return $classmap_data;
101
		}
102
103
		if ( $this->version_selector->is_version_update_required( $classmap_data['version'], $psr4_data['version'] ) ) {
104
			return $psr4_data;
105
		}
106
107
		return $classmap_data;
108
	}
109
110
	/**
111
	 * Finds the file for a given class in a PSR-4 namespace.
112
	 *
113
	 * @param string $class_name The class to find.
114
	 *
115
	 * @return array|null $data The version and path path to the file if found, null otherwise.
116
	 */
117
	private function find_psr4_file( $class_name ) {
118
		if ( ! isset( $this->psr4_map ) ) {
119
			return null;
120
		}
121
122
		// Don't bother with classes that have no namespace.
123
		$class_index = strrpos( $class_name, '\\' );
124
		if ( ! $class_index ) {
125
			return null;
126
		}
127
		$class_for_path = str_replace( '\\', '/', $class_name );
128
129
		// Search for the namespace by iteratively cutting off the last segment until
130
		// we find a match. This allows us to check the most-specific namespaces
131
		// first as well as minimize the amount of time spent looking.
132
		for (
133
			$class_namespace = substr( $class_name, 0, $class_index );
134
			! empty( $class_namespace );
135
			$class_namespace = substr( $class_namespace, 0, strrpos( $class_namespace, '\\' ) )
136
		) {
137
			$namespace = $class_namespace . '\\';
138
			if ( ! isset( $this->psr4_map[ $namespace ] ) ) {
139
				continue;
140
			}
141
			$data = $this->psr4_map[ $namespace ];
142
143
			foreach ( $data['path'] as $path ) {
144
				$path .= '/' . substr( $class_for_path, strlen( $namespace ) ) . '.php';
145
				if ( file_exists( $path ) ) {
146
					return array(
147
						'version' => $data['version'],
148
						'path'    => $path,
149
					);
150
				}
151
			}
152
		}
153
154
		return null;
155
	}
156
}
157