Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / page / AbstractArticlePage.class.php
1 <?php
2 namespace wcf\page;
3 use wcf\data\article\category\ArticleCategory;
4 use wcf\data\article\content\ViewableArticleContent;
5 use wcf\data\article\AccessibleArticleList;
6 use wcf\data\article\ArticleAction;
7 use wcf\data\article\ArticleEditor;
8 use wcf\data\article\ViewableArticle;
9 use wcf\data\tag\Tag;
10 use wcf\system\database\util\PreparedStatementConditionBuilder;
11 use wcf\system\exception\IllegalLinkException;
12 use wcf\system\exception\PermissionDeniedException;
13 use wcf\system\language\LanguageFactory;
14 use wcf\system\page\PageLocationManager;
15 use wcf\system\tagging\TagEngine;
16 use wcf\system\WCF;
17
18 /**
19 * Abstract implementation of the article page.
20 *
21 * @author Marcel Werk
22 * @copyright 2001-2018 WoltLab GmbH
23 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
24 * @package WoltLabSuite\Core\Page
25 * @since 3.0
26 */
27 abstract class AbstractArticlePage extends AbstractPage {
28 /**
29 * @inheritDoc
30 */
31 public $neededModules = ['MODULE_ARTICLE'];
32
33 /**
34 * article content id
35 * @var integer
36 */
37 public $articleContentID = 0;
38
39 /**
40 * article content object
41 * @var ViewableArticleContent
42 */
43 public $articleContent;
44
45 /**
46 * article object
47 * @var ViewableArticle
48 */
49 public $article;
50
51 /**
52 * list of tags
53 * @var Tag[]
54 */
55 public $tags = [];
56
57 /**
58 * category object
59 * @var ArticleCategory
60 */
61 public $category;
62
63 /**
64 * list of related articles
65 * @var AccessibleArticleList
66 */
67 public $relatedArticles;
68
69 /**
70 * @inheritDoc
71 */
72 public function readParameters() {
73 parent::readParameters();
74
75 if (isset($_REQUEST['id'])) $this->articleContentID = intval($_REQUEST['id']);
76 $this->articleContent = ViewableArticleContent::getArticleContent($this->articleContentID);
77 if ($this->articleContent === null) {
78 throw new IllegalLinkException();
79 }
80
81 // check if the language has been disabled
82 if ($this->articleContent->languageID && LanguageFactory::getInstance()->getLanguage($this->articleContent->languageID) === null) {
83 throw new IllegalLinkException();
84 }
85
86 $this->article = ViewableArticle::getArticle($this->articleContent->articleID, false);
87 $this->category = $this->article->getCategory();
88
89 // update interface language
90 if (!WCF::getUser()->userID && $this->article->isMultilingual && $this->articleContent->languageID != WCF::getLanguage()->languageID) {
91 WCF::setLanguage($this->articleContent->languageID);
92 }
93 }
94
95 /**
96 * @inheritDoc
97 */
98 public function checkPermissions() {
99 parent::checkPermissions();
100
101 if (!$this->article->canRead()) {
102 throw new PermissionDeniedException();
103 }
104 }
105
106 /**
107 * @inheritDoc
108 */
109 public function readData() {
110 parent::readData();
111
112 // update view count
113 $articleEditor = new ArticleEditor($this->article->getDecoratedObject());
114 $articleEditor->updateCounters([
115 'views' => 1
116 ]);
117
118 // update article visit
119 if (ARTICLE_ENABLE_VISIT_TRACKING && $this->article->isNew()) {
120 $articleAction = new ArticleAction([$this->article->getDecoratedObject()], 'markAsRead', [
121 'viewableArticle' => $this->article
122 ]);
123 $articleAction->executeAction();
124 }
125
126 // get tags
127 if (MODULE_TAGGING && WCF::getSession()->getPermission('user.tag.canViewTag')) {
128 $this->tags = TagEngine::getInstance()->getObjectTags(
129 'com.woltlab.wcf.article',
130 $this->articleContent->articleContentID,
131 [$this->articleContent->languageID ?: LanguageFactory::getInstance()->getDefaultLanguageID()]
132 );
133 }
134
135 // get related articles
136 if (MODULE_TAGGING && ARTICLE_RELATED_ARTICLES) {
137 if (!empty($this->tags)) {
138 $conditionBuilder = new PreparedStatementConditionBuilder();
139 $conditionBuilder->add('objectTypeID = ?', [TagEngine::getInstance()->getObjectTypeID('com.woltlab.wcf.article')]);
140 $conditionBuilder->add('tagID IN (?)', [array_keys($this->tags)]);
141 $conditionBuilder->add('objectID <> ?', [$this->articleContentID]);
142 $sql = "SELECT objectID, COUNT(*) AS count
143 FROM wcf" . WCF_N . "_tag_to_object
144 " . $conditionBuilder . "
145 GROUP BY objectID
146 HAVING COUNT(*) >= " . round(count($this->tags) * ARTICLE_RELATED_ARTICLES_MATCH_THRESHOLD / 100) . "
147 ORDER BY count DESC";
148 $statement = WCF::getDB()->prepareStatement($sql, ARTICLE_RELATED_ARTICLES);
149 $statement->execute($conditionBuilder->getParameters());
150 $articleContentIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
151
152 if (!empty($articleContentIDs)) {
153 $conditionBuilder = new PreparedStatementConditionBuilder();
154 $conditionBuilder->add('articleContentID IN (?)', [$articleContentIDs]);
155 $sql = "SELECT articleID
156 FROM wcf" . WCF_N . "_article_content
157 " . $conditionBuilder;
158 $statement = WCF::getDB()->prepareStatement($sql);
159 $statement->execute($conditionBuilder->getParameters());
160 $articleIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
161
162 $this->relatedArticles = new AccessibleArticleList();
163 $this->relatedArticles->getConditionBuilder()->add('article.articleID IN (?)', [$articleIDs]);
164 $this->relatedArticles->sqlOrderBy = 'article.time';
165 $this->relatedArticles->readObjects();
166 }
167 }
168 }
169
170 // set location
171 PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.CategoryArticleList', $this->article->categoryID, $this->article->getCategory());
172 foreach (array_reverse($this->article->getCategory()->getParentCategories()) as $parentCategory) {
173 PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.CategoryArticleList', $parentCategory->categoryID, $parentCategory);
174 }
175 }
176
177 /**
178 * @inheritDoc
179 */
180 public function assignVariables() {
181 parent::assignVariables();
182
183 WCF::getTPL()->assign([
184 'articleContentID' => $this->articleContentID,
185 'articleContent' => $this->articleContent,
186 'article' => $this->article,
187 'category' => $this->category,
188 'relatedArticles' => $this->relatedArticles,
189 'tags' => $this->tags
190 ]);
191 }
192 }