Commit | Line | Data |
---|---|---|
a5a4f02d | 1 | <?php |
308c880f | 2 | declare(strict_types=1); |
a5a4f02d | 3 | namespace wcf\data\article; |
8ff79ba2 | 4 | use wcf\data\article\category\ArticleCategory; |
a5a4f02d | 5 | use wcf\data\article\content\ArticleContent; |
70ecac8c | 6 | use wcf\data\article\content\ArticleContentAction; |
a5a4f02d | 7 | use wcf\data\article\content\ArticleContentEditor; |
70ecac8c | 8 | use wcf\data\language\Language; |
9c97b595 | 9 | use wcf\data\AbstractDatabaseObjectAction; |
8ff79ba2 | 10 | use wcf\system\clipboard\ClipboardHandler; |
2fd812d7 | 11 | use wcf\system\comment\CommentHandler; |
a81168d4 | 12 | use wcf\system\exception\UserInputException; |
a5a4f02d | 13 | use wcf\system\language\LanguageFactory; |
2fd812d7 | 14 | use wcf\system\like\LikeHandler; |
ef17c746 | 15 | use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; |
402a1169 | 16 | use wcf\system\request\LinkHandler; |
2fd812d7 | 17 | use wcf\system\search\SearchIndexManager; |
a5a4f02d | 18 | use wcf\system\tagging\TagEngine; |
ce6f758b | 19 | use wcf\system\user\storage\UserStorageHandler; |
3bd00cc5 | 20 | use wcf\system\version\VersionTracker; |
ce6f758b | 21 | use wcf\system\visitTracker\VisitTracker; |
a81168d4 | 22 | use wcf\system\WCF; |
a5a4f02d MW |
23 | |
24 | /** | |
25 | * Executes article related actions. | |
26 | * | |
27 | * @author Marcel Werk | |
c839bd49 | 28 | * @copyright 2001-2018 WoltLab GmbH |
a5a4f02d | 29 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
e71525e4 MW |
30 | * @package WoltLabSuite\Core\Data\Article |
31 | * @since 3.0 | |
a5a4f02d MW |
32 | * |
33 | * @method ArticleEditor[] getObjects() | |
34 | * @method ArticleEditor getSingleObject() | |
35 | */ | |
36 | class ArticleAction extends AbstractDatabaseObjectAction { | |
a81168d4 AE |
37 | /** |
38 | * article editor instance | |
39 | * @var ArticleEditor | |
40 | */ | |
41 | public $articleEditor; | |
42 | ||
70ecac8c AE |
43 | /** |
44 | * language object | |
45 | * @var Language | |
46 | */ | |
47 | public $language; | |
48 | ||
a5a4f02d MW |
49 | /** |
50 | * @inheritDoc | |
51 | */ | |
52 | protected $className = ArticleEditor::class; | |
53 | ||
54 | /** | |
55 | * @inheritDoc | |
56 | */ | |
57 | protected $permissionsCreate = ['admin.content.article.canManageArticle']; | |
58 | ||
59 | /** | |
60 | * @inheritDoc | |
61 | */ | |
62 | protected $permissionsDelete = ['admin.content.article.canManageArticle']; | |
63 | ||
64 | /** | |
65 | * @inheritDoc | |
66 | */ | |
67 | protected $permissionsUpdate = ['admin.content.article.canManageArticle']; | |
68 | ||
69 | /** | |
70 | * @inheritDoc | |
71 | */ | |
70ecac8c | 72 | protected $requireACP = ['create', 'delete', 'restore', 'toggleI18n', 'trash', 'update']; |
a5a4f02d | 73 | |
ce6f758b MW |
74 | /** |
75 | * @inheritDoc | |
76 | */ | |
77 | protected $allowGuestAccess = ['markAllAsRead']; | |
78 | ||
a5a4f02d MW |
79 | /** |
80 | * @inheritDoc | |
81 | * @return Article | |
82 | */ | |
83 | public function create() { | |
84 | /** @var Article $article */ | |
85 | $article = parent::create(); | |
86 | ||
87 | // save article content | |
88 | if (!empty($this->parameters['content'])) { | |
89 | foreach ($this->parameters['content'] as $languageID => $content) { | |
ef17c746 MW |
90 | if (!empty($content['htmlInputProcessor'])) { |
91 | /** @noinspection PhpUndefinedMethodInspection */ | |
92 | $content['content'] = $content['htmlInputProcessor']->getHtml(); | |
93 | } | |
94 | ||
2fd812d7 | 95 | /** @var ArticleContent $articleContent */ |
a5a4f02d MW |
96 | $articleContent = ArticleContentEditor::create([ |
97 | 'articleID' => $article->articleID, | |
63b9817b | 98 | 'languageID' => $languageID ?: null, |
a5a4f02d MW |
99 | 'title' => $content['title'], |
100 | 'teaser' => $content['teaser'], | |
101 | 'content' => $content['content'], | |
79305986 MW |
102 | 'imageID' => $content['imageID'], |
103 | 'teaserImageID' => $content['teaserImageID'] | |
a5a4f02d | 104 | ]); |
ef17c746 | 105 | $articleContentEditor = new ArticleContentEditor($articleContent); |
a5a4f02d MW |
106 | |
107 | // save tags | |
108 | if (!empty($content['tags'])) { | |
109 | TagEngine::getInstance()->addObjectTags('com.woltlab.wcf.article', $articleContent->articleContentID, $content['tags'], ($languageID ?: LanguageFactory::getInstance()->getDefaultLanguageID())); | |
110 | } | |
2fd812d7 MW |
111 | |
112 | // update search index | |
e5adfbe2 MS |
113 | SearchIndexManager::getInstance()->set( |
114 | 'com.woltlab.wcf.article', | |
115 | $articleContent->articleContentID, | |
116 | $articleContent->content, | |
117 | $articleContent->title, | |
118 | $article->time, | |
119 | $article->userID, | |
120 | $article->username, | |
121 | $languageID ?: null, | |
122 | $articleContent->teaser | |
123 | ); | |
ef17c746 MW |
124 | |
125 | // save embedded objects | |
126 | if (!empty($content['htmlInputProcessor'])) { | |
2f273839 MW |
127 | /** @noinspection PhpUndefinedMethodInspection */ |
128 | $content['htmlInputProcessor']->setObjectID($articleContent->articleContentID); | |
bfb52dd9 | 129 | if (MessageEmbeddedObjectManager::getInstance()->registerObjects($content['htmlInputProcessor'])) { |
ef17c746 MW |
130 | $articleContentEditor->update(['hasEmbeddedObjects' => 1]); |
131 | } | |
132 | } | |
a5a4f02d MW |
133 | } |
134 | } | |
135 | ||
ce6f758b MW |
136 | // reset storage |
137 | if (ARTICLE_ENABLE_VISIT_TRACKING) { | |
138 | UserStorageHandler::getInstance()->resetAll('unreadArticles'); | |
139 | } | |
140 | ||
a5a4f02d MW |
141 | return $article; |
142 | } | |
143 | ||
144 | /** | |
145 | * @inheritDoc | |
146 | */ | |
147 | public function update() { | |
148 | parent::update(); | |
149 | ||
1bee099c AE |
150 | $isRevert = (!empty($this->parameters['isRevert'])); |
151 | ||
a5a4f02d MW |
152 | // update article content |
153 | if (!empty($this->parameters['content'])) { | |
154 | foreach ($this->getObjects() as $article) { | |
3bd00cc5 AE |
155 | $versionData = []; |
156 | $hasChanges = false; | |
157 | ||
a5a4f02d | 158 | foreach ($this->parameters['content'] as $languageID => $content) { |
ef17c746 MW |
159 | if (!empty($content['htmlInputProcessor'])) { |
160 | /** @noinspection PhpUndefinedMethodInspection */ | |
161 | $content['content'] = $content['htmlInputProcessor']->getHtml(); | |
162 | } | |
163 | ||
a5a4f02d | 164 | $articleContent = ArticleContent::getArticleContent($article->articleID, ($languageID ?: null)); |
ef17c746 | 165 | $articleContentEditor = null; |
a5a4f02d MW |
166 | if ($articleContent !== null) { |
167 | // update | |
ef17c746 MW |
168 | $articleContentEditor = new ArticleContentEditor($articleContent); |
169 | $articleContentEditor->update([ | |
a5a4f02d MW |
170 | 'title' => $content['title'], |
171 | 'teaser' => $content['teaser'], | |
172 | 'content' => $content['content'], | |
1bee099c AE |
173 | 'imageID' => ($isRevert) ? $articleContent->imageID : $content['imageID'], |
174 | 'teaserImageID' => ($isRevert) ? $articleContent->teaserImageID : $content['teaserImageID'] | |
a5a4f02d MW |
175 | ]); |
176 | ||
3bd00cc5 AE |
177 | $versionData[] = $articleContent; |
178 | if ($articleContent->content != $content['content'] || $articleContent->teaser != $content['teaser'] || $articleContent->title != $content['title']) { | |
179 | $hasChanges = true; | |
180 | } | |
181 | ||
a5a4f02d | 182 | // delete tags |
1bee099c | 183 | if (!$isRevert && empty($content['tags'])) { |
a5a4f02d MW |
184 | TagEngine::getInstance()->deleteObjectTags('com.woltlab.wcf.article', $articleContent->articleContentID, ($languageID ?: null)); |
185 | } | |
186 | } | |
187 | else { | |
ef17c746 | 188 | /** @var ArticleContent $articleContent */ |
a5a4f02d MW |
189 | $articleContent = ArticleContentEditor::create([ |
190 | 'articleID' => $article->articleID, | |
63b9817b | 191 | 'languageID' => $languageID ?: null, |
a5a4f02d MW |
192 | 'title' => $content['title'], |
193 | 'teaser' => $content['teaser'], | |
194 | 'content' => $content['content'], | |
1bee099c AE |
195 | 'imageID' => ($isRevert) ? null : $content['imageID'], |
196 | 'teaserImageID' => ($isRevert) ? null : $content['teaserImageID'] | |
a5a4f02d | 197 | ]); |
ef17c746 | 198 | $articleContentEditor = new ArticleContentEditor($articleContent); |
3bd00cc5 AE |
199 | |
200 | $versionData[] = $articleContent; | |
201 | $hasChanges = true; | |
a5a4f02d MW |
202 | } |
203 | ||
204 | // save tags | |
1bee099c | 205 | if (!$isRevert && !empty($content['tags'])) { |
a5a4f02d MW |
206 | TagEngine::getInstance()->addObjectTags('com.woltlab.wcf.article', $articleContent->articleContentID, $content['tags'], ($languageID ?: LanguageFactory::getInstance()->getDefaultLanguageID())); |
207 | } | |
2fd812d7 MW |
208 | |
209 | // update search index | |
e5adfbe2 MS |
210 | SearchIndexManager::getInstance()->set( |
211 | 'com.woltlab.wcf.article', | |
212 | $articleContent->articleContentID, | |
213 | $articleContent->content, | |
214 | $articleContent->title, | |
215 | $article->time, | |
216 | $article->userID, | |
217 | $article->username, | |
218 | $languageID ?: null, | |
219 | $articleContent->teaser | |
220 | ); | |
ef17c746 MW |
221 | |
222 | // save embedded objects | |
223 | if (!empty($content['htmlInputProcessor'])) { | |
2f273839 MW |
224 | /** @noinspection PhpUndefinedMethodInspection */ |
225 | $content['htmlInputProcessor']->setObjectID($articleContent->articleContentID); | |
bfb52dd9 | 226 | if ($articleContent->hasEmbeddedObjects != MessageEmbeddedObjectManager::getInstance()->registerObjects($content['htmlInputProcessor'])) { |
63b9817b | 227 | $articleContentEditor->update(['hasEmbeddedObjects' => $articleContent->hasEmbeddedObjects ? 0 : 1]); |
ef17c746 MW |
228 | } |
229 | } | |
a5a4f02d | 230 | } |
3bd00cc5 AE |
231 | |
232 | if ($hasChanges) { | |
233 | $articleObj = new ArticleVersionTracker($article->getDecoratedObject()); | |
234 | $articleObj->setContent($versionData); | |
235 | VersionTracker::getInstance()->add('com.woltlab.wcf.article', $articleObj); | |
236 | } | |
a5a4f02d MW |
237 | } |
238 | } | |
ce6f758b MW |
239 | |
240 | // reset storage | |
241 | if (ARTICLE_ENABLE_VISIT_TRACKING) { | |
242 | UserStorageHandler::getInstance()->resetAll('unreadArticles'); | |
243 | } | |
a5a4f02d | 244 | } |
2fd812d7 | 245 | |
8ff79ba2 MS |
246 | /** |
247 | * Validates parameters to delete articles. | |
248 | * | |
249 | * @throws UserInputException | |
250 | */ | |
251 | public function validateDelete() { | |
252 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
253 | ||
254 | if (empty($this->objects)) { | |
255 | $this->readObjects(); | |
256 | ||
257 | if (empty($this->objects)) { | |
258 | throw new UserInputException('objectIDs'); | |
259 | } | |
260 | } | |
261 | ||
262 | foreach ($this->getObjects() as $article) { | |
263 | if (!$article->isDeleted) { | |
264 | throw new UserInputException('objectIDs'); | |
265 | } | |
266 | } | |
267 | } | |
268 | ||
2fd812d7 MW |
269 | /** |
270 | * @inheritDoc | |
271 | */ | |
272 | public function delete() { | |
273 | $articleIDs = $articleContentIDs = []; | |
274 | foreach ($this->getObjects() as $article) { | |
275 | $articleIDs[] = $article->articleID; | |
0c968ac8 | 276 | foreach ($article->getArticleContents() as $articleContent) { |
2fd812d7 MW |
277 | $articleContentIDs[] = $articleContent->articleContentID; |
278 | } | |
279 | } | |
280 | ||
281 | // delete articles | |
282 | parent::delete(); | |
283 | ||
284 | if (!empty($articleIDs)) { | |
285 | // delete like data | |
286 | LikeHandler::getInstance()->removeLikes('com.woltlab.wcf.likeableArticle', $articleIDs); | |
287 | // delete comments | |
62e2632a | 288 | CommentHandler::getInstance()->deleteObjects('com.woltlab.wcf.articleComment', $articleContentIDs); |
2fd812d7 MW |
289 | // delete tag to object entries |
290 | TagEngine::getInstance()->deleteObjects('com.woltlab.wcf.article', $articleContentIDs); | |
291 | // delete entry from search index | |
292 | SearchIndexManager::getInstance()->delete('com.woltlab.wcf.article', $articleContentIDs); | |
293 | } | |
402a1169 | 294 | |
8ff79ba2 MS |
295 | $this->unmarkItems(); |
296 | ||
402a1169 | 297 | return [ |
8ff79ba2 | 298 | 'objectIDs' => $this->objectIDs, |
402a1169 AE |
299 | 'redirectURL' => LinkHandler::getInstance()->getLink('ArticleList', ['isACP' => true]) |
300 | ]; | |
2fd812d7 | 301 | } |
a81168d4 AE |
302 | |
303 | /** | |
8ff79ba2 | 304 | * Validates parameters to move articles to the trash bin. |
a81168d4 | 305 | * |
8ff79ba2 | 306 | * @throws UserInputException |
a81168d4 AE |
307 | */ |
308 | public function validateTrash() { | |
309 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
310 | ||
8ff79ba2 MS |
311 | if (empty($this->objects)) { |
312 | $this->readObjects(); | |
313 | ||
314 | if (empty($this->objects)) { | |
315 | throw new UserInputException('objectIDs'); | |
316 | } | |
317 | } | |
318 | ||
319 | foreach ($this->getObjects() as $article) { | |
320 | if ($article->isDeleted) { | |
321 | throw new UserInputException('objectIDs'); | |
322 | } | |
a81168d4 AE |
323 | } |
324 | } | |
325 | ||
326 | /** | |
8ff79ba2 | 327 | * Moves articles to the trash bin. |
a81168d4 AE |
328 | */ |
329 | public function trash() { | |
8ff79ba2 MS |
330 | foreach ($this->getObjects() as $articleEditor) { |
331 | $articleEditor->update(['isDeleted' => 1]); | |
332 | } | |
333 | ||
334 | $this->unmarkItems(); | |
335 | ||
89a02464 AE |
336 | // reset storage |
337 | if (ARTICLE_ENABLE_VISIT_TRACKING) { | |
338 | UserStorageHandler::getInstance()->resetAll('unreadArticles'); | |
339 | } | |
340 | ||
8ff79ba2 | 341 | return ['objectIDs' => $this->objectIDs]; |
a81168d4 AE |
342 | } |
343 | ||
344 | /** | |
8ff79ba2 | 345 | * Validates parameters to restore articles. |
a81168d4 | 346 | * |
8ff79ba2 | 347 | * @throws UserInputException |
a81168d4 AE |
348 | */ |
349 | public function validateRestore() { | |
8ff79ba2 | 350 | $this->validateDelete(); |
a81168d4 AE |
351 | } |
352 | ||
353 | /** | |
8ff79ba2 | 354 | * Restores articles. |
a81168d4 AE |
355 | */ |
356 | public function restore() { | |
8ff79ba2 MS |
357 | foreach ($this->getObjects() as $articleEditor) { |
358 | $articleEditor->update(['isDeleted' => 0]); | |
359 | } | |
360 | ||
361 | $this->unmarkItems(); | |
362 | ||
89a02464 AE |
363 | // reset storage |
364 | if (ARTICLE_ENABLE_VISIT_TRACKING) { | |
365 | UserStorageHandler::getInstance()->resetAll('unreadArticles'); | |
366 | } | |
367 | ||
8ff79ba2 | 368 | return ['objectIDs' => $this->objectIDs]; |
a81168d4 | 369 | } |
ce6f758b | 370 | |
70ecac8c AE |
371 | /** |
372 | * Validates parameters to toggle between i18n and monolingual mode. | |
373 | * | |
374 | * @throws UserInputException | |
375 | */ | |
376 | public function validateToggleI18n() { | |
377 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
378 | ||
379 | $this->articleEditor = $this->getSingleObject(); | |
380 | if ($this->articleEditor->getDecoratedObject()->isMultilingual) { | |
381 | $this->readInteger('languageID'); | |
382 | $this->language = LanguageFactory::getInstance()->getLanguage($this->parameters['languageID']); | |
383 | if ($this->language === null) { | |
384 | throw new UserInputException('languageID'); | |
385 | } | |
386 | ||
387 | $contents = $this->articleEditor->getArticleContents(); | |
388 | if (!isset($contents[$this->language->languageID])) { | |
389 | // there is no content | |
390 | throw new UserInputException('languageID'); | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | /** | |
396 | * Toggles between i18n and monolingual mode. | |
397 | */ | |
398 | public function toggleI18n() { | |
399 | $removeContent = []; | |
400 | ||
401 | // i18n -> monolingual | |
402 | if ($this->articleEditor->getDecoratedObject()->isMultilingual) { | |
403 | foreach ($this->articleEditor->getArticleContents() as $articleContent) { | |
404 | if ($articleContent->languageID == $this->language->languageID) { | |
405 | $articleContentEditor = new ArticleContentEditor($articleContent); | |
406 | $articleContentEditor->update(['languageID' => null]); | |
407 | } | |
408 | else { | |
409 | $removeContent[] = $articleContent; | |
410 | } | |
411 | } | |
412 | } | |
413 | else { | |
414 | // monolingual -> i18n | |
415 | $articleContent = $this->articleEditor->getArticleContent(); | |
416 | $data = []; | |
417 | foreach (LanguageFactory::getInstance()->getLanguages() as $language) { | |
418 | $data[$language->languageID] = [ | |
419 | 'title' => $articleContent->title, | |
420 | 'teaser' => $articleContent->teaser, | |
421 | 'content' => $articleContent->content, | |
422 | 'imageID' => $articleContent->imageID ?: null, | |
423 | 'teaserImageID' => $articleContent->teaserImageID ?: null | |
424 | ]; | |
425 | } | |
426 | ||
427 | $action = new ArticleAction([$this->articleEditor], 'update', ['content' => $data]); | |
428 | $action->executeAction(); | |
429 | ||
430 | $removeContent[] = $articleContent; | |
431 | } | |
432 | ||
433 | if (!empty($removeContent)) { | |
434 | $action = new ArticleContentAction($removeContent, 'delete'); | |
435 | $action->executeAction(); | |
436 | } | |
437 | ||
438 | // flush edit history | |
439 | VersionTracker::getInstance()->reset('com.woltlab.wcf.article', $this->articleEditor->getDecoratedObject()->articleID); | |
440 | ||
441 | // update article's i18n state | |
442 | $this->articleEditor->update([ | |
443 | 'isMultilingual' => ($this->articleEditor->getDecoratedObject()->isMultilingual) ? 0 : 1 | |
444 | ]); | |
445 | } | |
446 | ||
ce6f758b MW |
447 | /** |
448 | * Marks articles as read. | |
449 | */ | |
450 | public function markAsRead() { | |
451 | if (empty($this->parameters['visitTime'])) { | |
452 | $this->parameters['visitTime'] = TIME_NOW; | |
453 | } | |
454 | ||
455 | if (empty($this->objects)) { | |
456 | $this->readObjects(); | |
457 | } | |
458 | ||
ce6f758b | 459 | foreach ($this->getObjects() as $article) { |
ce6f758b MW |
460 | VisitTracker::getInstance()->trackObjectVisit('com.woltlab.wcf.article', $article->articleID, $this->parameters['visitTime']); |
461 | } | |
462 | ||
463 | // reset storage | |
464 | if (WCF::getUser()->userID) { | |
465 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticles'); | |
466 | } | |
467 | } | |
468 | ||
469 | /** | |
470 | * Marks all articles as read. | |
471 | */ | |
472 | public function markAllAsRead() { | |
473 | VisitTracker::getInstance()->trackTypeVisit('com.woltlab.wcf.article'); | |
474 | ||
475 | // reset storage | |
476 | if (WCF::getUser()->userID) { | |
477 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticles'); | |
478 | } | |
479 | } | |
480 | ||
481 | /** | |
482 | * Validates the mark all as read action. | |
483 | */ | |
484 | public function validateMarkAllAsRead() { | |
485 | // does nothing | |
486 | } | |
8ff79ba2 MS |
487 | |
488 | /** | |
489 | * Validates the `setCategory` action. | |
490 | * | |
491 | * @throws UserInputException | |
492 | */ | |
493 | public function validateSetCategory() { | |
494 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
495 | ||
496 | $this->readBoolean('useMarkedArticles', true); | |
497 | ||
498 | // if no object ids are given, use clipboard handler | |
499 | if (empty($this->objectIDs) && $this->parameters['useMarkedArticles']) { | |
500 | $this->objectIDs = array_keys(ClipboardHandler::getInstance()->getMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.article'))); | |
501 | } | |
502 | ||
503 | if (empty($this->objects)) { | |
504 | $this->readObjects(); | |
505 | ||
506 | if (empty($this->objects)) { | |
507 | throw new UserInputException('objectIDs'); | |
508 | } | |
509 | } | |
510 | ||
511 | $this->readInteger('categoryID'); | |
512 | if (ArticleCategory::getCategory($this->parameters['categoryID']) === null) { | |
513 | throw new UserInputException('categoryID'); | |
514 | } | |
515 | } | |
516 | ||
517 | /** | |
518 | * Sets the category of articles. | |
519 | */ | |
520 | public function setCategory() { | |
521 | foreach ($this->getObjects() as $articleEditor) { | |
522 | $articleEditor->update(['categoryID' => $this->parameters['categoryID']]); | |
523 | } | |
524 | ||
525 | $this->unmarkItems(); | |
526 | } | |
527 | ||
528 | /** | |
529 | * Validates the `publish` action. | |
530 | * | |
531 | * @throws UserInputException | |
532 | */ | |
533 | public function validatePublish() { | |
534 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
535 | ||
536 | if (empty($this->objects)) { | |
537 | $this->readObjects(); | |
538 | ||
539 | if (empty($this->objects)) { | |
540 | throw new UserInputException('objectIDs'); | |
541 | } | |
542 | } | |
543 | ||
544 | foreach ($this->getObjects() as $article) { | |
545 | if ($article->publicationStatus == Article::PUBLISHED) { | |
546 | throw new UserInputException('objectIDs'); | |
547 | } | |
548 | } | |
549 | } | |
550 | ||
551 | /** | |
552 | * Publishes articles. | |
553 | */ | |
554 | public function publish() { | |
555 | foreach ($this->getObjects() as $articleEditor) { | |
556 | $articleEditor->update([ | |
557 | 'time' => TIME_NOW, | |
558 | 'publicationStatus' => Article::PUBLISHED, | |
559 | 'publicationDate' => 0 | |
560 | ]); | |
561 | } | |
562 | ||
563 | $this->unmarkItems(); | |
564 | } | |
565 | ||
566 | /** | |
567 | * Validates the `unpublish` action. | |
568 | * | |
569 | * @throws UserInputException | |
570 | */ | |
571 | public function validateUnpublish() { | |
572 | WCF::getSession()->checkPermissions(['admin.content.article.canManageArticle']); | |
573 | ||
574 | if (empty($this->objects)) { | |
575 | $this->readObjects(); | |
576 | ||
577 | if (empty($this->objects)) { | |
578 | throw new UserInputException('objectIDs'); | |
579 | } | |
580 | } | |
581 | ||
582 | foreach ($this->getObjects() as $article) { | |
583 | if ($article->publicationStatus != Article::PUBLISHED) { | |
584 | throw new UserInputException('objectIDs'); | |
585 | } | |
586 | } | |
587 | } | |
588 | ||
589 | /** | |
590 | * Unpublishes articles. | |
591 | */ | |
592 | public function unpublish() { | |
593 | foreach ($this->getObjects() as $articleEditor) { | |
594 | $articleEditor->update(['publicationStatus' => Article::UNPUBLISHED]); | |
595 | } | |
596 | ||
597 | $this->unmarkItems(); | |
598 | } | |
599 | ||
600 | /** | |
601 | * Unmarks articles. | |
602 | * | |
603 | * @param integer[] $articleIDs | |
604 | */ | |
605 | protected function unmarkItems(array $articleIDs = []) { | |
606 | if (empty($articleIDs)) { | |
607 | foreach ($this->getObjects() as $article) { | |
608 | $articleIDs[] = $article->articleID; | |
609 | } | |
610 | } | |
611 | ||
612 | if (!empty($articleIDs)) { | |
613 | ClipboardHandler::getInstance()->unmark($articleIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.article')); | |
614 | } | |
615 | } | |
a5a4f02d | 616 | } |