<definitionname>com.woltlab.wcf.like.likeableObject</definitionname>
<classname>wcf\data\article\LikeableArticleProvider</classname>
</type>
-
+ <type>
+ <name>com.woltlab.wcf.article</name>
+ <definitionname>com.woltlab.wcf.searchableObjectType</definitionname>
+ <classname>wcf\system\search\ArticleSearch</classname>
+ <searchindex>wcf1_article_search_index</searchindex>
+ </type>
<!-- /articles -->
<type>
--- /dev/null
+<dl>
+ <dt><label>{lang}wcf.article.search.categories{/lang}</label></dt>
+ <dd>
+ <ul class="scrollableCheckboxList">
+ {foreach from=$articleCategoryList item=category}
+ <li{if $category->getDepth() > 1} style="padding-left: {$category->getDepth()*20-20}px"{/if}>
+ <label><input type="checkbox" name="articleCategoryIDs[]" value="{@$category->categoryID}"{if $category->categoryID|in_array:$articleCategoryIDs} checked="checked"{/if} /> {$category->getTitle()}</label>
+ </li>
+ {/foreach}
+ </ul>
+ </dd>
+</dl>
+
+{event name='fields'}
use wcf\data\article\content\ArticleContent;
use wcf\data\article\content\ArticleContentEditor;
use wcf\data\AbstractDatabaseObjectAction;
+use wcf\system\comment\CommentHandler;
use wcf\system\language\LanguageFactory;
+use wcf\system\like\LikeHandler;
+use wcf\system\search\SearchIndexManager;
use wcf\system\tagging\TagEngine;
/**
// save article content
if (!empty($this->parameters['content'])) {
foreach ($this->parameters['content'] as $languageID => $content) {
+ /** @var ArticleContent $articleContent */
$articleContent = ArticleContentEditor::create([
'articleID' => $article->articleID,
'languageID' => ($languageID ?: null),
if (!empty($content['tags'])) {
TagEngine::getInstance()->addObjectTags('com.woltlab.wcf.article', $articleContent->articleContentID, $content['tags'], ($languageID ?: LanguageFactory::getInstance()->getDefaultLanguageID()));
}
+
+ // update search index
+ SearchIndexManager::getInstance()->add('com.woltlab.wcf.article', $articleContent->articleContentID, $articleContent->content, $articleContent->title, $article->time, $article->userID, $article->username, ($languageID ?: null), $articleContent->teaser);
}
}
if (!empty($content['tags'])) {
TagEngine::getInstance()->addObjectTags('com.woltlab.wcf.article', $articleContent->articleContentID, $content['tags'], ($languageID ?: LanguageFactory::getInstance()->getDefaultLanguageID()));
}
+
+ // update search index
+ SearchIndexManager::getInstance()->add('com.woltlab.wcf.article', $articleContent->articleContentID, $articleContent->content, $articleContent->title, $article->time, $article->userID, $article->username, ($languageID ?: null), $articleContent->teaser);
}
}
}
}
+
+ /**
+ * @inheritDoc
+ */
+ public function delete() {
+ $articleIDs = $articleContentIDs = [];
+ foreach ($this->getObjects() as $article) {
+ $articleIDs[] = $article->articleID;
+ foreach ($article->getArticleContent() as $articleContent) {
+ $articleContentIDs[] = $articleContent->articleContentID;
+ }
+ }
+
+ // delete articles
+ parent::delete();
+
+ if (!empty($articleIDs)) {
+ // delete like data
+ LikeHandler::getInstance()->removeLikes('com.woltlab.wcf.likeableArticle', $articleIDs);
+ // delete comments
+ CommentHandler::getInstance()->deleteObjects('com.woltlab.wcf.article', $articleContentIDs);
+ // delete tag to object entries
+ TagEngine::getInstance()->deleteObjects('com.woltlab.wcf.article', $articleContentIDs);
+ // delete entry from search index
+ SearchIndexManager::getInstance()->delete('com.woltlab.wcf.article', $articleContentIDs);
+ }
+ }
}
--- /dev/null
+<?php
+namespace wcf\data\article\content;;
+use wcf\data\search\ISearchResultObject;
+use wcf\system\request\LinkHandler;
+use wcf\system\search\SearchResultTextParser;
+
+/**
+ * Represents an article content as a search result.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2016 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.article.content
+ * @category Community Framework
+ * @since 2.2
+ */
+class SearchResultArticleContent extends ViewableArticleContent implements ISearchResultObject {
+ /**
+ * @inheritDoc
+ */
+ public function getUserProfile() {
+ return $this->getArticle()->getUserProfile();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getSubject() {
+ return $this->getDecoratedObject()->getTitle();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTime() {
+ return $this->getArticle()->time;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getLink($query = '') {
+ $parameters = [
+ 'object' => $this->getDecoratedObject(),
+ 'forceFrontend' => true
+ ];
+
+ if ($query) {
+ $parameters['highlight'] = urlencode($query);
+ }
+
+ return LinkHandler::getInstance()->getLink('Article', $parameters);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getObjectTypeName() {
+ return 'com.woltlab.wcf.article';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFormattedMessage() {
+ // @todo
+ $message = SearchResultTextParser::getInstance()->parse($this->getDecoratedObject()->getFormattedContent());
+
+ if ($this->getImage()) {
+ return '<div class="box96">'.$this->getImage()->getElementTag(96).'<div>'.$message.'</div></div>';
+ }
+
+ return $message;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getContainerTitle() {
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getContainerLink() {
+ return '';
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\article\content;
+
+/**
+ * Represents a list of article content as search results.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2016 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.article.content
+ * @category Community Framework
+ * @since 2.2
+ *
+ * @method SearchResultEntry current()
+ * @method SearchResultEntry[] getObjects()
+ * @method SearchResultEntry|null search($objectID)
+ */
+class SearchResultArticleContentList extends ViewableArticleContentList {
+ /**
+ * @inheritDoc
+ */
+ public $decoratorClassName = SearchResultArticleContent::class;
+}
<?php
namespace wcf\data\article\content;
+use wcf\data\article\ViewableArticle;
use wcf\data\media\ViewableMedia;
use wcf\data\DatabaseObjectDecorator;
* @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
- * @subpackage data.article
+ * @subpackage data.article.content
* @category Community Framework
* @since 2.2
*
*/
protected $image;
+ /**
+ * article object
+ * @var ViewableArticle
+ */
+ protected $article;
+
/**
* Gets a specific article content decorated as viewable article content.
*
return null;
}
+ /**
+ * Returns article object.
+ *
+ * @return ViewableArticle
+ */
+ public function getArticle() {
+ if ($this->article === null) {
+ $this->article = new ViewableArticle($this->getDecoratedObject()->getArticle());
+ }
+
+ return $this->article;
+ }
+
+ /**
+ * Sets the article objects.
+ *
+ * @param ViewableArticle $article
+ */
+ public function setArticle(ViewableArticle $article) {
+ $this->article = $article;
+ }
+
/**
* Returns the article's image.
*
* @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
- * @subpackage data.article
+ * @subpackage data.article.content
* @category Community Framework
* @since 2.2
*/
--- /dev/null
+<?php
+namespace wcf\system\search;
+use wcf\data\article\category\ArticleCategory;
+use wcf\data\article\content\SearchResultArticleContent;
+use wcf\data\article\content\SearchResultArticleContentList;
+use wcf\data\category\CategoryNodeTree;
+use wcf\form\IForm;
+use wcf\form\SearchForm;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\page\PageLocationManager;
+use wcf\system\WCF;
+use wcf\util\ArrayUtil;
+
+/**
+ * An implementation of ISearchableObjectType for searching in articles.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2016 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.search
+ * @category Community Framework
+ * @since 2.2
+ */
+class ArticleSearch extends AbstractSearchableObjectType {
+ /**
+ * ids of the selected categories
+ * @var integer[]
+ */
+ public $articleCategoryIDs = [];
+
+ /**
+ * message data cache
+ * @var SearchResultArticleContent[]
+ */
+ public $messageCache = [];
+
+ /**
+ * @inheritDoc
+ */
+ public function cacheObjects(array $objectIDs, array $additionalData = null) {
+ $list = new SearchResultArticleContentList();
+ $list->setObjectIDs($objectIDs);
+ $list->readObjects();
+ foreach ($list->getObjects() as $content) {
+ $this->messageCache[$content->articleContentID] = $content;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getObject($objectID) {
+ if (isset($this->messageCache[$objectID])) return $this->messageCache[$objectID];
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTableName() {
+ return 'wcf'.WCF_N.'_article_content';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getIDFieldName() {
+ return $this->getTableName().'.articleContentID';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getSubjectFieldName() {
+ return $this->getTableName().'.title';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getUsernameFieldName() {
+ return 'wcf'.WCF_N.'_article.username';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTimeFieldName() {
+ return 'wcf'.WCF_N.'_article.time';
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ /**
+ * @inheritDoc
+ */
+ public function getConditions(IForm $form = null) {
+ // accessible category ids
+ if (isset($_POST['articleCategoryIDs'])) $this->articleCategoryIDs = ArrayUtil::toIntegerArray($_POST['articleCategoryIDs']);
+ $accessibleCategoryIDs = ArticleCategory::getAccessibleCategoryIDs();
+ if (!empty($this->articleCategoryIDs)) {
+ $this->articleCategoryIDs = array_intersect($accessibleCategoryIDs, $this->articleCategoryIDs);
+ }
+ else {
+ $this->articleCategoryIDs = $accessibleCategoryIDs;
+ }
+ if (empty($this->articleCategoryIDs)) {
+ throw new PermissionDeniedException();
+ }
+
+ $conditionBuilder = new PreparedStatementConditionBuilder();
+ $conditionBuilder->add('wcf'.WCF_N.'_article.categoryID IN (?) AND wcf'.WCF_N.'_article.publicationStatus = ?', [$this->articleCategoryIDs, 1]);
+
+ return $conditionBuilder;
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ /**
+ * @inheritDoc
+ */
+ public function getJoins() {
+ return 'JOIN wcf'.WCF_N.'_article ON (wcf'.WCF_N.'_article.articleID = '.$this->getTableName().'.articleID)';
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ /**
+ * @inheritDoc
+ */
+ public function getFormTemplateName() {
+ return 'searchArticle';
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ /**
+ * @inheritDoc
+ */
+ public function getAdditionalData() {
+ return ['articleCategoryIDs' => $this->articleCategoryIDs];
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ /**
+ * @inheritDoc
+ */
+ public function isAccessible() {
+ return MODULE_ARTICLE;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function show(IForm $form = null) {
+ /** @var SearchForm $form */
+
+ $categoryTree = new CategoryNodeTree('com.woltlab.wcf.article.category');
+ $categoryList = $categoryTree->getIterator();
+ $categoryList->setMaxDepth(0);
+
+ // get existing values
+ if ($form !== null && isset($form->searchData['additionalData']['com.woltlab.wcf.article'])) {
+ $this->articleCategoryIDs = $form->searchData['additionalData']['com.woltlab.wcf.article']['articleCategoryIDs'];
+ }
+
+ WCF::getTPL()->assign([
+ 'articleCategoryIDs' => $this->articleCategoryIDs,
+ 'articleCategoryList' => $categoryList
+ ]);
+ }
+
+ /**
+ * @inheritDoc
+ * @since 2.2
+ */
+ public function setLocation() {
+ PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.ArticleList');
+ }
+}