TYPO3  7.6
ExtensionManagementService.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Service;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 
26 {
30  protected $downloadQueue;
31 
35  protected $dependencyUtility;
36 
40  protected $installUtility;
41 
46 
50  protected $downloadUtility;
51 
56 
60  protected $skipDependencyCheck = false;
61 
65  public function injectDownloadQueue(\TYPO3\CMS\Extensionmanager\Domain\Model\DownloadQueue $downloadQueue)
66  {
67  $this->downloadQueue = $downloadQueue;
68  }
69 
73  public function injectDependencyUtility(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility)
74  {
75  $this->dependencyUtility = $dependencyUtility;
76  }
77 
81  public function injectInstallUtility(\TYPO3\CMS\Extensionmanager\Utility\InstallUtility $installUtility)
82  {
83  $this->installUtility = $installUtility;
84  }
85 
89  public function injectExtensionModelUtility(\TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility $extensionModelUtility)
90  {
91  $this->extensionModelUtility = $extensionModelUtility;
92  }
93 
97  public function injectDownloadUtility(\TYPO3\CMS\Extensionmanager\Utility\DownloadUtility $downloadUtility)
98  {
99  $this->downloadUtility = $downloadUtility;
100  }
101 
106  public function markExtensionForInstallation($extensionKey)
107  {
108  // We have to check for dependencies of the extension first, before marking it for installation
109  // because this extension might have dependencies, which need to be installed first
110  $this->installUtility->reloadAvailableExtensions();
111  $extension = $this->getExtension($extensionKey);
112  $this->dependencyUtility->checkDependencies($extension);
113  $this->downloadQueue->addExtensionToInstallQueue($extension);
114  }
115 
123  public function markExtensionForCopy($extensionKey, $sourceFolder)
124  {
125  $this->downloadQueue->addExtensionToCopyQueue($extensionKey, $sourceFolder);
126  }
127 
134  public function markExtensionForDownload(Extension $extension)
135  {
136  // We have to check for dependencies of the extension first, before marking it for download
137  // because this extension might have dependencies, which need to be downloaded and installed first
138  $this->dependencyUtility->checkDependencies($extension);
139  if (!$this->dependencyUtility->hasDependencyErrors()) {
140  $this->downloadQueue->addExtensionToQueue($extension);
141  }
142  }
143 
148  public function markExtensionForUpdate(Extension $extension)
149  {
150  // We have to check for dependencies of the extension first, before marking it for download
151  // because this extension might have dependencies, which need to be downloaded and installed first
152  $this->dependencyUtility->checkDependencies($extension);
153  $this->downloadQueue->addExtensionToQueue($extension, 'update');
154  }
155 
162  {
163  $this->skipDependencyCheck = $skipDependencyCheck;
164  }
165 
170  {
171  $this->automaticInstallationEnabled = (bool)$automaticInstallationEnabled;
172  }
173 
180  public function installExtension(Extension $extension)
181  {
182  $this->downloadExtension($extension);
183  if (!$this->checkDependencies($extension)) {
184  return false;
185  }
186 
187  $updatedDependencies = array();
188  $installedDependencies = array();
189  $queue = $this->downloadQueue->getExtensionQueue();
190  $copyQueue = $this->downloadQueue->getExtensionCopyStorage();
191 
192  if (!empty($copyQueue)) {
193  $this->copyDependencies($copyQueue);
194  }
195  $downloadedDependencies = array();
196  if (array_key_exists('download', $queue)) {
197  $downloadedDependencies = $this->downloadDependencies($queue['download']);
198  }
199  if ($this->automaticInstallationEnabled) {
200  if (array_key_exists('update', $queue)) {
201  $this->downloadDependencies($queue['update']);
202  $updatedDependencies = $this->uninstallDependenciesToBeUpdated($queue['update']);
203  }
204  // add extension at the end of the download queue
205  $this->downloadQueue->addExtensionToInstallQueue($extension);
206  $installQueue = $this->downloadQueue->getExtensionInstallStorage();
207  if (!empty($installQueue)) {
208  $installedDependencies = $this->installDependencies($installQueue);
209  }
210  }
211  return array_merge($downloadedDependencies, $updatedDependencies, $installedDependencies);
212  }
213 
219  public function getDependencyErrors()
220  {
221  return $this->dependencyUtility->getDependencyErrors();
222  }
223 
229  public function getExtension($extensionKey)
230  {
231  return $this->extensionModelUtility->mapExtensionArrayToModel(
232  $this->installUtility->enrichExtensionWithDetails($extensionKey)
233  );
234  }
235 
242  public function isAvailable($extensionKey)
243  {
244  return $this->installUtility->isAvailable($extensionKey);
245  }
246 
254  public function reloadPackageInformation($extensionKey)
255  {
256  $this->installUtility->reloadPackageInformation($extensionKey);
257  }
258 
264  protected function downloadExtension(Extension $extension)
265  {
266  $this->downloadMainExtension($extension);
267  $this->setInExtensionRepository($extension->getExtensionKey());
268  }
269 
276  protected function checkDependencies(Extension $extension)
277  {
278  $this->dependencyUtility->setSkipDependencyCheck($this->skipDependencyCheck);
279  $this->dependencyUtility->checkDependencies($extension);
280 
281  return !$this->dependencyUtility->hasDependencyErrors();
282  }
283 
291  protected function setInExtensionRepository($extensionKey)
292  {
294  $path = $paths[$this->downloadUtility->getDownloadPath()];
295  $localExtensionStorage = $path . $extensionKey . '/Initialisation/Extensions/';
296  $this->dependencyUtility->setLocalExtensionStorage($localExtensionStorage);
297  }
298 
305  protected function copyDependencies(array $copyQueue)
306  {
307  $installPaths = Extension::returnAllowedInstallPaths();
308  foreach ($copyQueue as $extensionKey => $sourceFolder) {
309  $destination = $installPaths['Local'] . $extensionKey;
310  GeneralUtility::mkdir($destination);
311  GeneralUtility::copyDirectory($sourceFolder . $extensionKey, $destination);
312  $this->markExtensionForInstallation($extensionKey);
313  $this->downloadQueue->removeExtensionFromCopyQueue($extensionKey);
314  }
315  }
316 
324  protected function uninstallDependenciesToBeUpdated(array $updateQueue)
325  {
326  $resolvedDependencies = array();
327  foreach ($updateQueue as $extensionToUpdate) {
328  $this->installUtility->uninstall($extensionToUpdate->getExtensionKey());
329  $resolvedDependencies['updated'][$extensionToUpdate->getExtensionKey()] = $extensionToUpdate;
330  }
331  return $resolvedDependencies;
332  }
333 
340  protected function installDependencies(array $installQueue)
341  {
342  if (!empty($installQueue)) {
343  $this->emitWillInstallExtensionsSignal($installQueue);
344  }
345  $resolvedDependencies = array();
346  foreach ($installQueue as $extensionKey => $_) {
347  $this->installUtility->install($extensionKey);
348  $this->emitHasInstalledExtensionSignal($extensionKey);
349  if (!is_array($resolvedDependencies['installed'])) {
350  $resolvedDependencies['installed'] = array();
351  }
352  $resolvedDependencies['installed'][$extensionKey] = $extensionKey;
353  }
354  return $resolvedDependencies;
355  }
356 
364  protected function downloadDependencies(array $downloadQueue)
365  {
366  $resolvedDependencies = array();
367  foreach ($downloadQueue as $extensionToDownload) {
368  $this->downloadUtility->download($extensionToDownload);
369  $this->downloadQueue->removeExtensionFromQueue($extensionToDownload);
370  $resolvedDependencies['downloaded'][$extensionToDownload->getExtensionKey()] = $extensionToDownload;
371  $this->markExtensionForInstallation($extensionToDownload->getExtensionKey());
372  }
373  return $resolvedDependencies;
374  }
375 
382  public function getAndResolveDependencies(Extension $extension)
383  {
384  $this->dependencyUtility->setSkipDependencyCheck($this->skipDependencyCheck);
385  $this->dependencyUtility->checkDependencies($extension);
386  $installQueue = $this->downloadQueue->getExtensionInstallStorage();
387  if (is_array($installQueue) && !empty($installQueue)) {
388  $installQueue = array('install' => $installQueue);
389  }
390  return array_merge($this->downloadQueue->getExtensionQueue(), $installQueue);
391  }
392 
401  public function downloadMainExtension(Extension $extension)
402  {
403  // The extension object has a uid if the extension is not present in the system
404  // or an update of a present extension is triggered.
405  if ($extension->getUid()) {
406  $this->downloadUtility->download($extension);
407  }
408  }
409 
413  protected function emitWillInstallExtensionsSignal(array $installQueue)
414  {
415  $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'willInstallExtensions', array($installQueue));
416  }
417 
421  protected function emitHasInstalledExtensionSignal($extensionKey)
422  {
423  $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'hasInstalledExtensions', array($extensionKey));
424  }
425 
431  protected function getSignalSlotDispatcher()
432  {
433  if (!isset($this->signalSlotDispatcher)) {
434  $this->signalSlotDispatcher = GeneralUtility::makeInstance(ObjectManager::class)
435  ->get(Dispatcher::class);
436  }
438  }
439 }