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