ElggPluginManifest::normalizeDep()   F
last analyzed

Complexity

Conditions 26
Paths 161

Size

Total Lines 87
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 40.6338

Importance

Changes 0
Metric Value
cc 26
eloc 61
nc 161
nop 1
dl 0
loc 87
ccs 44
cts 61
cp 0.7213
crap 40.6338
rs 3.6583
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Parses Elgg manifest.xml files.
4
 *
5
 * Normalizes the values from the \ElggManifestParser object.
6
 *
7
 * This requires an \ElggPluginManifestParser class implementation
8
 * as $this->parser.
9
 *
10
 * To add new parser versions, name them \ElggPluginManifestParserXX
11
 * where XX is the version specified in the top-level <plugin_manifest>
12
 * tag's XML namespace.
13
 *
14
 * @package    Elgg.Core
15
 * @subpackage Plugins
16
 * @since      1.8
17
 */
18
class ElggPluginManifest {
19
20
	/**
21
	 * The parser object
22
	 *
23
	 * @var \ElggPluginManifestParser18
24
	 */
25
	protected $parser;
26
27
	/**
28
	 * The root for plugin manifest namespaces.
29
	 * This is in the format http://www.elgg.org/plugin_manifest/<version>
30
	 */
31
	protected $namespace_root = 'http://www.elgg.org/plugin_manifest/';
32
33
	/**
34
	 * The expected structure of a plugins requires element
35
	 */
36
	private $depsStructPlugin = [
37
		'type' => '',
38
		'name' => '',
39
		'version' => '',
40
		'comparison' => 'ge'
41
	];
42
43
	/**
44
	 * The expected structure of a priority element
45
	 */
46
	private $depsStructPriority = [
47
		'type' => '',
48
		'priority' => '',
49
		'plugin' => ''
50
	];
51
52
	/*
53
	 * The expected structure of elgg_release requires element
54
	 */
55
	private $depsStructElgg = [
56
		'type' => '',
57
		'version' => '',
58
		'comparison' => 'ge'
59
	];
60
61
	/**
62
	 * The expected structure of a requires php_version dependency element
63
	 */
64
	private $depsStructPhpVersion = [
65
		'type' => '',
66
		'version' => '',
67
		'comparison' => 'ge'
68
	];
69
70
	/**
71
	 * The expected structure of a requires php_ini dependency element
72
	 */
73
	private $depsStructPhpIni = [
74
		'type' => '',
75
		'name' => '',
76
		'value' => '',
77
		'comparison' => '='
78
	];
79
80
	/**
81
	 * The expected structure of a requires php_extension dependency element
82
	 */
83
	private $depsStructPhpExtension = [
84
		'type' => '',
85
		'name' => '',
86
		'version' => '',
87
		'comparison' => '='
88
	];
89
90
	/**
91
	 * The expected structure of a conflicts depedency element
92
	 */
93
	private $depsConflictsStruct = [
94
		'type' => '',
95
		'name' => '',
96
		'version' => '',
97
		'comparison' => '='
98
	];
99
100
	/**
101
	 * The expected structure of a provides dependency element.
102
	 */
103
	private $depsProvidesStruct = [
104
		'type' => '',
105
		'name' => '',
106
		'version' => ''
107
	];
108
109
	/**
110
	 * The expected structure of a screenshot element
111
	 */
112
	private $screenshotStruct = [
113
		'description' => '',
114
		'path' => ''
115
	];
116
117
	/**
118
	 * The expected structure of a contributor element
119
	 */
120
	private $contributorStruct = [
121
		'name' => '',
122
		'email' => '',
123
		'website' => '',
124
		'username' => '',
125
		'description' => '',
126
	];
127
128
	/**
129
	 * The API version of the manifest.
130
	 *
131
	 * @var string
132
	 */
133
	protected $apiVersion;
134
135
	/**
136
	 * The optional plugin id this manifest belongs to.
137
	 *
138
	 * @var string
139
	 */
140
	protected $pluginID;
141
142
	/**
143
	 * Load a manifest file, XmlElement or path to manifest.xml file
144
	 *
145
	 * @param mixed  $manifest  A string, XmlElement, or path of a manifest file.
146
	 * @param string $plugin_id Optional ID of the owning plugin. Used to
147
	 *                          fill in some values automatically.
148
	 *
149
	 * @throws PluginException
150
	 */
151 368
	public function __construct($manifest, $plugin_id = null) {
152 368
		if ($plugin_id) {
153 368
			$this->pluginID = $plugin_id;
154
		}
155
156
		// see if we need to construct the xml object.
157 368
		if ($manifest instanceof \ElggXMLElement) {
158 1
			$manifest_obj = $manifest;
159
		} else {
160 368
			$raw_xml = '';
161 368
			if (substr(trim($manifest), 0, 1) == '<') {
162
				// this is a string
163 1
				$raw_xml = $manifest;
164 368
			} elseif (is_file($manifest)) {
165
				// this is a file
166 368
				$raw_xml = file_get_contents($manifest);
167
			}
168 368
			if ($raw_xml) {
169 368
				$manifest_obj = new \ElggXMLElement($raw_xml);
170
			} else {
171
				$manifest_obj = null;
172
			}
173
		}
174
175 368
		if (!$manifest_obj) {
176
			$msg = elgg_echo('PluginException:InvalidManifest', [$this->getPluginID()]);
177
			throw PluginException::factory('InvalidManifest', null, $msg);
178
		}
179
180
		// set manifest api version
181 368
		if (isset($manifest_obj->attributes['xmlns'])) {
182 368
			$namespace = $manifest_obj->attributes['xmlns'];
183 368
			$version = str_replace($this->namespace_root, '', $namespace);
184
		} else {
185
			$version = '1.7';
186
		}
187
188 368
		$this->apiVersion = $version;
189
190 368
		$parser_class_name = '\ElggPluginManifestParser' . str_replace('.', '', $this->apiVersion);
191
192
		// @todo currently the autoloader freaks out if a class doesn't exist.
193
		try {
194 368
			$class_exists = class_exists($parser_class_name);
195
		} catch (Exception $e) {
196
			$class_exists = false;
197
		}
198
199 368
		if ($class_exists) {
200 368
			$this->parser = new $parser_class_name($manifest_obj, $this);
201
		} else {
202
			$msg = elgg_echo('PluginException:NoAvailableParser', [$this->apiVersion, $this->getPluginID()]);
203
			throw PluginException::factory('NoAvailableParser', null, $msg);
204
		}
205
206 368
		if (!$this->parser->parse()) {
207
			$msg = elgg_echo('PluginException:ParserError', [$this->apiVersion, $this->getPluginID()]);
208
			throw PluginException::factory('ParseError', null, $msg);
209
		}
210 368
	}
211
212
	/**
213
	 * Returns the API version in use.
214
	 *
215
	 * @return string
216
	 */
217 45
	public function getApiVersion() {
218 45
		return $this->apiVersion;
219
	}
220
221
	/**
222
	 * Returns the plugin ID.
223
	 *
224
	 * @return string
225
	 */
226 74
	public function getPluginID() {
227 74
		if ($this->pluginID) {
228 74
			return $this->pluginID;
229
		} else {
230
			return elgg_echo('unknown');
231
		}
232
	}
233
234
	/**
235
	 * Returns the manifest array.
236
	 *
237
	 * Used for backward compatibility.  Specific
238
	 * methods should be called instead.
239
	 *
240
	 * @return array
241
	 */
242 1
	public function getManifest() {
243 1
		return $this->parser->getManifest();
244
	}
245
246
	/***************************************
247
	 * Parsed and Normalized Manifest Data *
248
	 ***************************************/
249
250
	/**
251
	 * Returns the plugin name
252
	 *
253
	 * @return string
254
	 */
255 32
	public function getName() {
256 32
		$name = $this->parser->getAttribute('name');
257
258 32
		if (!$name && $this->pluginID) {
259
			$name = ucwords(str_replace('_', ' ', $this->pluginID));
260
		}
261
262 32
		return $name;
263
	}
264
265
	/**
266
	 * Return the plugin ID required by the author. If getPluginID() does
267
	 * not match this, the plugin should not be started.
268
	 *
269
	 * @return string empty string if not empty/not defined
270
	 */
271 75
	public function getID() {
272 75
		return trim((string) $this->parser->getAttribute('id'));
273
	}
274
275
276
	/**
277
	 * Return the description
278
	 *
279
	 * @return string
280
	 */
281 31
	public function getDescription() {
282 31
		return (string) $this->parser->getAttribute('description');
283
	}
284
285
	/**
286
	 * Return the short description
287
	 *
288
	 * @return string
289
	 */
290 1
	public function getBlurb() {
291 1
		$blurb = $this->parser->getAttribute('blurb');
292
293 1
		if (!$blurb) {
294
			$blurb = elgg_get_excerpt($this->getDescription());
295
		}
296
297 1
		return $blurb;
298
	}
299
300
	/**
301
	 * Returns the license
302
	 *
303
	 * @return string
304
	 */
305 31
	public function getLicense() {
306
		// license vs licence.  Use license.
307 31
		$en_us = $this->parser->getAttribute('license');
308
		
309 31
		return (string) ($en_us ?: $this->parser->getAttribute('licence'));
310
	}
311
312
	/**
313
	 * Returns the repository url
314
	 *
315
	 * @return string
316
	 */
317 1
	public function getRepositoryURL() {
318 1
		return (string) $this->parser->getAttribute('repository');
319
	}
320
321
	/**
322
	 * Returns the bug tracker page
323
	 *
324
	 * @return string
325
	 */
326 1
	public function getBugTrackerURL() {
327 1
		return (string) $this->parser->getAttribute('bugtracker');
328
	}
329
330
	/**
331
	 * Returns the donations page
332
	 *
333
	 * @return string
334
	 */
335 1
	public function getDonationsPageURL() {
336 1
		return (string) $this->parser->getAttribute('donations');
337
	}
338
339
	/**
340
	 * Returns the version of the plugin.
341
	 *
342
	 * @return mixed
343
	 */
344 45
	public function getVersion() {
345 45
		return $this->parser->getAttribute('version');
346
	}
347
348
	/**
349
	 * Returns the plugin author.
350
	 *
351
	 * @return string
352
	 */
353 31
	public function getAuthor() {
354 31
		return (string) $this->parser->getAttribute('author');
355
	}
356
357
	/**
358
	 * Return the copyright
359
	 *
360
	 * @return string
361
	 */
362 1
	public function getCopyright() {
363 1
		return (string) $this->parser->getAttribute('copyright');
364
	}
365
366
	/**
367
	 * Return the website
368
	 *
369
	 * @return string
370
	 */
371 1
	public function getWebsite() {
372 1
		return (string) $this->parser->getAttribute('website');
373
	}
374
375
	/**
376
	 * Return the categories listed for this plugin
377
	 *
378
	 * @return array
379
	 */
380 31
	public function getCategories() {
381
		$bundled_plugins = [
382 31
			'activity',
383
			'blog',
384
			'bookmarks',
385
			'ckeditor',
386
			'custom_index',
387
			'dashboard',
388
			'developers',
389
			'diagnostics',
390
			'discussions',
391
			'embed',
392
			'externalpages',
393
			'file',
394
			'friends',
395
			'friends_collections',
396
			'garbagecollector',
397
			'groups',
398
			'invitefriends',
399
			'likes',
400
			'login_as',
401
			'members',
402
			'messageboard',
403
			'messages',
404
			'notifications',
405
			'pages',
406
			'profile',
407
			'reportedcontent',
408
			'search',
409
			'site_notifications',
410
			'system_log',
411
			'tagcloud',
412
			'thewire',
413
			'uservalidationbyemail',
414
			'web_services',
415
		];
416
417 31
		$cats = $this->parser->getAttribute('category');
418
419 31
		if (!$cats) {
420
			$cats = [];
421
		}
422
423 31
		if (in_array('bundled', $cats) && !in_array($this->getPluginID(), $bundled_plugins)) {
424
			unset($cats[array_search('bundled', $cats)]);
425
		}
426
427 31
		return $cats;
428
	}
429
430
	/**
431
	 * Return the screenshots listed.
432
	 *
433
	 * @return array
434
	 */
435 1
	public function getScreenshots() {
436 1
		$ss = $this->parser->getAttribute('screenshot');
437
438 1
		if (!$ss) {
439
			$ss = [];
440
		}
441
442 1
		$normalized = [];
443 1
		foreach ($ss as $s) {
444 1
			$normalized[] = $this->buildStruct($this->screenshotStruct, $s);
445
		}
446
447 1
		return $normalized;
448
	}
449
450
	/**
451
	 * Return the contributors listed.
452
	 *
453
	 * @return array
454
	 */
455 1
	public function getContributors() {
456 1
		$ss = $this->parser->getAttribute('contributor');
457
458 1
		if (!$ss) {
459
			$ss = [];
460
		}
461
462 1
		$normalized = [];
463 1
		foreach ($ss as $s) {
464 1
			$normalized[] = $this->buildStruct($this->contributorStruct, $s);
465
		}
466
467 1
		return $normalized;
468
	}
469
470
	/**
471
	 * Return the list of provides by this plugin.
472
	 *
473
	 * @return array
474
	 */
475 45
	public function getProvides() {
476
		// normalize for 1.7
477 45
		if ($this->getApiVersion() < 1.8) {
478
			$provides = [];
479
		} else {
480 45
			$provides = $this->parser->getAttribute('provides');
481
		}
482
483 45
		if (!$provides) {
484 17
			$provides = [];
485
		}
486
487
		// always provide ourself if we can
488 45
		if ($this->pluginID) {
489 45
			$provides[] = [
490 45
				'type' => 'plugin',
491 45
				'name' => $this->getPluginID(),
492 45
				'version' => $this->getVersion()
493
			];
494
		}
495
496 45
		$normalized = [];
497 45
		foreach ($provides as $provide) {
498 45
			$normalized[] = $this->buildStruct($this->depsProvidesStruct, $provide);
499
		}
500
501 45
		return $normalized;
502
	}
503
504
	/**
505
	 * Returns the dependencies listed.
506
	 *
507
	 * @return array
508
	 */
509 193
	public function getRequires() {
510 193
		$reqs = $this->parser->getAttribute('requires');
511
512 193
		if (!$reqs) {
513
			$reqs = [];
514
		}
515
516 193
		$normalized = [];
517 193
		foreach ($reqs as $req) {
518 193
			$normalized[] = $this->normalizeDep($req);
519
		}
520
521 193
		return $normalized;
522
	}
523
524
	/**
525
	 * Returns the suggests elements.
526
	 *
527
	 * @return array
528
	 */
529 1
	public function getSuggests() {
530 1
		$suggests = $this->parser->getAttribute('suggests');
531
532 1
		if (!$suggests) {
533
			$suggests = [];
534
		}
535
536 1
		$normalized = [];
537 1
		foreach ($suggests as $suggest) {
538 1
			$normalized[] = $this->normalizeDep($suggest);
539
		}
540
541 1
		return $normalized;
542
	}
543
544
	/**
545
	 * Normalizes a dependency array using the defined structs.
546
	 * Can be used with either requires or suggests.
547
	 *
548
	 * @param array $dep A dependency array.
549
	 * @return array The normalized deps array.
550
	 */
551 193
	private function normalizeDep($dep) {
552
		
553 193
		$struct = [];
554
		
555 193
		switch ($dep['type']) {
556 193
			case 'elgg_release':
557 193
				$struct = $this->depsStructElgg;
558 193
				break;
559
560 39
			case 'plugin':
561 39
				$struct = $this->depsStructPlugin;
562 39
				break;
563
564 34
			case 'priority':
565 34
				$struct = $this->depsStructPriority;
566 34
				break;
567
568 30
			case 'php_version':
569 30
				$struct = $this->depsStructPhpVersion;
570 30
				break;
571
572 30
			case 'php_extension':
573 30
				$struct = $this->depsStructPhpExtension;
574 30
				break;
575
576 30
			case 'php_ini':
577 30
				$struct = $this->depsStructPhpIni;
578
579
				// also normalize boolean values
580 30
				if (isset($dep['value'])) {
581 30
					switch (strtolower($dep['value'])) {
582 30
						case 'yes':
583 30
						case 'true':
584 30
						case 'on':
585 30
						case 1:
586
							$dep['value'] = 1;
587
							break;
588
589 30
						case 'no':
590 30
						case 'false':
591 30
						case 'off':
592
						case 0:
593
						case '':
594 30
							$dep['value'] = 0;
595 30
							break;
596
					}
597
				}
598 30
				break;
599
			default:
600
				// unrecognized so we just return the raw dependency
601
				return $dep;
602
		}
603
		
604 193
		$normalized_dep = $this->buildStruct($struct, $dep);
605
606
		// normalize comparison operators
607 193
		if (isset($normalized_dep['comparison'])) {
608 193
			switch ($normalized_dep['comparison']) {
609 193
				case '<':
610
					$normalized_dep['comparison'] = 'lt';
611
					break;
612
613 193
				case '<=':
614
					$normalized_dep['comparison'] = 'le';
615
					break;
616
617 193
				case '>':
618
					$normalized_dep['comparison'] = 'gt';
619
					break;
620
621 193
				case '>=':
622
					$normalized_dep['comparison'] = 'ge';
623
					break;
624
625 193
				case '==':
626 193
				case 'eq':
627
					$normalized_dep['comparison'] = '=';
628
					break;
629
630 193
				case '<>':
631 193
				case 'ne':
632
					$normalized_dep['comparison'] = '!=';
633
					break;
634
			}
635
		}
636
637 193
		return $normalized_dep;
638
	}
639
640
	/**
641
	 * Returns the conflicts listed
642
	 *
643
	 * @return array
644
	 */
645 45
	public function getConflicts() {
646
		// normalize for 1.7
647 45
		if ($this->getApiVersion() < 1.8) {
648
			$conflicts = [];
649
		} else {
650 45
			$conflicts = $this->parser->getAttribute('conflicts');
651
		}
652
653 45
		if (!$conflicts) {
654 17
			$conflicts = [];
655
		}
656
657 45
		$normalized = [];
658
659 45
		foreach ($conflicts as $conflict) {
660 36
			$normalized[] = $this->buildStruct($this->depsConflictsStruct, $conflict);
661
		}
662
663 45
		return $normalized;
664
	}
665
666
	/**
667
	 * Should this plugin be activated when Elgg is installed
668
	 *
669
	 *  @return bool
670
	 */
671 1
	public function getActivateOnInstall() {
672 1
		$activate = $this->parser->getAttribute('activate_on_install');
673 1
		switch (strtolower($activate)) {
0 ignored issues
show
Bug introduced by Brett Profitt
It seems like $activate can also be of type false; however, parameter $str of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

673
		switch (strtolower(/** @scrutinizer ignore-type */ $activate)) {
Loading history...
674 1
			case 'yes':
675 1
			case 'true':
676
			case 'on':
677
			case 1:
678 1
				return true;
679
680
			case 'no':
681
			case 'false':
682
			case 'off':
683
			case 0:
684
			case '':
685
				return false;
686
		}
687
	}
688
689
	/**
690
	 * Normalizes an array into the structure specified
691
	 *
692
	 * @param array $struct The struct to normalize $element to.
693
	 * @param array $array  The array
694
	 *
695
	 * @return array
696
	 */
697 193
	protected function buildStruct(array $struct, array $array) {
698 193
		$return = [];
699
700 193
		foreach ($struct as $index => $default) {
701 193
			$return[$index] = elgg_extract($index, $array, $default);
702
		}
703
704 193
		return $return;
705
	}
706
707
	/**
708
	 * Returns a category's friendly name. This can be localized by
709
	 * defining the string 'admin:plugins:category:<category>'. If no
710
	 * localization is found, returns the category with _ and - converted to ' '
711
	 * and then ucwords()'d.
712
	 *
713
	 * @param string $category The category as defined in the manifest.
714
	 * @return string A human-readable category
715
	 */
716
	static public function getFriendlyCategory($category) {
717
		$cat_raw_string = "admin:plugins:category:$category";
718
		if (_elgg_services()->translator->languageKeyExists($cat_raw_string)) {
719
			return elgg_echo($cat_raw_string);
720
		}
721
		
722
		$category = str_replace(['-', '_'], ' ', $category);
723
		return ucwords($category);
724
	}
725
}
726