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