Vtiger_Loader   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Test Coverage

Coverage 84.71%

Importance

Changes 0
Metric Value
wmc 33
eloc 88
dl 0
loc 208
ccs 72
cts 85
cp 0.8471
rs 9.76
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A resolveNameToPath() 0 6 3
A includePath() 0 13 2
A autoLoad() 0 20 5
B getComponentClassName() 0 42 9
B getRealPathFile() 0 19 7
A resolveRelativePath() 0 12 3
A includeOnce() 0 23 4
1
<?php
2
/* +**********************************************************************************
3
 * The contents of this file are subject to the vtiger CRM Public License Version 1.1
4
 * ("License"); You may not use this file except in compliance with the License
5
 * The Original Code is:  vtiger CRM Open Source
6
 * The Initial Developer of the Original Code is vtiger.
7
 * Portions created by vtiger are Copyright (C) vtiger.
8
 * All Rights Reserved.
9
 * Contributor(s): YetiForce S.A.
10
 * ********************************************************************************** */
11
12
class Vtiger_Loader
13
{
14
	protected static $includeCache = [];
15
	protected static $includePathCache = [];
16
	protected static $componentClassCache = [];
17
	protected static $loaderDirs = [
18
		'custom.modules.',
19
		'modules.',
20
	];
21
22
	/**
23
	 * Static function to resolve the qualified php filename to absolute path.
24
	 *
25
	 * @param string $qualifiedName
26
	 * @param mixed  $fileExtension
27 111
	 *
28
	 * @return string Absolute File Name
29 111
	 */
30 111
	public static function resolveNameToPath($qualifiedName, $fileExtension = 'php')
31 111
	{
32
		if ($file = self::resolveRelativePath($qualifiedName, $fileExtension)) {
33
			$file = ROOT_DIRECTORY . DIRECTORY_SEPARATOR . ('php' !== $fileExtension ? 'public_html' . DIRECTORY_SEPARATOR : '') . $file;
34 111
		}
35 111
		return $file;
36 1
	}
37
38
	/**
39 111
	 * Static function to resolve the qualified php filename to relative path.
40 4
	 *
41 4
	 * @param string $qualifiedName
42
	 * @param string $fileExtension
43 108
	 *
44 108
	 * @return string
45
	 */
46 111
	public static function resolveRelativePath(string $qualifiedName, string $fileExtension = 'php'): string
47
	{
48
		$allowedExtensions = ['php', 'js', 'css', 'less'];
49
		$file = '';
50
		if (\in_array($fileExtension, $allowedExtensions)) {
51
			if (0 === strpos($qualifiedName, '~')) {
52
				$file = str_replace('~', '', $qualifiedName);
53
			} else {
54
				$file = str_replace('.', DIRECTORY_SEPARATOR, $qualifiedName) . '.' . $fileExtension;
55
			}
56 4
		}
57
		return $file;
58 4
	}
59 1
60
	/**
61
	 * Returns canonicalized absolute pathname for css/js files.
62 4
	 *
63
	 * @param string $filePath
64 4
	 * @param string $fileExtension
65
	 * @param array  $layoutPaths
66
	 *
67
	 * @return string
68
	 */
69 4
	public static function getRealPathFile(string $filePath, string $fileExtension, array $layoutPaths): string
70
	{
71 4
		$realPath = '';
72
		$checkMin = \vtlib\Functions::getMinimizationOptions($fileExtension);
73 4
		foreach ($layoutPaths as $layoutPath) {
74
			$realPaths = [];
75 4
			$completeFilePath = ROOT_DIRECTORY . DIRECTORY_SEPARATOR . 'public_html' . DIRECTORY_SEPARATOR . $layoutPath . self::resolveRelativePath($filePath, $fileExtension);
76 4
			if ($checkMin && false === strpos($completeFilePath, '.min.')) {
77
				$realPaths[] = substr($completeFilePath, 0, -(\strlen($fileExtension) + 1)) . ".min.{$fileExtension}";
78 4
			}
79
			$realPaths[] = $completeFilePath;
80
			foreach ($realPaths as $path) {
81
				if ($path && is_file($path)) {
82
					$realPath = $path;
83
					break 2;
84
				}
85
			}
86
		}
87
		return $realPath;
88
	}
89
90
	/**
91
	 * Function to include a given php file through qualified file name.
92
	 *
93
	 * @param string $qualifiedName
94
	 *
95
	 * @return bool
96
	 */
97
	public static function includeOnce($qualifiedName)
98
	{
99
		if (isset(self::$includeCache[$qualifiedName])) {
100
			return true;
101
		}
102
103
		$file = self::resolveNameToPath($qualifiedName);
104
105
		if (!file_exists($file)) {
106
			return false;
107 106
		}
108
109
		// Check file inclusion before including it
110 106
		\vtlib\Deprecated::checkFileAccessForInclusion($file);
111
112 106
		$status = include_once $file;
113
114
		$success = (0 !== $status);
115 106
116
		if ($success) {
117 106
			self::$includeCache[$qualifiedName] = $file;
118 14
		}
119 14
		return $success;
120 14
	}
121 14
122 14
	public static function includePath($qualifiedName)
123 14
	{
124 14
		// Already included?
125 14
		if (isset(self::$includePathCache[$qualifiedName])) {
126 14
			return true;
127
		}
128 14
129 14
		$path = realpath(self::resolveNameToPath($qualifiedName));
130
		self::$includePathCache[$qualifiedName] = $path;
131
132
		set_include_path($path . PATH_SEPARATOR . get_include_path());
133 106
134
		return true;
135 106
	}
136 106
137 106
	/**
138 54
	 * Function to get the class name of a given Component, of given Type, for a given Module.
139
	 *
140
	 * @param string $componentType
141
	 * @param string $componentName
142 106
	 * @param string $moduleName
143 14
	 * @param mixed  $throwException
144 14
	 *
145 14
	 * @throws \App\Exceptions\AppException
146
	 *
147
	 * @return string Required Class Name
148
	 */
149
	public static function getComponentClassName($componentType, $componentName, $moduleName = 'Vtiger', $throwException = true)
150
	{
151 106
		$cacheKey = "$componentType|$componentName|$moduleName";
152 14
		if (isset(self::$componentClassCache[$cacheKey])) {
153 14
			return self::$componentClassCache[$cacheKey];
154 14
		}
155
		// Change component type from view to views, action to actions to navigate to the right path.
156
		$componentTypeDirectory = strtolower($componentType) . 's';
157
		// Change the Module directory & class, along with intermediate fall back directory and class, if module names has submodule as well
158
		if (false !== strpos($moduleName, ':')) {
159
			$load = [
160 106
				str_replace(':', '_', $moduleName) => str_replace(':', '.', $moduleName),
161 106
			];
162 106
			$moduleHierarchyParts = explode(':', $moduleName);
163 86
			$actualModule = $moduleHierarchyParts[\count($moduleHierarchyParts) - 1];
164
			if ('Users' !== $actualModule) {
165
				$baseModule = $moduleHierarchyParts[0];
166
				if ('Settings' === $baseModule) {
167 1
					$baseModule = 'Settings:Vtiger';
168
				}
169
				$load[str_replace(':', '_', $baseModule)] = str_replace(':', '.', $baseModule);
170
			}
171 1
			$load[$actualModule] = $actualModule;
172
			$load['Vtiger'] = 'Vtiger';
173
		} else {
174
			$load = [
175
				$moduleName => $moduleName,
176
				'Vtiger' => 'Vtiger',
177
			];
178
		}
179
		foreach ($load as $classPath => $classDir) {
180
			foreach (self::$loaderDirs as $dir) {
181 14
				if (file_exists(self::resolveNameToPath("$dir$classDir.$componentTypeDirectory.$componentName"))) {
182
					return self::$componentClassCache[$cacheKey] = "{$classPath}_{$componentName}_{$componentType}";
183 14
				}
184 14
			}
185 14
		}
186 4
		if ($throwException) {
187
			\App\Log::error("Error Vtiger_Loader::getComponentClassName($componentType, $componentName, $moduleName): Handler not found");
188 4
			throw new \App\Exceptions\AppException('LBL_HANDLER_NOT_FOUND');
189 4
		}
190
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
191
	}
192 4
193 4
	/**
194 4
	 * Function to auto load the required class files matching the directory pattern modules/xyz/types/Abc.php for class xyz_Abc_Type.
195
	 *
196 4
	 * @param string $className
197 3
	 *
198
	 * @return bool
199
	 */
200
	public static function autoLoad($className)
201 13
	{
202
		$parts = explode('_', $className);
203
		$noOfParts = \count($parts);
204
		if ($noOfParts > 2) {
205
			foreach (self::$loaderDirs as $filePath) {
206
				// Append modules and sub modules names to the path
207
				for ($i = 0; $i < ($noOfParts - 2); ++$i) {
208
					$filePath .= $parts[$i] . '.';
209
				}
210
211
				$fileName = $parts[$noOfParts - 2];
212
				$fileComponentName = strtolower($parts[$noOfParts - 1]) . 's';
213
				$filePath .= $fileComponentName . '.' . $fileName;
214
				if (file_exists(self::resolveNameToPath($filePath))) {
215
					return self::includeOnce($filePath);
216
				}
217
			}
218
		}
219
		return false;
220
	}
221
}
222
223
spl_autoload_register('Vtiger_Loader::autoLoad');
224