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