2 namespace wcf\system\package\plugin
;
3 use wcf\data\cronjob\Cronjob
;
4 use wcf\data\cronjob\CronjobEditor
;
5 use wcf\system\cronjob\ICronjob
;
6 use wcf\system\devtools\pip\IDevtoolsPipEntryList
;
7 use wcf\system\devtools\pip\IGuiPackageInstallationPlugin
;
8 use wcf\system\devtools\pip\TXmlGuiPackageInstallationPlugin
;
9 use wcf\system\exception\SystemException
;
10 use wcf\system\form\builder\container\IFormContainer
;
11 use wcf\system\form\builder\field\BooleanFormField
;
12 use wcf\system\form\builder\field\ClassNameFormField
;
13 use wcf\system\form\builder\field\OptionFormField
;
14 use wcf\system\form\builder\field\TextFormField
;
15 use wcf\system\form\builder\field\validation\FormFieldValidationError
;
16 use wcf\system\form\builder\field\validation\FormFieldValidator
;
17 use wcf\system\form\builder\IFormDocument
;
18 use wcf\system\language\LanguageFactory
;
20 use wcf\util\CronjobUtil
;
21 use wcf\util\StringUtil
;
24 * Installs, updates and deletes cronjobs.
26 * @author Alexander Ebert, Matthias Schmidt
27 * @copyright 2001-2018 WoltLab GmbH
28 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
29 * @package WoltLabSuite\Core\Acp\Package\Plugin
31 class CronjobPackageInstallationPlugin
extends AbstractXMLPackageInstallationPlugin
implements IGuiPackageInstallationPlugin
{
32 use TXmlGuiPackageInstallationPlugin
;
37 public $className = CronjobEditor
::class;
42 protected function getElement(\DOMXPath
$xpath, array &$elements, \DOMElement
$element) {
43 if ($element->tagName
== 'description') {
44 if (!isset($elements['description'])) {
45 $elements['description'] = [];
48 $elements['description'][$element->getAttribute('language')] = $element->nodeValue
;
51 parent
::getElement($xpath, $elements, $element);
58 protected function handleDelete(array $items) {
59 $sql = "DELETE FROM wcf".WCF_N
."_".$this->tableName
."
62 $legacyStatement = WCF
::getDB()->prepareStatement($sql);
64 $sql = "DELETE FROM wcf".WCF_N
."_".$this->tableName
."
67 $statement = WCF
::getDB()->prepareStatement($sql);
69 foreach ($items as $item) {
70 if (!isset($item['attributes']['name'])) {
71 $legacyStatement->execute([
72 $item['elements']['classname'],
73 $this->installation
->getPackageID()
78 $item['attributes']['name'],
79 $this->installation
->getPackageID()
88 protected function prepareImport(array $data) {
90 'canBeDisabled' => isset($data['elements']['canbedisabled']) ?
intval($data['elements']['canbedisabled']) : 1,
91 'canBeEdited' => isset($data['elements']['canbeedited']) ?
intval($data['elements']['canbeedited']) : 1,
92 'className' => isset($data['elements']['classname']) ?
$data['elements']['classname'] : '',
93 'cronjobName' => isset($data['attributes']['name']) ?
$data['attributes']['name'] : '',
94 'description' => isset($data['elements']['description']) ?
$data['elements']['description'] : '',
95 'isDisabled' => isset($data['elements']['isdisabled']) ?
intval($data['elements']['isdisabled']) : 0,
96 'options' => isset($data['elements']['options']) ? StringUtil
::normalizeCsv($data['elements']['options']) : '',
97 'startDom' => $data['elements']['startdom'],
98 'startDow' => $data['elements']['startdow'],
99 'startHour' => $data['elements']['starthour'],
100 'startMinute' => $data['elements']['startminute'],
101 'startMonth' => $data['elements']['startmonth']
108 protected function validateImport(array $data) {
109 CronjobUtil
::validate($data['startMinute'], $data['startHour'], $data['startDom'], $data['startMonth'], $data['startDow']);
115 protected function import(array $row, array $data) {
116 // if a cronjob is updated without a name given, keep the old automatically
118 if (!empty($row) && !$data['cronjobName']) {
119 unset($data['cronjobName']);
122 /** @var Cronjob $cronjob */
123 $cronjob = parent
::import($row, $data);
125 // update cronjob name
126 if (!$cronjob->cronjobName
) {
127 $cronjobEditor = new CronjobEditor($cronjob);
128 $cronjobEditor->update([
129 'cronjobName' => Cronjob
::AUTOMATIC_NAME_PREFIX
.$cronjob->cronjobID
132 $cronjob = new Cronjob($cronjob->cronjobID
);
141 protected function findExistingItem(array $data) {
142 if (!$data['cronjobName']) return null;
145 FROM wcf".WCF_N
."_".$this->tableName
."
147 AND cronjobName = ?";
149 $this->installation
->getPackageID(),
155 'parameters' => $parameters
162 protected function prepareCreate(array &$data) {
163 parent
::prepareCreate($data);
165 $data['nextExec'] = TIME_NOW
;
172 public static function getSyncDependencies() {
180 protected function addFormFields(IFormDocument
$form) {
181 /** @var IFormContainer $dataContainer */
182 $dataContainer = $form->getNodeById('data');
184 $dataContainer->appendChildren([
185 TextFormField
::create('cronjobName')
186 ->objectProperty('name')
187 ->label('wcf.acp.pip.cronjob.cronjobName')
188 ->description('wcf.acp.pip.cronjob.cronjobName.description')
191 TextFormField
::create('description')
192 ->label('wcf.global.description')
193 ->description('wcf.acp.pip.cronjob.description.description')
195 ->languageItemPattern('__NONE__'),
197 ClassNameFormField
::create()
198 ->objectProperty('classname')
199 ->implementedInterface(ICronjob
::class)
202 OptionFormField
::create()
203 ->description('wcf.acp.pip.cronjob.options.description'),
205 BooleanFormField
::create('isDisabled')
206 ->objectProperty('isdisabled')
207 ->label('wcf.acp.pip.cronjob.isDisabled')
208 ->description('wcf.acp.pip.cronjob.isDisabled.description'),
210 BooleanFormField
::create('canBeEdited')
211 ->objectProperty('canbeedited')
212 ->label('wcf.acp.pip.cronjob.canBeEdited')
213 ->description('wcf.acp.pip.cronjob.canBeEdited.description')
216 BooleanFormField
::create('canBeDisabled')
217 ->objectProperty('canbedisabled')
218 ->label('wcf.acp.pip.cronjob.canBeDisabled')
219 ->description('wcf.acp.pip.cronjob.canBeDisabled.description')
223 foreach (['startDom', 'startDow', 'startHour', 'startMinute', 'startMonth'] as $timeProperty) {
224 $dataContainer->insertBefore(
225 TextFormField
::create($timeProperty)
226 ->objectProperty(strtolower($timeProperty))
227 ->label('wcf.acp.cronjob.' . $timeProperty)
228 ->description("wcf.acp.cronjob.{$timeProperty}.description")
230 ->addValidator(new FormFieldValidator('format', function(TextFormField
$formField) use ($timeProperty) {
232 CronjobUtil
::validateAttribute($timeProperty, $formField->getSaveValue());
234 catch (SystemException
$e) {
235 $formField->addValidationError(
236 new FormFieldValidationError(
238 "wcf.acp.pip.cronjob.{$timeProperty}.error.format"
252 protected function doGetElementData(\DOMElement
$element, $saveData) {
254 'className' => $element->getElementsByTagName('classname')->item(0)->nodeValue
,
255 'cronjobName' => $element->getAttribute('name'),
257 'packageID' => $this->installation
->getPackage()->packageID
,
258 'startDom' => $element->getElementsByTagName('startdom')->item(0)->nodeValue
,
259 'startDow' => $element->getElementsByTagName('startdow')->item(0)->nodeValue
,
260 'startHour' => $element->getElementsByTagName('starthour')->item(0)->nodeValue
,
261 'startMinute' => $element->getElementsByTagName('startminute')->item(0)->nodeValue
,
262 'startMonth' => $element->getElementsByTagName('startmonth')->item(0)->nodeValue
265 $canBeDisabled = $element->getElementsByTagName('canbedisabled')->item(0);
266 if ($canBeDisabled !== null) {
267 $data['canBeDisabled'] = $canBeDisabled->nodeValue
;
270 $descriptionElements = $element->getElementsByTagName('description');
273 /** @var \DOMElement $description */
274 foreach ($descriptionElements as $description) {
275 $descriptions[$description->getAttribute('language')] = $description->nodeValue
;
278 foreach (LanguageFactory
::getInstance()->getLanguages() as $language) {
279 if (!empty($descriptions)) {
280 if (isset($descriptions[$language->languageCode
])) {
281 $data['description'][$language->languageID
] = $descriptions[$language->languageCode
];
283 else if (isset($descriptions[''])) {
284 $data['description'][$language->languageID
] = $descriptions[''];
286 else if (isset($descriptions['en'])) {
287 $data['description'][$language->languageID
] = $descriptions['en'];
289 else if (isset($descriptions[WCF
::getLanguage()->getFixedLanguageCode()])) {
290 $data['description'][$language->languageID
] = $descriptions[WCF
::getLanguage()->getFixedLanguageCode()];
293 $data['description'][$language->languageID
] = reset($descriptions);
297 $data['description'][$language->languageID
] = '';
301 $canBeEdited = $element->getElementsByTagName('canbeedited')->item(0);
302 if ($canBeEdited !== null) {
303 $data['canBeDisabled'] = $canBeEdited->nodeValue
;
306 $isDisabled = $element->getElementsByTagName('isdisabled')->item(0);
307 if ($isDisabled !== null) {
308 $data['canBeDisabled'] = $isDisabled->nodeValue
;
318 public function getElementIdentifier(\DOMElement
$element) {
319 return $element->getAttribute('name');
326 protected function setEntryListKeys(IDevtoolsPipEntryList
$entryList) {
327 $entryList->setKeys([
328 'cronjobName' => 'wcf.acp.pip.cronjob.cronjobName',
329 'className' => 'wcf.form.field.className'
337 protected function doCreateXmlElement(\DOMDocument
$document, IFormDocument
$form) {
338 $data = $form->getData();
339 $formData = $form->getData()['data'];
341 $cronjob = $document->createElement($this->tagName
);
342 $cronjob->setAttribute('name', $formData['name']);
343 $cronjob->appendChild($document->createElement('classname', $formData['classname']));
345 if (isset($formData['description'])) {
346 if ($formData['description'] !== '') {
347 $cronjob->appendChild($document->createElement('description', $formData['description']));
350 else if (isset($data['description_i18n'])) {
351 /** @var \DOMElement $firstDescription */
352 $firstDescription = null;
353 foreach ($data['description_i18n'] as $languageItem => $description) {
354 if ($description !== '') {
355 $descriptionElement = $document->createElement('description', $description);
356 $languageCode = LanguageFactory
::getInstance()->getLanguage($languageItem)->languageCode
;
357 if ($languageCode !== 'en') {
358 $descriptionElement->setAttribute('language', $languageCode);
359 $cronjob->appendChild($descriptionElement);
361 else if ($firstDescription === null) {
362 $cronjob->appendChild($descriptionElement);
365 // default description should be shown first
366 $cronjob->insertBefore($descriptionElement, $firstDescription);
369 if ($firstDescription === null) {
370 $firstDescription = $descriptionElement;
376 $this->appendElementChildren(
386 'canbedisabled' => 1,