71a6bed1827d4f1771f38e0869190068998059f0
[GitHub/WoltLab/WCF.git] /
1 <?php
2 namespace wcf\data\package\installation\plugin;
3 use wcf\data\devtools\project\DevtoolsProject;
4 use wcf\data\AbstractDatabaseObjectAction;
5 use wcf\system\cache\CacheHandler;
6 use wcf\system\devtools\pip\DevtoolsPackageInstallationDispatcher;
7 use wcf\system\devtools\pip\DevtoolsPip;
8 use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin;
9 use wcf\system\exception\PermissionDeniedException;
10 use wcf\system\exception\UserInputException;
11 use wcf\system\language\LanguageFactory;
12 use wcf\system\package\SplitNodeException;
13 use wcf\system\search\SearchIndexManager;
14 use wcf\system\version\VersionTracker;
15 use wcf\system\WCF;
16
17 /**
18 * Executes package installation plugin-related actions.
19 *
20 * @author Alexander Ebert
21 * @copyright 2001-2017 WoltLab GmbH
22 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
23 * @package WoltLabSuite\Core\Data\Package\Installation\Plugin
24 *
25 * @method PackageInstallationPlugin create()
26 * @method PackageInstallationPluginEditor[] getObjects()
27 * @method PackageInstallationPluginEditor getSingleObject()
28 */
29 class PackageInstallationPluginAction extends AbstractDatabaseObjectAction {
30 /**
31 * @inheritDoc
32 */
33 protected $className = PackageInstallationPluginEditor::class;
34
35 /**
36 * @inheritDoc
37 */
38 protected $requireACP = ['invoke'];
39
40 /**
41 * @var DevtoolsPip
42 */
43 public $devtoolsPip;
44
45 /**
46 * @var PackageInstallationPlugin
47 */
48 public $packageInstallationPlugin;
49
50 /**
51 * @var DevtoolsProject
52 */
53 public $project;
54
55 /**
56 * Validates parameters to invoke a single PIP.
57 *
58 * @throws PermissionDeniedException
59 * @throws UserInputException
60 */
61 public function validateInvoke() {
62 if (!ENABLE_DEVELOPER_TOOLS || !WCF::getSession()->getPermission('admin.configuration.package.canInstallPackage')) {
63 throw new PermissionDeniedException();
64 }
65
66 $this->readString('pluginName');
67 $this->readInteger('projectID');
68 $this->readString('target');
69
70 $this->project = new DevtoolsProject($this->parameters['projectID']);
71 if (!$this->project->projectID || $this->project->validate() !== '') {
72 throw new UserInputException('projectID');
73 }
74
75 $this->packageInstallationPlugin = new PackageInstallationPlugin($this->parameters['pluginName']);
76 if (!$this->packageInstallationPlugin->pluginName) {
77 throw new UserInputException('pluginName');
78 }
79
80 $this->devtoolsPip = new DevtoolsPip($this->packageInstallationPlugin);
81 $targets = $this->devtoolsPip->getTargets($this->project);
82 if (!in_array($this->parameters['target'], $targets)) {
83 throw new UserInputException('target');
84 }
85 }
86
87 /**
88 * Invokes a single PIP and returns the time needed to process it.
89 *
90 * @return string[]
91 */
92 public function invoke() {
93 $dispatcher = new DevtoolsPackageInstallationDispatcher($this->project);
94 /** @var IIdempotentPackageInstallationPlugin $pip */
95 $pip = new $this->packageInstallationPlugin->className(
96 $dispatcher,
97 $this->devtoolsPip->getInstructions($this->project, $this->parameters['target'])
98 );
99
100 $start = microtime(true);
101
102 try {
103 $pip->update();
104 }
105 catch (SplitNodeException $e) {
106 throw new \RuntimeException("PIP '{$this->packageInstallationPlugin->pluginName}' is not allowed to throw a 'SplitNodeException'.");
107 }
108
109 // clear cache
110
111 // TODO: use a central method instead!
112
113 // create search index tables
114 SearchIndexManager::getInstance()->createSearchIndices();
115
116 VersionTracker::getInstance()->createStorageTables();
117
118 CacheHandler::getInstance()->flushAll();
119
120 if ($this->packageInstallationPlugin->pluginName === 'language') {
121 LanguageFactory::getInstance()->clearCache();
122 LanguageFactory::getInstance()->deleteLanguageCache();
123 }
124
125 return [
126 'pluginName' => $this->packageInstallationPlugin->pluginName,
127 'target' => $this->parameters['target'],
128 'timeElapsed' => WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.sync.status.success', ['timeElapsed' => round(microtime(true) - $start, 3)])
129 ];
130 }
131 }