diff --git a/wcfsetup/install/files/lib/command/article/EnableI18n.class.php b/wcfsetup/install/files/lib/command/article/EnableI18n.class.php index a585680e379..e445b8a7124 100644 --- a/wcfsetup/install/files/lib/command/article/EnableI18n.class.php +++ b/wcfsetup/install/files/lib/command/article/EnableI18n.class.php @@ -4,9 +4,14 @@ use wcf\data\article\Article; use wcf\data\article\ArticleAction; +use wcf\data\article\content\ArticleContent; use wcf\data\article\content\ArticleContentAction; +use wcf\data\article\content\ArticleContentEditor; +use wcf\data\object\type\ObjectTypeCache; +use wcf\system\article\discussion\IArticleDiscussionProvider; use wcf\system\language\LanguageFactory; use wcf\system\version\VersionTracker; +use wcf\system\WCF; /** * Converts a monolingual article to a multilingual. @@ -36,14 +41,19 @@ public function __invoke(): void ]; } + $discussionProvider = $this->article->getDiscussionProvider(); + $action = new ArticleAction([$this->article], 'update', [ 'content' => $data, 'data' => [ 'isMultilingual' => 1, ], + 'migrateDiscussions' => true, ]); $action->executeAction(); + $this->migrateDiscussions($discussionProvider, $this->article, $articleContent); + $action = new ArticleContentAction([$articleContent], 'delete'); $action->executeAction(); @@ -52,4 +62,22 @@ public function __invoke(): void $this->article->articleID ); } + + /** + * Preserves the comments by associating the existing comments with the + * content matching the site’s default language id. + */ + private function migrateDiscussions(IArticleDiscussionProvider $discussionProvider, Article $article, ArticleContent $oldContent): void + { + $article = new Article($article->articleID); + $newContent = $article->getArticleContents()[LanguageFactory::getInstance()->getDefaultLanguageID()] ?? null; + if ($newContent === null) { + // This shouldn’t be possible but throwing an exception here would + // yield a malformed article that cannot be fixed except through + // manual editing of the database. + return; + } + + $discussionProvider->migrateDiscussions($oldContent, $newContent); + } } diff --git a/wcfsetup/install/files/lib/system/article/discussion/AbstractArticleDiscussionProvider.class.php b/wcfsetup/install/files/lib/system/article/discussion/AbstractArticleDiscussionProvider.class.php index 46571973793..f7952fb39a7 100644 --- a/wcfsetup/install/files/lib/system/article/discussion/AbstractArticleDiscussionProvider.class.php +++ b/wcfsetup/install/files/lib/system/article/discussion/AbstractArticleDiscussionProvider.class.php @@ -26,21 +26,17 @@ abstract class AbstractArticleDiscussionProvider implements IArticleDiscussionPr */ protected $articleContent; - /** - * AbstractArticleDiscussionProvider constructor. - * - * @param Article $article - */ public function __construct(Article $article) { $this->article = $article; } - /** - * @inheritDoc - */ + #[\Override] public function setArticleContent(ArticleContent $articleContent) { $this->articleContent = $articleContent; } + + #[\Override] + public function migrateDiscussions(ArticleContent $oldContent, ArticleContent $newContent): void {} } diff --git a/wcfsetup/install/files/lib/system/article/discussion/CommentArticleDiscussionProvider.class.php b/wcfsetup/install/files/lib/system/article/discussion/CommentArticleDiscussionProvider.class.php index 08439ce5547..693df553dde 100644 --- a/wcfsetup/install/files/lib/system/article/discussion/CommentArticleDiscussionProvider.class.php +++ b/wcfsetup/install/files/lib/system/article/discussion/CommentArticleDiscussionProvider.class.php @@ -3,6 +3,9 @@ namespace wcf\system\article\discussion; use wcf\data\article\Article; +use wcf\data\article\content\ArticleContent; +use wcf\data\article\content\ArticleContentEditor; +use wcf\data\object\type\ObjectTypeCache; use wcf\system\comment\CommentHandler; use wcf\system\WCF; @@ -12,21 +15,16 @@ * @author Alexander Ebert * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License - * @since 5.2 */ class CommentArticleDiscussionProvider extends AbstractArticleDiscussionProvider { - /** - * @inheritDoc - */ + #[\Override] public function getDiscussionCount() { return $this->articleContent ? $this->articleContent->comments : $this->article->getArticleContent()->comments; } - /** - * @inheritDoc - */ + #[\Override] public function getDiscussionCountPhrase() { return WCF::getLanguage()->getDynamicVariable('wcf.article.articleComments', [ @@ -35,17 +33,13 @@ public function getDiscussionCountPhrase() ]); } - /** - * @inheritDoc - */ + #[\Override] public function getDiscussionLink() { return $this->articleContent->getLink() . '#comments'; } - /** - * @inheritDoc - */ + #[\Override] public function renderDiscussions() { $commentCanAdd = WCF::getSession()->getPermission('user.article.canAddComment'); @@ -66,6 +60,31 @@ public function renderDiscussions() ]); } + #[\Override] + public function migrateDiscussions(ArticleContent $oldContent, ArticleContent $newContent): void + { + $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( + 'com.woltlab.wcf.comment.commentableContent', + 'com.woltlab.wcf.articleComment', + ); + \assert($objectTypeID !== null); + + $sql = "UPDATE wcf1_comment + SET objectID = ? + WHERE objectTypeID = ? + AND objectID = ?"; + $statement = WCF::getDB()->prepare($sql); + $statement->execute([ + $newContent->articleContentID, + $objectTypeID, + $oldContent->articleContentID, + ]); + + (new ArticleContentEditor($newContent))->update([ + 'comments' => $oldContent->comments, + ]); + } + /** * @inheritDoc */ diff --git a/wcfsetup/install/files/lib/system/article/discussion/IArticleDiscussionProvider.class.php b/wcfsetup/install/files/lib/system/article/discussion/IArticleDiscussionProvider.class.php index 158d356ec93..90000a1828b 100644 --- a/wcfsetup/install/files/lib/system/article/discussion/IArticleDiscussionProvider.class.php +++ b/wcfsetup/install/files/lib/system/article/discussion/IArticleDiscussionProvider.class.php @@ -58,4 +58,12 @@ public function setArticleContent(ArticleContent $articleContent); * @return bool */ public static function isResponsible(Article $article); + + /** + * Migrates discussions from one content to another. This is intended to be + * used when converting a monolingual article into a multilingual one. + * + * @since 6.2 + */ + public function migrateDiscussions(ArticleContent $oldContent, ArticleContent $newContent): void; }