Issues (971)

extensions/install.php (16 issues)

1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  Model
5
 *
6
 * @copyright   Copyright (C) 2008 - 2021 redWEB.dk. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
use Joomla\Registry\Registry;
11
12
defined('_JEXEC') or die;
13
14
/**
15
 * Custom installation of redCORE
16
 *
17
 * @package     Redcore
18
 * @subpackage  Install
19
 * @since       1.0
20
 */
21
class Com_RedcoreInstallerScript
22
{
23
	/**
24
	 * Status of the installation
25
	 *
26
	 * @var  stdClass
27
	 */
28
	public $status;
29
30
	/**
31
	 * Show component info after install / update
32
	 *
33
	 * @var  boolean
34
	 */
35
	public $showComponentInfo = true;
36
37
	/**
38
	 * Installer instance
39
	 *
40
	 * @var  JInstaller
41
	 */
42
	public $installer;
43
44
	/**
45
	 * Extension element name
46
	 *
47
	 * @var  string
48
	 */
49
	protected $extensionElement = '';
50
51
	/**
52
	 * Manifest of the extension being processed
53
	 *
54
	 * @var  SimpleXMLElement
55
	 */
56
	protected $manifest;
57
58
	/**
59
	 * Old version according to manifest
60
	 *
61
	 * @var  string
62
	 */
63
	protected $oldVersion = '0.0.0';
64
65
	/**
66
	 * Get the common JInstaller instance used to install all the extensions
67
	 *
68
	 * @return JInstaller The JInstaller object
69
	 */
70
	public function getInstaller()
71
	{
72
		if (null === $this->installer)
73
		{
74
			$this->installer = new JInstaller;
75
		}
76
77
		return $this->installer;
78
	}
79
80
	/**
81
	 * Getter with manifest cache support
82
	 *
83
	 * @param   JInstallerAdapter  $parent  Parent object
84
	 *
85
	 * @return  SimpleXMLElement
86
	 */
87
	protected function getManifest($parent)
88
	{
89
		if (null === $this->manifest)
90
		{
91
			$this->loadManifest($parent);
92
		}
93
94
		return $this->manifest;
95
	}
96
97
	/**
98
	 * Method to run before an install/update/uninstall method
99
	 *
100
	 * @param   string             $type    Type of change (install, update or discover_install)
101
	 * @param   JInstallerAdapter  $parent  Class calling this method
102
	 *
103
	 * @return  boolean
104
	 * @throws  \Exception
105
	 */
106
	public function preflight($type, $parent)
107
	{
108
		$this->installRedcore($type, $parent);
109
		$this->loadRedcoreLibrary();
110
		$this->loadRedcoreLanguage();
111
		$manifest               = $this->getManifest($parent);
112
		$extensionType          = $manifest->attributes()->type;
113
		$this->extensionElement = $this->getElement($parent, $manifest);
114
115
		// Reads current (old) version from manifest
116
		$db      = JFactory::getDbo();
117
		$version = $db->setQuery(
118
			$db->getQuery(true)
119
				->select($db->qn('s.version_id'))
120
				->from($db->qn('#__schemas', 's'))
121
				->join('inner', $db->qn('#__extensions', 'e') . ' ON ' . $db->qn('e.extension_id') . ' = ' . $db->qn('s.extension_id'))
122
				->where($db->qn('e.element') . ' = ' . $db->q($this->extensionElement))
123
		)
124
			->loadResult();
125
126
		if (!empty($version))
127
		{
128
			$this->oldVersion = (string) $version;
129
		}
130
131
		if ($extensionType == 'component' && in_array($type, array('install', 'update', 'discover_install')))
0 ignored issues
show
The condition $extensionType == 'component' is always false.
Loading history...
132
		{
133
			// Update SQL pre-processing
134
			if ($type == 'update')
135
			{
136
				if (!$this->preprocessUpdates($parent))
137
				{
138
					return false;
139
				}
140
			}
141
142
			// In case we are installing redcore
143
			if (get_called_class() === 'Com_RedcoreInstallerScript')
144
			{
145
				if (!$this->checkComponentVersion($this->getRedcoreComponentFolder(), __DIR__, 'redcore.xml'))
146
				{
147
					throw new \Exception(JText::_('COM_REDCORE_INSTALL_ERROR_OLDER_VERSION'));
148
				}
149
150
				if (!class_exists('RComponentHelper'))
151
				{
152
					$searchPaths = array(
153
						// Discover install
154
						JPATH_LIBRARIES . '/redcore/component',
155
						// Install
156
						__DIR__ . '/redCORE/libraries/redcore/component',
157
						__DIR__ . '/libraries/redcore/component'
158
					);
159
160
					$componentHelper = JPath::find($searchPaths, 'helper.php');
161
162
					if ($componentHelper)
163
					{
164
						require_once $componentHelper;
165
					}
166
				}
167
			}
168
169
			$requirements = array();
170
171
			if (method_exists('RComponentHelper', 'checkComponentRequirements'))
172
			{
173
				$requirements = RComponentHelper::checkComponentRequirements($manifest->requirements);
174
			}
175
176
			if (!empty($requirements))
177
			{
178
				foreach ($requirements as $key => $requirement)
179
				{
180
					foreach ($requirement as $checked)
181
					{
182
						if (!$checked['status'])
183
						{
184
							// In case redCORE cannot be installed we do not have the language string
185
							if (get_called_class() === 'Com_RedcoreInstallerScript')
186
							{
187
								$this->loadRedcoreLanguage(__DIR__);
188
								$checked['name'] = JText::_($checked['name']);
189
							}
190
191
							$messageKey = $key == 'extensions'
192
								? 'COM_REDCORE_INSTALL_ERROR_REQUIREMENTS_EXTENSIONS'
193
								: 'COM_REDCORE_INSTALL_ERROR_REQUIREMENTS';
194
195
							throw new \Exception(JText::sprintf($messageKey, $checked['name'], $checked['required'], $checked['current']));
196
						}
197
					}
198
				}
199
			}
200
		}
201
202
		return true;
203
	}
204
205
	/**
206
	 * Method to install the component
207
	 *
208
	 * @param   JInstallerAdapter  $parent  Class calling this method
209
	 *
210
	 * @return  boolean          True on success
211
	 */
212
	public function install($parent)
213
	{
214
		// Common tasks for install or update
215
		$this->installOrUpdate($parent);
216
217
		return true;
218
	}
219
220
	/**
221
	 * Method to install the component
222
	 *
223
	 * @param   JInstallerAdapter  $parent  Class calling this method
224
	 *
225
	 * @return  boolean                     True on success
226
	 */
227
	public function installOrUpdate($parent)
228
	{
229
		// Install extensions
230
		// We have already installed redCORE library on preflight so we will not do it again
231
		if (get_called_class() !== 'Com_RedcoreInstallerScript')
232
		{
233
			$this->installLibraries($parent);
234
		}
235
236
		$this->loadRedcoreLibrary();
237
		$this->installMedia($parent);
238
		$this->installWebservices($parent);
239
		$this->installModules($parent);
240
		$this->installPlugins($parent);
241
		$this->installTemplates($parent);
242
		$this->installCli($parent);
243
244
		return true;
245
	}
246
247
	/**
248
	 * Method to process SQL updates previous to the install process
249
	 *
250
	 * @param   JInstallerAdapter  $parent  Class calling this method
251
	 *
252
	 * @return  boolean          True on success
253
	 */
254
	public function preprocessUpdates($parent)
255
	{
256
		$manifest = $parent->get('manifest');
257
258
		if (isset($manifest->update))
259
		{
260
			if (isset($manifest->update->attributes()->folder))
261
			{
262
				$path       = $manifest->update->attributes()->folder;
263
				$sourcePath = $parent->getParent()->getPath('source');
264
265
				if (isset($manifest->update->pre, $manifest->update->pre->schemas))
266
				{
267
					$schemaPaths = $manifest->update->pre->schemas->children();
268
269
					if (count($schemaPaths))
270
					{
271
						// If it just upgraded redCORE to a newer version using RFactory for database, it forces using the redCORE database drivers
272
						if (substr(get_class(JFactory::$database), 0, 1) == 'J' && $this->extensionElement != 'com_redcore')
273
						{
274
							RFactory::$database = null;
275
							JFactory::$database = RFactory::getDbo();
276
						}
277
278
						$db = JFactory::getDbo();
279
280
						$dbDriver   = strtolower($db->name);
281
						$dbDriver   = $dbDriver == 'mysqli' ? 'mysql' : $dbDriver;
282
						$schemaPath = '';
283
284
						foreach ($schemaPaths as $entry)
285
						{
286
							if (isset($entry->attributes()->type))
287
							{
288
								$uDriver = strtolower($entry->attributes()->type);
289
290
								if ($uDriver == 'mysqli')
291
								{
292
									$uDriver = 'mysql';
293
								}
294
295
								if ($uDriver == $dbDriver)
296
								{
297
									$schemaPath = (string) $entry;
298
									break;
299
								}
300
							}
301
						}
302
303
						if ($schemaPath != '')
0 ignored issues
show
The condition $schemaPath != '' is always false.
Loading history...
304
						{
305
							$files = str_replace('.sql', '', JFolder::files($sourcePath . '/' . $path . '/' . $schemaPath, '\.sql$'));
306
							usort($files, 'version_compare');
307
308
							if (count($files))
309
							{
310
								foreach ($files as $file)
311
								{
312
									if (version_compare($file, $this->oldVersion) > 0)
313
									{
314
										$buffer  = file_get_contents($sourcePath . '/' . $path . '/' . $schemaPath . '/' . $file . '.sql');
315
										$queries = RHelperDatabase::splitSQL($buffer);
316
317
										if (count($queries))
318
										{
319
											foreach ($queries as $query)
320
											{
321
												if ($query != '' && $query[0] != '#')
322
												{
323
													$db->setQuery($query);
324
325
													if (!$db->execute(true))
326
													{
327
														JLog::add(
328
															JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true)),
329
															JLog::WARNING,
330
															'jerror'
331
														);
332
333
														return false;
334
													}
335
												}
336
											}
337
										}
338
									}
339
								}
340
							}
341
						}
342
					}
343
				}
344
			}
345
		}
346
347
		return true;
348
	}
349
350
	/**
351
	 * Method to process PHP update files defined in the manifest file
352
	 *
353
	 * @param   JInstallerAdapter  $parent              Class calling this method
354
	 * @param   bool               $executeAfterUpdate  The name of the function to execute
355
	 *
356
	 * @return  boolean          True on success
357
	 */
358
	public function phpUpdates($parent, $executeAfterUpdate)
359
	{
360
		$manifest = $parent->get('manifest');
361
362
		if (isset($manifest->update))
363
		{
364
			if (isset($manifest->update->php) && isset($manifest->update->php->path))
365
			{
366
				$updatePath = (string) $manifest->update->php->path;
367
368
				if ($updatePath != '')
369
				{
370
					switch ((string) $manifest['type'])
371
					{
372
						case 'plugin':
373
							$sourcePath = JPATH_PLUGINS . '/' . (string) $manifest['group'] . '/' . $this->extensionElement;
374
							break;
375
						case 'module':
376
							if ((string) $manifest['client'] == 'administrator')
377
							{
378
								$sourcePath = JPATH_ADMINISTRATOR . '/modules/' . $this->extensionElement;
379
							}
380
							else
381
							{
382
								$sourcePath = JPATH_SITE . '/modules/' . $this->extensionElement;
383
							}
384
							break;
385
						case 'library':
386
							$sourcePath = JPATH_BASE . '/libraries/' . $this->extensionElement;
387
							break;
388
						case 'component':
389
						default:
390
							$sourcePath = JPATH_ADMINISTRATOR . '/components/' . $this->extensionElement;
391
							break;
392
					}
393
394
					if (is_dir($sourcePath . '/' . $updatePath))
395
					{
396
						$files = str_replace('.php', '', JFolder::files($sourcePath . '/' . $updatePath, '\.php$'));
397
398
						if (!empty($files))
399
						{
400
							usort($files, 'version_compare');
401
402
							if (count($files))
403
							{
404
								foreach ($files as $file)
405
								{
406
									if (version_compare($file, $this->oldVersion) > 0)
407
									{
408
										if (!$this->processPHPUpdateFile(
409
											$parent,
410
											$sourcePath . '/' . $updatePath . '/' . $file . '.php', $file, $executeAfterUpdate
411
										))
412
										{
413
											return false;
414
										}
415
									}
416
								}
417
							}
418
						}
419
					}
420
				}
421
			}
422
		}
423
424
		return true;
425
	}
426
427
	/**
428
	 * Method to process a single PHP update file
429
	 *
430
	 * @param   JInstallerAdapter  $parent              Class calling this method
431
	 * @param   string             $file                File to process
432
	 * @param   string             $version             File version
433
	 * @param   bool               $executeAfterUpdate  The name of the function to execute
434
	 *
435
	 * @return  boolean          True on success
436
	 */
437
	public function processPHPUpdateFile($parent, $file, $version, $executeAfterUpdate)
438
	{
439
		static $upgradeClasses;
440
441
		if (!isset($upgradeClasses))
442
		{
443
			$upgradeClasses = array();
444
		}
445
446
		require_once $file;
447
448
		$extensionElement    = $this->extensionElement;
449
		$extensionElementArr = explode ('_', $extensionElement);
450
451
		foreach ($extensionElementArr as $key => $item)
452
		{
453
			$extensionElementArr[$key] = ucfirst($item);
454
		}
455
456
		$extensionElement = implode('_', $extensionElementArr);
457
458
		$versionArr = explode('-', $version);
459
460
		foreach ($versionArr as $key => $item)
461
		{
462
			$versionArr[$key] = ucfirst($item);
463
		}
464
465
		$version = implode('_', $versionArr);
466
		$version = str_replace('.', '_', $version);
467
468
		$class = $extensionElement . 'UpdateScript_' . $version;
469
470
		$methodName = $executeAfterUpdate ? 'executeAfterUpdate' : 'execute';
471
472
		if (class_exists($class))
473
		{
474
			if (!isset($upgradeClasses[$class]))
475
			{
476
				$upgradeClasses[$class] = new $class;
477
			}
478
479
			if (method_exists($upgradeClasses[$class], $methodName))
480
			{
481
				if (!$upgradeClasses[$class]->{$methodName}($parent))
482
				{
483
					return false;
484
				}
485
			}
486
		}
487
488
		return true;
489
	}
490
491
	/**
492
	 * Install the package libraries
493
	 *
494
	 * @param   JInstallerAdapter  $parent  class calling this method
495
	 *
496
	 * @return  void
497
	 */
498
	private function installLibraries($parent)
499
	{
500
		// Required objects
501
		$installer = $this->getInstaller();
502
		$manifest  = $this->getManifest($parent);
503
		$src       = $parent->getParent()->getPath('source');
504
505
		if ($nodes = $manifest->libraries->library)
506
		{
507
			foreach ($nodes as $node)
508
			{
509
				$extName = $node->attributes()->name;
0 ignored issues
show
The method attributes() does not exist on null. ( Ignorable by Annotation )

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

509
				$extName = $node->/** @scrutinizer ignore-call */ attributes()->name;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
510
				$extPath = $src . '/libraries/' . $extName;
511
				$result  = 0;
512
513
				// Standard install
514
				if (is_dir($extPath))
515
				{
516
					$result = $installer->install($extPath);
517
				}
518
				// Discover install
519
				elseif ($extId = $this->searchExtension($extName, 'library', '-1'))
520
				{
521
					$result = $installer->discover_install($extId);
522
				}
523
524
				$this->_storeStatus('libraries', array('name' => $extName, 'result' => $result));
525
			}
526
		}
527
	}
528
529
	/**
530
	 * Install the media folder
531
	 *
532
	 * @param   JInstallerAdapter  $parent  class calling this method
533
	 *
534
	 * @return  void
535
	 */
536
	private function installMedia($parent)
537
	{
538
		$installer = $this->getInstaller();
539
		$manifest  = $this->getManifest($parent);
540
		$src       = $parent->getParent()->getPath('source');
541
542
		if ($manifest && $manifest->attributes()->type == 'package')
0 ignored issues
show
The condition $manifest->attributes()->type == 'package' is always false.
Loading history...
543
		{
544
			$installer->setPath('source', $src);
545
			$installer->parseMedia($manifest->media);
546
		}
547
	}
548
549
	/**
550
	 * Install the package modules
551
	 *
552
	 * @param   JInstallerAdapter  $parent  class calling this method
553
	 *
554
	 * @return  void
555
	 */
556
	protected function installModules($parent)
557
	{
558
		// Required objects
559
		$installer = $this->getInstaller();
560
		$manifest  = $parent->get('manifest');
561
		$src       = $parent->getParent()->getPath('source');
562
		$nodes     = $manifest->modules->module;
563
564
		if (empty($nodes))
565
		{
566
			return;
567
		}
568
569
		foreach ($nodes as $node)
570
		{
571
			$extName   = $node->attributes()->name;
572
			$extClient = $node->attributes()->client;
573
			$extPath   = $src . '/modules/' . $extClient . '/' . $extName;
574
			$result    = 0;
575
576
			// Standard install
577
			if (is_dir($extPath))
578
			{
579
				$installer->setAdapter('module');
580
				$result = $installer->install($extPath);
581
			}
582
			elseif ($extId = $this->searchExtension($extName, 'module', '-1'))
583
				// Discover install
584
			{
585
				$result = $installer->discover_install($extId);
586
			}
587
588
			$this->_storeStatus('modules', array('name' => $extName, 'client' => $extClient, 'result' => $result));
589
		}
590
	}
591
592
	/**
593
	 * Install the package libraries
594
	 *
595
	 * @param   JInstallerAdapter  $parent  class calling this method
596
	 *
597
	 * @return  void
598
	 */
599
	protected function installPlugins($parent)
600
	{
601
		// Required objects
602
		$installer = $this->getInstaller();
603
		$manifest  = $parent->get('manifest');
604
		$src       = $parent->getParent()->getPath('source');
605
		$nodes     = $manifest->plugins->plugin;
606
607
		if (empty($nodes))
608
		{
609
			return;
610
		}
611
612
		foreach ($nodes as $node)
613
		{
614
			$extName  = $node->attributes()->name;
615
			$extGroup = $node->attributes()->group;
616
			$disabled = !empty($node->attributes()->disabled) ? true : false;
617
			$extPath  = $src . '/plugins/' . $extGroup . '/' . $extName;
618
			$result   = 0;
619
620
			// Standard install
621
			if (is_dir($extPath))
622
			{
623
				$installer->setAdapter('plugin');
624
				$result = $installer->install($extPath);
625
			}
626
			elseif ($extId = $this->searchExtension($extName, 'plugin', '-1', $extGroup))
627
				// Discover install
628
			{
629
				$result = $installer->discover_install($extId);
630
			}
631
632
			// Store the result to show install summary later
633
			$this->_storeStatus('plugins', array('name' => $extName, 'group' => $extGroup, 'result' => $result));
634
635
			// Enable the installed plugin
636
			if ($result && !$disabled)
637
			{
638
				$db    = JFactory::getDBO();
639
				$query = $db->getQuery(true);
640
				$query->update($db->qn('#__extensions'));
641
				$query->set($db->qn('enabled') . ' = 1');
642
				$query->set($db->qn('state') . ' = 1');
643
				$query->where($db->qn('type') . ' = ' . $db->q('plugin'));
644
				$query->where($db->qn('element') . ' = ' . $db->q($extName));
645
				$query->where($db->qn('folder') . ' = ' . $db->q($extGroup));
646
				$db->setQuery($query)->execute();
647
			}
648
		}
649
	}
650
651
	/**
652
	 * Install the package translations
653
	 *
654
	 * @param   JInstallerAdapter  $parent  class calling this method
655
	 *
656
	 * @return  void
657
	 */
658
	protected function installTranslations($parent)
659
	{
660
		// Required objects
661
		$manifest = $parent->get('manifest');
662
663
		if (method_exists('RTranslationTable', 'batchContentElements'))
664
		{
665
			$nodes = $manifest->translations->translation;
666
667
			if (empty($nodes))
668
			{
669
				return;
670
			}
671
672
			foreach ($nodes as $node)
673
			{
674
				$extName = (string) $node->attributes()->name;
675
676
				try
677
				{
678
					RTranslationTable::batchContentElements($extName, 'install');
679
				}
680
				catch (Exception $e)
681
				{
682
					// We are already setting message queue so we don't need to set it here as well
683
				}
684
685
				$this->_storeStatus('translations', array('name' => $extName, 'result' => true));
686
			}
687
		}
688
	}
689
690
	/**
691
	 * Function to install redCORE for components
692
	 *
693
	 * @param   string             $type    type of change (install, update or discover_install)
694
	 * @param   JInstallerAdapter  $parent  class calling this method
695
	 *
696
	 * @return  void
697
	 * @throws  Exception
698
	 */
699
	protected function installRedcore($type, $parent)
700
	{
701
		// If it's installing redcore as dependency
702
		if (get_called_class() != 'Com_RedcoreInstallerScript' && $type != 'discover_install')
703
		{
704
			$manifest = $this->getManifest($parent);
705
706
			if ($manifest->redcore)
707
			{
708
				$installer              = $this->getInstaller();
709
				$redcoreFolder          = __DIR__;
710
				$redcoreComponentFolder = $this->getRedcoreComponentFolder();
711
712
				if (is_dir($redcoreFolder) && JPath::clean($redcoreFolder) != JPath::clean($redcoreComponentFolder))
713
				{
714
					$install = $this->checkComponentVersion($redcoreComponentFolder, $redcoreFolder, 'redcore.xml');
715
716
					if ($install)
717
					{
718
						$installer->install($redcoreFolder);
719
						$this->loadRedcoreLibrary();
720
					}
721
				}
722
			}
723
		}
724
		// If it is installing redCORE we want to make sure it installs redCORE library first
725
		elseif (get_called_class() == 'Com_RedcoreInstallerScript' && in_array($type, array('install', 'update', 'discover_install')))
726
		{
727
			$install = $this->checkComponentVersion(JPATH_LIBRARIES . '/redcore', __DIR__ . '/libraries/redcore', 'redcore.xml');
728
729
			// Only install if installation in the package is newer version
730
			if ($install)
731
			{
732
				$this->installLibraries($parent);
733
			}
734
		}
735
	}
736
737
	/**
738
	 * Function to install redCORE for components
739
	 *
740
	 * @param   JInstallerAdapter  $parent  class calling this method
741
	 *
742
	 * @return  void
743
	 */
744
	protected function postInstallRedcore($parent)
745
	{
746
		$manifest = $this->getManifest($parent);
747
		$type     = $manifest->attributes()->type;
748
749
		if ($type == 'component')
0 ignored issues
show
The condition $type == 'component' is always false.
Loading history...
750
		{
751
			$redcoreNode = $manifest->redcore;
752
753
			if ($redcoreNode)
754
			{
755
				$redcoreFolder = __DIR__;
756
757
				if (!empty($redcoreFolder))
758
				{
759
					$version = $redcoreNode->attributes()->version;
760
761
					$class  = get_called_class();
762
					$option = strtolower(strstr($class, 'Installer', true));
763
764
					$db    = JFactory::getDBO();
765
					$query = $db->getQuery(true)
766
						->select($db->qn('params'))
767
						->from($db->qn('#__extensions'))
768
						->where($db->qn('type') . ' = ' . $db->q($type))
769
						->where($db->qn('element') . ' = ' . $db->q($option));
770
771
					$comParams = new Registry($db->setQuery($query)->loadResult());
772
					$comParams->set('redcore',
773
						array('version' => (string) $version)
774
					);
775
776
					$query = $db->getQuery(true);
777
					$query->update($db->qn('#__extensions'));
778
					$query->set($db->qn('params') . ' = ' . $db->q($comParams->toString()));
779
					$query->where($db->qn('type') . ' = ' . $db->q($type));
780
					$query->where($db->qn('element') . ' = ' . $db->q($option));
781
					$db->setQuery($query)->execute();
782
				}
783
			}
784
		}
785
	}
786
787
	/**
788
	 * Install the package templates
789
	 *
790
	 * @param   JInstallerAdapter  $parent  class calling this method
791
	 *
792
	 * @return  void
793
	 */
794
	private function installTemplates($parent)
795
	{
796
		// Required objects
797
		$installer = $this->getInstaller();
798
		$manifest  = $parent->get('manifest');
799
		$src       = $parent->getParent()->getPath('source');
800
		$nodes     = $manifest->templates->template;
801
802
		if ($nodes)
803
		{
804
			foreach ($nodes as $node)
805
			{
806
				$extName   = $node->attributes()->name;
807
				$extClient = $node->attributes()->client;
808
				$extPath   = $src . '/templates/' . $extClient . '/' . $extName;
809
				$result    = 0;
810
811
				// Standard install
812
				if (is_dir($extPath))
813
				{
814
					$installer->setAdapter('template');
815
					$result = $installer->install($extPath);
816
				}
817
				// Discover install
818
				elseif ($extId = $this->searchExtension($extName, 'template', '-1'))
819
				{
820
					$result = $installer->discover_install($extId);
821
				}
822
823
				$this->_storeStatus('templates', array('name' => $extName, 'client' => $extClient, 'result' => $result));
824
			}
825
		}
826
	}
827
828
	/**
829
	 * Install the package Cli scripts
830
	 *
831
	 * @param   JInstallerAdapter  $parent  class calling this method
832
	 *
833
	 * @return  void
834
	 */
835
	private function installCli($parent)
836
	{
837
		// Required objects
838
		$installer = $this->getInstaller();
839
		$manifest  = $parent->get('manifest');
840
		$src       = $parent->getParent()->getPath('source');
841
842
		if (!$manifest)
843
		{
844
			return;
845
		}
846
847
		$installer->setPath('source', $src);
848
		$element = $manifest->cli;
849
850
		if (!$element || !count($element->children()))
851
		{
852
			// Either the tag does not exist or has no children therefore we return zero files processed.
853
			return;
854
		}
855
856
		$nodes = $element->children();
857
858
		foreach ($nodes as $node)
859
		{
860
			// Here we set the folder name we are going to copy the files to.
861
			$name = (string) $node->attributes()->name;
862
863
			// Here we set the folder we are going to copy the files to.
864
			$destination = JPath::clean(JPATH_ROOT . '/cli/' . $name);
865
866
			// Here we set the folder we are going to copy the files from.
867
			$folder = (string) $node->attributes()->folder;
868
869
			if ($folder && file_exists($src . '/' . $folder))
870
			{
871
				$source = $src . '/' . $folder;
872
			}
873
			else
874
			{
875
				// Cli folder does not exist
876
				continue;
877
			}
878
879
			$copyFiles = $this->prepareFilesForCopy($element, $source, $destination);
880
881
			$installer->copyFiles($copyFiles, true);
882
		}
883
	}
884
885
	/**
886
	 * Method to parse through a webservices element of the installation manifest and take appropriate
887
	 * action.
888
	 *
889
	 * @param   JInstallerAdapter  $parent  class calling this method
890
	 *
891
	 * @return  boolean     True on success
892
	 *
893
	 * @since   1.3
894
	 */
895
	public function installWebservices($parent)
896
	{
897
		$installer = $this->getInstaller();
898
		$manifest  = $this->getManifest($parent);
899
		$src       = $parent->getParent()->getPath('source');
900
901
		if (!$manifest)
0 ignored issues
show
$manifest is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
902
		{
903
			return false;
904
		}
905
906
		$installer->setPath('source', $src);
907
		$element = $manifest->webservices;
908
909
		if (!$element || !count($element->children()))
0 ignored issues
show
$element is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
910
		{
911
			// Either the tag does not exist or has no children therefore we return zero files processed.
912
			return false;
913
		}
914
915
		// Here we set the folder we are going to copy the files from.
916
		$folder = (string) $element->attributes()->folder;
917
918
		// This prevents trying to install webservice from other extension directory if webservice folder is not set
919
		if (!$folder || !is_dir($src . '/' . $folder))
920
		{
921
			return false;
922
		}
923
924
		// Here we set the folder we are going to copy the files to.
925
		$destination = JPath::clean(RApiHalHelper::getWebservicesPath());
926
		$source      = $src . '/' . $folder;
927
928
		$copyFiles = $this->prepareFilesForCopy($element, $source, $destination);
929
930
		// Copy the webservice XML files
931
		$return = $installer->copyFiles($copyFiles, true);
932
933
		// Recreate or create new SOAP WSDL files
934
		if (method_exists('RApiSoapHelper', 'generateWsdlFromFolder'))
935
		{
936
			foreach ($element->children() as $file)
937
			{
938
				RApiSoapHelper::generateWsdlFromFolder($destination . '/' . $file);
939
			}
940
		}
941
942
		return $return;
943
	}
944
945
	/**
946
	 * Method to parse through a xml element of the installation manifest and take appropriate action.
947
	 *
948
	 * @param   SimpleXMLElement  $element      Element to iterate
949
	 * @param   string            $source       Source location of the files
950
	 * @param   string            $destination  Destination location of the files
951
	 *
952
	 * @return  array
953
	 *
954
	 * @since   1.4
955
	 */
956
	public function prepareFilesForCopy($element, $source, $destination)
957
	{
958
		$copyFiles = array();
959
960
		// Process each file in the $files array (children of $tagName).
961
		foreach ($element->children() as $file)
962
		{
963
			$path         = array();
964
			$path['src']  = $source . '/' . $file;
965
			$path['dest'] = $destination . '/' . $file;
966
967
			// Is this path a file or folder?
968
			$path['type'] = ($file->getName() == 'folder') ? 'folder' : 'file';
969
970
			if (basename($path['dest']) != $path['dest'])
971
			{
972
				$newDir = dirname($path['dest']);
973
974
				if (!JFolder::create($newDir))
975
				{
976
					JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newDir), JLog::WARNING, 'jerror');
977
978
					return array();
979
				}
980
			}
981
982
			// Add the file to the copyfiles array
983
			$copyFiles[] = $path;
984
		}
985
986
		return $copyFiles;
987
	}
988
989
	/**
990
	 * Method to run after an install/update/uninstall method
991
	 *
992
	 * @param   string             $type    type of change (install, update or discover_install)
993
	 * @param   JInstallerAdapter  $parent  class calling this method
994
	 *
995
	 * @return  boolean
996
	 */
997
	public function postflight($type, $parent)
998
	{
999
		$installer = get_called_class();
1000
1001
		// If it's installing redcore as dependency
1002
		if ($installer !== 'Com_RedcoreInstallerScript' && $type != 'discover_install')
1003
		{
1004
			$this->postInstallRedcore($parent);
1005
		}
1006
1007
		// Execute the postflight tasks from the manifest
1008
		$this->postFlightFromManifest($type, $parent);
0 ignored issues
show
$type of type string is incompatible with the type object expected by parameter $type of Com_RedcoreInstallerScri...ostFlightFromManifest(). ( Ignorable by Annotation )

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

1008
		$this->postFlightFromManifest(/** @scrutinizer ignore-type */ $type, $parent);
Loading history...
1009
1010
		$this->installTranslations($parent);
1011
1012
		/** @var JXMLElement $manifest */
1013
		$manifest = $parent->get('manifest');
1014
1015
		if (in_array($type, array('install', 'update', 'discover_install')))
1016
		{
1017
			$attributes = current($manifest->attributes());
1018
1019
			// If it's a component
1020
			if (isset($attributes['type']) && (string) $attributes['type'] === 'component')
1021
			{
1022
				$this->loadRedcoreLanguage();
1023
				$this->displayComponentInfo($parent);
1024
			}
1025
		}
1026
1027
		if ($type == 'update')
1028
		{
1029
			$db = JFactory::getDbo();
1030
			$db->setQuery('TRUNCATE ' . $db->qn('#__redcore_schemas'))
1031
				->execute();
1032
		}
1033
1034
		// If this is install redcore component.
1035
		if ($installer == 'Com_RedcoreInstallerScript')
1036
		{
1037
			$this->insertSiteDomain();
1038
		}
1039
1040
		return true;
1041
	}
1042
1043
	/**
1044
	 * Execute the postflight tasks from the manifest if there is any.
1045
	 *
1046
	 * @param   object             $type    type of change (install, update or discover_install)
1047
	 * @param   JInstallerAdapter  $parent  class calling this method
1048
	 *
1049
	 * @return  void
1050
	 */
1051
	protected function postFlightFromManifest($type, $parent)
1052
	{
1053
		$manifest = $parent->get('manifest');
1054
1055
		if ($tasks = $manifest->postflight->task)
1056
		{
1057
			/** @var JXMLElement $task */
1058
			foreach ($tasks as $task)
1059
			{
1060
				$attributes = current($task->attributes());
1061
1062
				// No task name
1063
				if (!isset($attributes['name']))
1064
				{
1065
					continue;
1066
				}
1067
1068
				$taskName = $attributes['name'];
1069
				$class    = get_called_class();
1070
1071
				// Do we have some parameters ?
1072
				$parameters = array();
1073
1074
				if ($params = $task->parameter)
1075
				{
1076
					foreach ($params as $param)
1077
					{
1078
						$parameters[] = (string) $param;
1079
					}
1080
				}
1081
1082
				$parameters = array_merge(array($type, $parent), $parameters);
1083
1084
				// Call the task with $type and $parent as parameters
1085
				if (method_exists($class, $taskName))
1086
				{
1087
					call_user_func_array(array($class, $taskName), $parameters);
1088
				}
1089
			}
1090
		}
1091
	}
1092
1093
	/**
1094
	 * Delete the menu item of the extension.
1095
	 *
1096
	 * @param   string             $type    Type of change (install, update or discover_install)
1097
	 * @param   JInstallerAdapter  $parent  Class calling this method
1098
	 * @param   string             $client  The client
1099
	 *
1100
	 * @return  void
1101
	 */
1102
	protected function deleteMenu($type, $parent, $client = null)
1103
	{
1104
		/** @var JXMLElement $manifest */
1105
		$manifest   = $parent->get('manifest');
1106
		$attributes = current($manifest->attributes());
1107
1108
		// If it's not a component
1109
		if (!isset($attributes['type']))
1110
		{
1111
			return;
1112
		}
1113
1114
		$type          = $attributes['type'];
1115
		$componentName = (string) $manifest->name;
1116
1117
		if (empty($componentName))
1118
		{
1119
			return;
1120
		}
1121
1122
		$db    = JFactory::getDbo();
1123
		$query = $db->getQuery(true)
1124
			->delete('#__menu')
1125
			->where('type = ' . $db->q($type));
1126
1127
		if (!empty($client))
1128
		{
1129
			$query->where($db->qn('client_id') . ' = ' . $db->q($client));
1130
		}
1131
1132
		$query->where(
1133
			array(
1134
				'title = ' . $db->q($componentName),
1135
				'title = ' . $db->q(strtolower($componentName))
1136
			),
1137
			'OR'
1138
		);
1139
1140
		$db->setQuery($query);
1141
		$db->execute();
1142
	}
1143
1144
	/**
1145
	 * Search a extension in the database
1146
	 *
1147
	 * @param   string  $element  Extension technical name/alias
1148
	 * @param   string  $type     Type of extension (component, file, language, library, module, plugin)
1149
	 * @param   string  $state    State of the searched extension
1150
	 * @param   string  $folder   Folder name used mainly in plugins
1151
	 *
1152
	 * @return  integer           Extension identifier
1153
	 */
1154
	protected function searchExtension($element, $type, $state = null, $folder = null)
1155
	{
1156
		$db    = JFactory::getDBO();
1157
		$query = $db->getQuery(true)
1158
			->select($db->qn('extension_id'))
1159
			->from($db->qn("#__extensions"))
1160
			->where($db->qn('type') . ' = ' . $db->q($type))
1161
			->where($db->qn('element') . ' = ' . $db->q($element));
1162
1163
		if (null !== $state)
1164
		{
1165
			$query->where($db->qn('state') . ' = ' . (int) $state);
1166
		}
1167
1168
		if (null !== $folder)
1169
		{
1170
			$query->where($db->qn('folder') . ' = ' . $db->q($folder));
1171
		}
1172
1173
		return $db->setQuery($query)->loadResult();
1174
	}
1175
1176
	/**
1177
	 * method to update the component
1178
	 *
1179
	 * @param   JInstallerAdapter  $parent  class calling this method
1180
	 *
1181
	 * @return void
1182
	 */
1183
	public function update($parent)
1184
	{
1185
		// Process PHP update files
1186
		$this->phpUpdates($parent, false);
1187
1188
		// Common tasks for install or update
1189
		$this->installOrUpdate($parent);
1190
1191
		// Process PHP update files
1192
		$this->phpUpdates($parent, true);
1193
	}
1194
1195
	/**
1196
	 * Prevents uninstalling redcore component if some components using it are still installed.
1197
	 *
1198
	 * @param   JInstallerAdapter  $parent  class calling this method
1199
	 *
1200
	 * @return  void
1201
	 *
1202
	 * @throws  Exception
1203
	 */
1204
	private function preventUninstallRedcore($parent)
1205
	{
1206
		$this->loadRedcoreLibrary();
1207
1208
		// Avoid uninstalling redcore if there is a component using it
1209
		$manifest  = $this->getManifest($parent);
1210
		$isRedcore = 'COM_REDCORE' == (string) $manifest->name;
1211
1212
		if ($isRedcore)
1213
		{
1214
			if (method_exists('RComponentHelper', 'getRedcoreComponents'))
1215
			{
1216
				$components = RComponentHelper::getRedcoreComponents();
1217
1218
				if (!empty($components))
1219
				{
1220
					$app     = JFactory::getApplication();
1221
					$message = sprintf(
1222
						'Cannot uninstall redCORE because the following components are using it: <br /> [%s]',
1223
						implode(',<br /> ', $components)
1224
					);
1225
1226
					$app->enqueueMessage($message, 'error');
1227
					$app->redirect('index.php?option=com_installer&view=manage');
1228
				}
1229
			}
1230
		}
1231
	}
1232
1233
	/**
1234
	 * method to uninstall the component
1235
	 *
1236
	 * @param   JInstallerAdapter  $parent  class calling this method
1237
	 *
1238
	 * @return  void
1239
	 *
1240
	 * @throws  Exception
1241
	 */
1242
	public function uninstall($parent)
1243
	{
1244
		$this->preventUninstallRedcore($parent);
1245
1246
		// Uninstall extensions
1247
		$this->uninstallTranslations($parent);
1248
		$this->uninstallMedia($parent);
1249
		$this->uninstallWebservices($parent);
1250
		$this->uninstallModules($parent);
1251
		$this->uninstallPlugins($parent);
1252
		$this->uninstallTemplates($parent);
1253
		$this->uninstallCli($parent);
1254
		$this->uninstallLibraries($parent);
1255
	}
1256
1257
	/**
1258
	 * Uninstall all Translation tables from database
1259
	 *
1260
	 * @param   JInstallerAdapter  $parent  class calling this method
1261
	 *
1262
	 * @return  void
1263
	 *
1264
	 * @throws  Exception
1265
	 */
1266
	protected function uninstallTranslations($parent)
1267
	{
1268
		if (method_exists('RTranslationTable', 'batchContentElements'))
1269
		{
1270
			// Required objects
1271
			$manifest              = $parent->get('manifest');
1272
			$class                 = get_called_class();
1273
			$deleteIds             = array();
1274
			$translationTables     = RTranslationTable::getInstalledTranslationTables(true);
1275
			$translationTableModel = RModel::getAdminInstance('Translation_Table', array(), 'com_redcore');
1276
1277
			// Delete specific extension translation tables
1278
			if ($class != 'Com_RedcoreInstallerScript')
1279
			{
1280
				$nodes = $manifest->translations->translation;
1281
1282
				if ($nodes)
1283
				{
1284
					foreach ($nodes as $node)
1285
					{
1286
						$extensionOption = (string) $node->attributes()->name;
1287
1288
						if (!empty($translationTables))
1289
						{
1290
							foreach ($translationTables as $translationTableParams)
1291
							{
1292
								if ($extensionOption == $translationTableParams->option)
1293
								{
1294
									$deleteIds[] = $translationTableParams->id;
1295
								}
1296
							}
1297
						}
1298
					}
1299
				}
1300
			}
1301
			// We delete everything
1302
			else
1303
			{
1304
				if (!empty($translationTables))
1305
				{
1306
					foreach ($translationTables as $translationTableParams)
1307
					{
1308
						$deleteIds[] = $translationTableParams->id;
1309
					}
1310
				}
1311
			}
1312
1313
			if (!empty($deleteIds))
1314
			{
1315
				foreach ($deleteIds as $deleteId)
1316
				{
1317
					try
1318
					{
1319
						$translationTableModel->delete($deleteId);
0 ignored issues
show
The method delete() does not exist on RModel. ( Ignorable by Annotation )

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

1319
						$translationTableModel->/** @scrutinizer ignore-call */ 
1320
                              delete($deleteId);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1320
					}
1321
					catch (Exception $e)
1322
					{
1323
						JFactory::getApplication()->enqueueMessage(
1324
							JText::sprintf('LIB_REDCORE_TRANSLATIONS_DELETE_ERROR', $e->getMessage()), 'error'
1325
						);
1326
					}
1327
				}
1328
			}
1329
		}
1330
	}
1331
1332
	/**
1333
	 * Uninstall the package libraries
1334
	 *
1335
	 * @param   JInstallerAdapter  $parent  class calling this method
1336
	 *
1337
	 * @return  void
1338
	 */
1339
	protected function uninstallLibraries($parent)
1340
	{
1341
		// Required objects
1342
		$installer = $this->getInstaller();
1343
		$manifest  = $this->getManifest($parent);
1344
		$nodes     = $manifest->libraries->library;
1345
1346
		if ($nodes)
0 ignored issues
show
$nodes is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
1347
		{
1348
			foreach ($nodes as $node)
1349
			{
1350
				$extName = $node->attributes()->name;
1351
				$result  = 0;
1352
				$extId   = $this->searchExtension($extName, 'library');
1353
1354
				if ($extId)
1355
				{
1356
					$result = $installer->uninstall('library', $extId);
1357
				}
1358
1359
				// Store the result to show install summary later
1360
				$this->_storeStatus('libraries', array('name' => $extName, 'result' => $result));
1361
			}
1362
		}
1363
	}
1364
1365
	/**
1366
	 * Uninstall the media folder
1367
	 *
1368
	 * @param   JInstallerAdapter  $parent  class calling this method
1369
	 *
1370
	 * @return  void
1371
	 */
1372
	protected function uninstallMedia($parent)
1373
	{
1374
		// Required objects
1375
		$installer = $this->getInstaller();
1376
		$manifest  = $this->getManifest($parent);
1377
1378
		if ($manifest && $manifest->attributes()->type == 'package')
0 ignored issues
show
The condition $manifest->attributes()->type == 'package' is always false.
Loading history...
1379
		{
1380
			$installer->removeFiles($manifest->media);
1381
		}
1382
	}
1383
1384
	/**
1385
	 * Uninstall the webservices
1386
	 *
1387
	 * @param   JInstallerAdapter  $parent  class calling this method
1388
	 *
1389
	 * @return  boolean
1390
	 */
1391
	protected function uninstallWebservices($parent)
1392
	{
1393
		// Required objects
1394
		$manifest = $this->getManifest($parent);
1395
1396
		if (!$manifest)
0 ignored issues
show
$manifest is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
1397
		{
1398
			return false;
1399
		}
1400
1401
		// We will use webservices removal function to remove webservice files
1402
		$element = $manifest->webservices;
1403
1404
		if (!$element || !count($element->children()))
0 ignored issues
show
$element is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
1405
		{
1406
			// Either the tag does not exist or has no children therefore we return zero files processed.
1407
			return true;
1408
		}
1409
1410
		$returnValue = true;
1411
1412
		// Get the array of file nodes to process
1413
		$files  = $element->children();
1414
		$source = RApiHalHelper::getWebservicesPath();
1415
1416
		// Process each file in the $files array (children of $tagName).
1417
		foreach ($files as $file)
1418
		{
1419
			$path = $source . '/' . $file;
1420
1421
			// Actually delete the files/folders
1422
1423
			if (is_dir($path))
1424
			{
1425
				$val = JFolder::delete($path);
1426
			}
1427
			else
1428
			{
1429
				$val = JFile::delete($path);
1430
			}
1431
1432
			if ($val === false)
1433
			{
1434
				JLog::add(JText::sprintf('LIB_REDCORE_INSTALLER_ERROR_FAILED_TO_DELETE', $path), JLog::WARNING, 'jerror');
1435
				$returnValue = false;
1436
			}
1437
		}
1438
1439
		return $returnValue;
1440
	}
1441
1442
	/**
1443
	 * Uninstall the Cli
1444
	 *
1445
	 * @param   JInstallerAdapter  $parent  class calling this method
1446
	 *
1447
	 * @return  boolean
1448
	 */
1449
	protected function uninstallCli($parent)
1450
	{
1451
		// Required objects
1452
		$manifest = $this->getManifest($parent);
1453
1454
		if (!$manifest)
0 ignored issues
show
$manifest is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
1455
		{
1456
			return false;
1457
		}
1458
1459
		// We will use cli removal function to remove cli folders
1460
		$element = $manifest->cli;
1461
1462
		if (!$element || !count($element->children()))
0 ignored issues
show
$element is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
1463
		{
1464
			// Either the tag does not exist or has no children therefore we return zero files processed.
1465
			return true;
1466
		}
1467
1468
		$returnValue = true;
1469
1470
		// Get the array of file nodes to process
1471
		$folders = $element->children();
1472
		$source  = JPATH_ROOT . '/cli/';
1473
1474
		// Process each folder in the $folders array
1475
		foreach ($folders as $folder)
1476
		{
1477
			// Here we set the folder name we are going to delete from cli main folder
1478
			$name = (string) $folder->attributes()->name;
0 ignored issues
show
The method attributes() does not exist on null. ( Ignorable by Annotation )

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

1478
			$name = (string) $folder->/** @scrutinizer ignore-call */ attributes()->name;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1479
1480
			// If name is not set we should not delete whole cli folder
1481
			if (empty($name))
1482
			{
1483
				continue;
1484
			}
1485
1486
			$path = $source . '/' . $name;
1487
1488
			// Delete the files/folders
1489
			if (is_dir($path))
1490
			{
1491
				$val = JFolder::delete($path);
1492
			}
1493
			else
1494
			{
1495
				$val = JFile::delete($path);
1496
			}
1497
1498
			if ($val === false)
1499
			{
1500
				JLog::add(JText::sprintf('LIB_REDCORE_INSTALLER_ERROR_FAILED_TO_DELETE', $path), JLog::WARNING, 'jerror');
1501
				$returnValue = false;
1502
			}
1503
		}
1504
1505
		return $returnValue;
1506
	}
1507
1508
	/**
1509
	 * Uninstall the package modules
1510
	 *
1511
	 * @param   JInstallerAdapter  $parent  class calling this method
1512
	 *
1513
	 * @return  void
1514
	 */
1515
	protected function uninstallModules($parent)
1516
	{
1517
		// Required objects
1518
		$installer = $this->getInstaller();
1519
		$manifest  = $this->getManifest($parent);
1520
		$nodes     = $manifest->modules->module;
1521
1522
		if (empty($nodes))
1523
		{
1524
			return;
1525
		}
1526
1527
		foreach ($nodes as $node)
1528
		{
1529
			$extName   = $node->attributes()->name;
1530
			$extClient = $node->attributes()->client;
1531
			$result    = 0;
1532
			$extId     = $this->searchExtension($extName, 'module');
1533
1534
			if ($extId)
1535
			{
1536
				$result = $installer->uninstall('module', $extId);
1537
			}
1538
1539
			// Store the result to show install summary later
1540
			$this->_storeStatus('modules', array('name' => $extName, 'client' => $extClient, 'result' => $result));
1541
		}
1542
	}
1543
1544
	/**
1545
	 * Uninstall the package plugins
1546
	 *
1547
	 * @param   JInstallerAdapter  $parent  class calling this method
1548
	 *
1549
	 * @return  void
1550
	 */
1551
	protected function uninstallPlugins($parent)
1552
	{
1553
		// Required objects
1554
		$installer = $this->getInstaller();
1555
		$manifest  = $this->getManifest($parent);
1556
		$nodes     = $manifest->plugins->plugin;
1557
1558
		if (empty($nodes))
1559
		{
1560
			return;
1561
		}
1562
1563
		foreach ($nodes as $node)
1564
		{
1565
			$extName  = $node->attributes()->name;
1566
			$extGroup = $node->attributes()->group;
1567
			$result   = 0;
1568
			$extId    = $this->searchExtension($extName, 'plugin', null, $extGroup);
1569
1570
			if ($extId)
1571
			{
1572
				$result = $installer->uninstall('plugin', $extId);
1573
			}
1574
1575
			// Store the result to show install summary later
1576
			$this->_storeStatus('plugins', array('name' => $extName, 'group' => $extGroup, 'result' => $result));
1577
		}
1578
	}
1579
1580
	/**
1581
	 * Uninstall the package templates
1582
	 *
1583
	 * @param   JInstallerAdapter  $parent  class calling this method
1584
	 *
1585
	 * @return  void
1586
	 */
1587
	protected function uninstallTemplates($parent)
1588
	{
1589
		// Required objects
1590
		$installer = $this->getInstaller();
1591
		$manifest  = $this->getManifest($parent);
1592
		$nodes     = $manifest->templates->template;
1593
1594
		if (empty($nodes))
1595
		{
1596
			return;
1597
		}
1598
1599
		foreach ($nodes as $node)
1600
		{
1601
			$extName   = $node->attributes()->name;
1602
			$extClient = $node->attributes()->client;
1603
			$result    = 0;
1604
			$extId     = $this->searchExtension($extName, 'template', 0);
1605
1606
			if ($extId)
1607
			{
1608
				$result = $installer->uninstall('template', $extId);
1609
			}
1610
1611
			// Store the result to show install summary later
1612
			$this->_storeStatus('templates', array('name' => $extName, 'client' => $extClient, 'result' => $result));
1613
		}
1614
	}
1615
1616
	/**
1617
	 * Store the result of trying to install an extension
1618
	 *
1619
	 * @param   string  $type    Type of extension (libraries, modules, plugins)
1620
	 * @param   array   $status  The status info
1621
	 *
1622
	 * @return void
1623
	 */
1624
	private function _storeStatus($type, $status)
1625
	{
1626
		// Initialise status object if needed
1627
		if (null === $this->status)
1628
		{
1629
			$this->status = new stdClass;
1630
		}
1631
1632
		// Initialise current status type if needed
1633
		if (!isset($this->status->{$type}))
1634
		{
1635
			$this->status->{$type} = array();
1636
		}
1637
1638
		// Insert the status
1639
		$this->status->{$type}[] = $status;
1640
	}
1641
1642
	/**
1643
	 * Method to display component info
1644
	 *
1645
	 * @param   JInstallerAdapter  $parent   Class calling this method
1646
	 * @param   string             $message  Message to apply to the Component info layout
1647
	 *
1648
	 * @return  void
1649
	 */
1650
	public function displayComponentInfo($parent, $message = '')
1651
	{
1652
		$this->loadRedcoreLibrary();
1653
1654
		if ($this->showComponentInfo && method_exists('RComponentHelper', 'displayComponentInfo'))
1655
		{
1656
			$manifest = $this->getManifest($parent);
1657
			echo RComponentHelper::displayComponentInfo((string) $manifest->name, $message);
1658
		}
1659
	}
1660
1661
	/**
1662
	 * Load redCORE component language file
1663
	 *
1664
	 * @param   string  $path  Path to the language folder
1665
	 *
1666
	 * @return  void
1667
	 */
1668
	public function loadRedcoreLanguage($path = JPATH_ADMINISTRATOR)
1669
	{
1670
		// Load common and local language files.
1671
		$lang = JFactory::getLanguage();
1672
1673
		// Load language file
1674
		$lang->load('com_redcore', $path, null, true, true)
1675
		|| $lang->load('com_redcore', $path . '/components/com_redcore', null, true, true)
1676
		|| $lang->load('com_redcore', $path . '/components/com_redcore/admin', null, true, true);
1677
	}
1678
1679
	/**
1680
	 * Load redCORE library
1681
	 *
1682
	 * @return  void
1683
	 */
1684
	public function loadRedcoreLibrary()
1685
	{
1686
		$redcoreLoader = JPATH_LIBRARIES . '/redcore/bootstrap.php';
1687
1688
		if (file_exists($redcoreLoader))
1689
		{
1690
			require_once $redcoreLoader;
1691
1692
			RBootstrap::bootstrap(false);
1693
		}
1694
	}
1695
1696
	/**
1697
	 * Checks version of the extension and returns
1698
	 *
1699
	 * @param   string  $original  Original path
1700
	 * @param   string  $source    Install path
1701
	 * @param   string  $xmlFile   Component filename
1702
	 *
1703
	 * @return  boolean  Returns true if current version is lower or equal or if that extension do not exist
1704
	 * @throws  Exception
1705
	 */
1706
	public function checkComponentVersion($original, $source, $xmlFile)
1707
	{
1708
		if (is_dir($original))
1709
		{
1710
			try
1711
			{
1712
				$source      = $source . '/' . $xmlFile;
1713
				$sourceXml   = new SimpleXMLElement($source, 0, true);
1714
				$original    = $original . '/' . $xmlFile;
1715
				$originalXml = new SimpleXMLElement($original, 0, true);
1716
1717
				if (version_compare((string) $sourceXml->version, (string) $originalXml->version, '<'))
1718
				{
1719
					return false;
1720
				}
1721
			}
1722
			catch (Exception $e)
1723
			{
1724
				JFactory::getApplication()->enqueueMessage(
1725
					JText::_('COM_REDCORE_INSTALL_UNABLE_TO_CHECK_VERSION'),
1726
					'message'
1727
				);
1728
			}
1729
		}
1730
1731
		return true;
1732
	}
1733
1734
	/**
1735
	 * Gets or generates the element name (using the manifest)
1736
	 *
1737
	 * @param   JInstallerAdapter  $parent    Parent adapter
1738
	 * @param   SimpleXMLElement   $manifest  Extension manifest
1739
	 *
1740
	 * @return  string  Element
1741
	 */
1742
	public function getElement($parent, $manifest = null)
1743
	{
1744
		if (method_exists($parent, 'getElement'))
1745
		{
1746
			return $parent->getElement();
1747
		}
1748
1749
		if (null === $manifest)
1750
		{
1751
			$manifest = $parent->get('manifest');
1752
		}
1753
1754
		if (isset($manifest->element))
1755
		{
1756
			$element = (string) $manifest->element;
1757
		}
1758
		else
1759
		{
1760
			$element = (string) $manifest->name;
1761
		}
1762
1763
		// Filter the name for illegal characters
1764
		return strtolower(JFilterInput::getInstance()->clean($element, 'cmd'));
1765
	}
1766
1767
	/**
1768
	 * Gets the path of redCORE component
1769
	 *
1770
	 * @return  string
1771
	 */
1772
	public function getRedcoreComponentFolder()
1773
	{
1774
		return JPATH_ADMINISTRATOR . '/components/com_redcore';
1775
	}
1776
1777
	/**
1778
	 * Shit happens. Patched function to bypass bug in package uninstaller
1779
	 *
1780
	 * @param   JInstallerAdapter  $parent  Parent object
1781
	 *
1782
	 * @return  void
1783
	 */
1784
	protected function loadManifest($parent)
1785
	{
1786
		$element      = strtolower(str_replace('InstallerScript', '', get_called_class()));
1787
		$elementParts = explode('_', $element);
1788
1789
		// Type not properly detected or not a package
1790
		if (count($elementParts) !== 2 || strtolower($elementParts[0]) !== 'pkg')
1791
		{
1792
			$this->manifest = $parent->get('manifest');
1793
1794
			return;
1795
		}
1796
1797
		$rootPath     = $parent->getParent()->getPath('extension_root');
1798
		$manifestPath = dirname($rootPath);
1799
		$manifestFile = $manifestPath . '/' . $element . '.xml';
1800
1801
		// Package manifest found
1802
		if (file_exists($manifestFile))
1803
		{
1804
			$this->manifest = new SimpleXMLElement($manifestFile);
1805
1806
			return;
1807
		}
1808
1809
		$this->manifest = $parent->get('manifest');
1810
	}
1811
1812
	/**
1813
	 * Setup site url for redCORE config
1814
	 *
1815
	 * @return  void
1816
	 */
1817
	private function insertSiteDomain()
1818
	{
1819
		$db    = JFactory::getDbo();
1820
		$query = $db->getQuery(true)
1821
			->select($db->qn('extension_id'))
1822
			->from($db->qn('#__extensions'))
1823
			->where($db->qn('type') . ' = ' . $db->q('component'))
1824
			->where($db->qn('element') . ' = ' . $db->q('com_redcore'));
1825
1826
		$extensionId = $db->setQuery($query)->loadResult();
1827
1828
		if (!$extensionId)
1829
		{
1830
			return;
1831
		}
1832
1833
		/** @var JTableExtension $table */
1834
		$table = JTable::getInstance('Extension', 'JTable');
1835
1836
		if (!$table->load($extensionId))
1837
		{
1838
			return;
1839
		}
1840
1841
		$params = new Registry($table->get('params'));
1842
1843
		// Skip update if already exist
1844
		if ($params->get('domain', ''))
1845
		{
1846
			return;
1847
		}
1848
1849
		$params->set('domain', $_SERVER['SERVER_NAME']);
1850
		$table->set('params', $params->toString());
1851
		$table->store();
1852
	}
1853
}
1854