diff options
Diffstat (limited to 'lib/Db')
-rw-r--r-- | lib/Db/EntityJSONSerializer.php | 28 | ||||
-rw-r--r-- | lib/Db/Feed.php | 189 | ||||
-rw-r--r-- | lib/Db/FeedMapper.php | 166 | ||||
-rw-r--r-- | lib/Db/FeedType.php | 24 | ||||
-rw-r--r-- | lib/Db/Folder.php | 73 | ||||
-rw-r--r-- | lib/Db/FolderMapper.php | 110 | ||||
-rw-r--r-- | lib/Db/IAPI.php | 18 | ||||
-rw-r--r-- | lib/Db/Item.php | 256 | ||||
-rw-r--r-- | lib/Db/ItemMapper.php | 403 | ||||
-rw-r--r-- | lib/Db/MapperFactory.php | 47 | ||||
-rw-r--r-- | lib/Db/Mysql/ItemMapper.php | 88 | ||||
-rw-r--r-- | lib/Db/NewsMapper.php | 93 | ||||
-rw-r--r-- | lib/Db/StatusFlag.php | 47 |
13 files changed, 1542 insertions, 0 deletions
diff --git a/lib/Db/EntityJSONSerializer.php b/lib/Db/EntityJSONSerializer.php new file mode 100644 index 000000000..c0d946452 --- /dev/null +++ b/lib/Db/EntityJSONSerializer.php @@ -0,0 +1,28 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +trait EntityJSONSerializer { + + + public function serializeFields($properties) { + $result = []; + foreach($properties as $property) { + $result[$property] = $this->$property; + } + return $result; + } + + +}
\ No newline at end of file diff --git a/lib/Db/Feed.php b/lib/Db/Feed.php new file mode 100644 index 000000000..62d49c01b --- /dev/null +++ b/lib/Db/Feed.php @@ -0,0 +1,189 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +use \OCP\AppFramework\Db\Entity; + +/** + * @method integer getId() + * @method void setId(integer $value) + * @method string getUserId() + * @method void setUserId(string $value) + * @method int getOrdering() + * @method void setOrdering(integer $value) + * @method string getUrlHash() + * @method void setUrlHash(string $value) + * @method string getLocation() + * @method void setLocation(string $value) + * @method string getUrl() + * @method string getTitle() + * @method void setTitle(string $value) + * @method string getLastModified() + * @method void setLastModified(integer $value) + * @method string getHttpLastModified() + * @method void setHttpLastModified(string $value) + * @method string getHttpEtag() + * @method void setHttpEtag(string $value) + * @method string getFaviconLink() + * @method void setFaviconLink(string $value) + * @method integer getAdded() + * @method void setAdded(integer $value) + * @method boolean getPinned() + * @method void setPinned(boolean $value) + * @method integer getFolderId() + * @method void setFolderId(integer $value) + * @method integer getFullTextEnabled() + * @method void setFullTextEnabled(bool $value) + * @method integer getUnreadCount() + * @method void setUnreadCount(integer $value) + * @method string getLink() + * @method boolean getPreventUpdate() + * @method void setPreventUpdate(boolean $value) + * @method integer getDeletedAt() + * @method void setDeletedAt(integer $value) + * @method integer getArticlesPerUpdate() + * @method void setArticlesPerUpdate(integer $value) + * @method integer getUpdateErrorCount() + * @method void setUpdateErrorCount(integer $value) + * @method string getLastUpdateError() + * @method void setLastUpdateError(string $value) + * @method string getBasicAuthUser() + * @method void setBasicAuthUser(string $value) + * @method string getBasicAuthPassword() + * @method void setBasicAuthPassword(string $value) + */ +class Feed extends Entity implements IAPI, \JsonSerializable { + + use EntityJSONSerializer; + + protected $userId; + protected $urlHash; + protected $url; + protected $title; + protected $faviconLink; + protected $added; + protected $folderId; + protected $unreadCount; + protected $link; + protected $preventUpdate; + protected $deletedAt; + protected $articlesPerUpdate; + protected $httpLastModified; + protected $lastModified; + protected $httpEtag; + protected $location; + protected $ordering; + protected $fullTextEnabled; + protected $pinned; + protected $updateMode; + protected $updateErrorCount; + protected $lastUpdateError; + protected $basicAuthUser; + protected $basicAuthPassword; + + public function __construct(){ + $this->addType('parentId', 'integer'); + $this->addType('added', 'integer'); + $this->addType('folderId', 'integer'); + $this->addType('unreadCount', 'integer'); + $this->addType('preventUpdate', 'boolean'); + $this->addType('pinned', 'boolean'); + $this->addType('deletedAt', 'integer'); + $this->addType('articlesPerUpdate', 'integer'); + $this->addType('ordering', 'integer'); + $this->addType('fullTextEnabled', 'boolean'); + $this->addType('updateMode', 'integer'); + $this->addType('updateErrorCount', 'integer'); + $this->addType('lastModified', 'integer'); + } + + + /** + * Turns entitie attributes into an array + */ + public function jsonSerialize() { + $serialized = $this->serializeFields([ + 'id', + 'userId', + 'urlHash', + 'url', + 'title', + 'faviconLink', + 'added', + 'folderId', + 'unreadCount', + 'link', + 'preventUpdate', + 'deletedAt', + 'articlesPerUpdate', + 'location', + 'ordering', + 'fullTextEnabled', + 'pinned', + 'updateMode', + 'updateErrorCount', + 'lastUpdateError', + 'basicAuthUser', + 'basicAuthPassword' + ]); + + $url = parse_url($this->link)['host']; + + // strip leading www. to avoid css class confusion + if (strpos($url, 'www.') === 0) { + $url = substr($url, 4); + } + + $serialized['cssClass'] = 'custom-' . str_replace('.', '-', $url); + + return $serialized; + } + + + public function toAPI() { + return $this->serializeFields([ + 'id', + 'url', + 'title', + 'faviconLink', + 'added', + 'folderId', + 'unreadCount', + 'ordering', + 'link', + 'pinned', + 'updateErrorCount', + 'lastUpdateError' + ]); + } + + + public function setUrl($url) { + $url = trim($url); + if(strpos($url, 'http') === 0) { + parent::setUrl($url); + $this->setUrlHash(md5($url)); + } + } + + + public function setLink($url) { + $url = trim($url); + if(strpos($url, 'http') === 0) { + parent::setLink($url); + } + } + + +} diff --git a/lib/Db/FeedMapper.php b/lib/Db/FeedMapper.php new file mode 100644 index 000000000..80d75e723 --- /dev/null +++ b/lib/Db/FeedMapper.php @@ -0,0 +1,166 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +use OCA\News\Utility\Time; +use OCP\IDBConnection; +use OCP\AppFramework\Db\Entity; + + +class FeedMapper extends NewsMapper { + + + public function __construct(IDBConnection $db, Time $time) { + parent::__construct($db, 'news_feeds', Feed::class, $time); + } + + + public function find($id, $userId){ + $sql = 'SELECT `feeds`.*, COUNT(`items`.`id`) AS `unread_count` ' . + 'FROM `*PREFIX*news_feeds` `feeds` ' . + 'LEFT JOIN `*PREFIX*news_items` `items` ' . + 'ON `feeds`.`id` = `items`.`feed_id` ' . + // WARNING: this is a desperate attempt at making this query + // work because prepared statements dont work. This is a + // POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. + // think twice when changing this + 'AND (`items`.`status` & ' . StatusFlag::UNREAD . ') = ' . + StatusFlag::UNREAD . ' ' . + 'WHERE `feeds`.`id` = ? ' . + 'AND `feeds`.`user_id` = ? ' . + 'GROUP BY `feeds`.`id`'; + $params = [$id, $userId]; + + return $this->findEntity($sql, $params); + } + + + public function findAllFromUser($userId){ + $sql = 'SELECT `feeds`.*, COUNT(`items`.`id`) AS `unread_count` ' . + 'FROM `*PREFIX*news_feeds` `feeds` ' . + 'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` '. + 'ON `feeds`.`folder_id` = `folders`.`id` ' . + 'LEFT JOIN `*PREFIX*news_items` `items` ' . + 'ON `feeds`.`id` = `items`.`feed_id` ' . + // WARNING: this is a desperate attempt at making this query + // work because prepared statements dont work. This is a + // POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. + // think twice when changing this + 'AND (`items`.`status` & ' . StatusFlag::UNREAD . ') = ' . + StatusFlag::UNREAD . ' ' . + 'WHERE `feeds`.`user_id` = ? ' . + 'AND (`feeds`.`folder_id` = 0 ' . + 'OR `folders`.`deleted_at` = 0' . + ')' . + 'AND `feeds`.`deleted_at` = 0 ' . + 'GROUP BY `feeds`.`id`'; + $params = [$userId]; + + return $this->findEntities($sql, $params); + } + + + public function findAll(){ + $sql = 'SELECT `feeds`.*, COUNT(`items`.`id`) AS `unread_count` ' . + 'FROM `*PREFIX*news_feeds` `feeds` ' . + 'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` '. + 'ON `feeds`.`folder_id` = `folders`.`id` ' . + 'LEFT JOIN `*PREFIX*news_items` `items` ' . + 'ON `feeds`.`id` = `items`.`feed_id` ' . + // WARNING: this is a desperate attempt at making this query + // work because prepared statements dont work. This is a + // POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. + // think twice when changing this + 'AND (`items`.`status` & ' . StatusFlag::UNREAD . ') = ' . + StatusFlag::UNREAD . ' ' . + 'WHERE (`feeds`.`folder_id` = 0 ' . + 'OR `folders`.`deleted_at` = 0' . + ')' . + 'AND `feeds`.`deleted_at` = 0 ' . + 'GROUP BY `feeds`.`id`'; + + return $this->findEntities($sql); + } + + + public function findByUrlHash($hash, $userId){ + $sql = 'SELECT `feeds`.*, COUNT(`items`.`id`) AS `unread_count` ' . + 'FROM `*PREFIX*news_feeds` `feeds` ' . + 'LEFT JOIN `*PREFIX*news_items` `items` ' . + 'ON `feeds`.`id` = `items`.`feed_id` ' . + // WARNING: this is a desperate attempt at making this query + // work because prepared statements dont work. This is a + // POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. + // think twice when changing this + 'AND (`items`.`status` & ' . StatusFlag::UNREAD . ') = ' . + StatusFlag::UNREAD . ' ' . + 'WHERE `feeds`.`url_hash` = ? ' . + 'AND `feeds`.`user_id` = ? ' . + 'GROUP BY `feeds`.`id`'; + $params = [$hash, $userId]; + + return $this->findEntity($sql, $params); + } + + + public function delete(Entity $entity){ + parent::delete($entity); + + // someone please slap me for doing this manually :P + // we needz CASCADE + FKs please + $sql = 'DELETE FROM `*PREFIX*news_items` WHERE `feed_id` = ?'; + $params = [$entity->getId()]; + $this->execute($sql, $params); + } + + + /** + * @param int $deleteOlderThan if given gets all entries with a delete date + * older than that timestamp + * @param string $userId if given returns only entries from the given user + * @return array with the database rows + */ + public function getToDelete($deleteOlderThan=null, $userId=null) { + $sql = 'SELECT * FROM `*PREFIX*news_feeds` ' . + 'WHERE `deleted_at` > 0 '; + $params = []; + + // sometimes we want to delete all entries + if ($deleteOlderThan !== null) { + $sql .= 'AND `deleted_at` < ? '; + $params[] = $deleteOlderThan; + } + + // we need to sometimes only delete feeds of a user + if($userId !== null) { + $sql .= 'AND `user_id` = ?'; + $params[] = $userId; + } + + return $this->findEntities($sql, $params); + } + + + /** + * Deletes all feeds of a user, delete items first since the user_id + * is not defined in there + * @param string $userId the name of the user + */ + public function deleteUser($userId) { + $sql = 'DELETE FROM `*PREFIX*news_feeds` WHERE `user_id` = ?'; + $this->execute($sql, [$userId]); + } + + +} diff --git a/lib/Db/FeedType.php b/lib/Db/FeedType.php new file mode 100644 index 000000000..fcb42bb8a --- /dev/null +++ b/lib/Db/FeedType.php @@ -0,0 +1,24 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + + +class FeedType { + const FEED = 0; + const FOLDER = 1; + const STARRED = 2; + const SUBSCRIPTIONS = 3; + const SHARED = 4; + const EXPLORE = 5; +}
\ No newline at end of file diff --git a/lib/Db/Folder.php b/lib/Db/Folder.php new file mode 100644 index 000000000..8d1432a73 --- /dev/null +++ b/lib/Db/Folder.php @@ -0,0 +1,73 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +use \OCP\AppFramework\Db\Entity; + +/** + * @method integer getId() + * @method void setId(integer $value) + * @method string getUserId() + * @method void setUserId(string $value) + * @method string getName() + * @method void setName(string $value) + * @method integer getParentId() + * @method void setParentId(integer $value) + * @method boolean getOpened() + * @method void setOpened(boolean $value) + * @method integer getDeletedAt() + * @method void setDeletedAt(integer $value) + * @method integer getLastModified() + * @method void setLastModified(integer $value) + + */ +class Folder extends Entity implements IAPI, \JsonSerializable { + + use EntityJSONSerializer; + + protected $parentId; + protected $name; + protected $userId; + protected $opened; + protected $deletedAt; + protected $lastModified; + + public function __construct(){ + $this->addType('parentId', 'integer'); + $this->addType('opened', 'boolean'); + $this->addType('deletedAt', 'integer'); + $this->addType('lastModified', 'integer'); + } + + /** + * Turns entitie attributes into an array + */ + public function jsonSerialize() { + return $this->serializeFields([ + 'id', + 'parentId', + 'name', + 'userId', + 'opened', + 'deletedAt', + ]); + } + + public function toAPI() { + return $this->serializeFields([ + 'id', + 'name' + ]); + } +}
\ No newline at end of file diff --git a/lib/Db/FolderMapper.php b/lib/Db/FolderMapper.php new file mode 100644 index 000000000..30acb455c --- /dev/null +++ b/lib/Db/FolderMapper.php @@ -0,0 +1,110 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +use OCA\News\Utility\Time; +use OCP\IDBConnection; +use OCP\AppFramework\Db\Entity; + +class FolderMapper extends NewsMapper { + + public function __construct(IDBConnection $db, Time $time) { + parent::__construct($db, 'news_folders', Folder::class, $time); + } + + public function find($id, $userId){ + $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . + 'WHERE `id` = ? ' . + 'AND `user_id` = ?'; + + return $this->findEntity($sql, [$id, $userId]); + } + + + public function findAllFromUser($userId){ + $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . + 'WHERE `user_id` = ? ' . + 'AND `deleted_at` = 0'; + $params = [$userId]; + + return $this->findEntities($sql, $params); + } + + + public function findByName($folderName, $userId){ + $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . + 'WHERE `name` = ? ' . + 'AND `user_id` = ?'; + $params = [$folderName, $userId]; + + return $this->findEntities($sql, $params); + } + + + public function delete(Entity $entity){ + parent::delete($entity); + + // someone please slap me for doing this manually :P + // we needz CASCADE + FKs please + $sql = 'DELETE FROM `*PREFIX*news_feeds` WHERE `folder_id` = ?'; + $params = [$entity->getId()]; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + + $sql = 'DELETE FROM `*PREFIX*news_items` WHERE `feed_id` NOT IN '. + '(SELECT `feeds`.`id` FROM `*PREFIX*news_feeds` `feeds`)'; + + $stmt = $this->execute($sql); + $stmt->closeCursor(); + } + + + /** + * @param int $deleteOlderThan if given gets all entries with a delete date + * older than that timestamp + * @param string $userId if given returns only entries from the given user + * @return array with the database rows + */ + public function getToDelete($deleteOlderThan=null, $userId=null) { + $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . + 'WHERE `deleted_at` > 0 '; + $params = []; + + // sometimes we want to delete all entries + if ($deleteOlderThan !== null) { + $sql .= 'AND `deleted_at` < ? '; + $params[] = $deleteOlderThan; + } + + // we need to sometimes only delete feeds of a user + if($userId !== null) { + $sql .= 'AND `user_id` = ?'; + $params[] = $userId; + } + + return $this->findEntities($sql, $params); + } + + + /** + * Deletes all folders of a user + * @param string $userId the name of the user + */ + public function deleteUser($userId) { + $sql = 'DELETE FROM `*PREFIX*news_folders` WHERE `user_id` = ?'; + $this->execute($sql, [$userId]); + } + + +} diff --git a/lib/Db/IAPI.php b/lib/Db/IAPI.php new file mode 100644 index 000000000..ff9791753 --- /dev/null +++ b/lib/Db/IAPI.php @@ -0,0 +1,18 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +interface IAPI { + public function toAPI(); +} diff --git a/lib/Db/Item.php b/lib/Db/Item.php new file mode 100644 index 000000000..e0d8b069b --- /dev/null +++ b/lib/Db/Item.php @@ -0,0 +1,256 @@ +<?php +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alessandro Cosentino <cosenal@gmail.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Alessandro Cosentino 2012 + * @copyright Bernhard Posselt 2012, 2014 + */ + +namespace OCA\News\Db; + +use \OCP\AppFramework\Db\Entity; + +/** + * @method integer getId() + * @method void setId(integer $value) + * @method string getGuid() + * @method void setGuid(string $value) + * @method string getGuidHash() + * @method void setGuidHash(string $value) + * @method string getUrl() + * @method string getTitle() + * @method string getAuthor() + * @method string getRtl() + * @method string getFingerprint() + * @method string getContentHash() + * @method integer getPubDate() + * @method void setPubDate(integer $value) + * @method string getBody() + * @method string getEnclosureMime() + * @method void setEnclosureMime(string $value) + * @method string getEnclosureLink() + * @method void setEnclosureLink(string $value) + * @method integer getFeedId() + * @method void setFeedId(integer $value) + * @method integer getStatus() + * @method void setStatus(integer $value) + * @method void setRtl(boolean $value) + * @method integer getLastModified() + * @method void setLastModified(integer $value) + * @method void setFingerprint(string $value) + * @method void setContentHash(string $value) + * @method void setSearchIndex(string $value) + */ +class Item extends Entity implements IAPI, \JsonSerializable { + + use EntityJSONSerializer; + + protected $contentHash; + protected $guidHash; + protected $guid; + protected $url; + protected $title; + protected $author; + protected $pubDate; + protected $body; + protected $enclosureMime; + protected $enclosureLink; + protected $feedId; + protected $status = 0; + protected $lastModified; + protected $searchIndex; + protected $rtl; + protected $fingerprint; + + public function __construct() { + $this->addType('pubDate', 'integer'); + $this->addType('feedId', 'integer'); + $this->addType('status', 'integer'); + $this->addType('lastModified', 'integer'); + $this->addType('rtl', 'boolean'); + } + + public function setRead() { + $this->markFieldUpdated('status'); + $this->status &= ~StatusFlag::UNREAD; + } + + public function isRead() { + return !(($this->status & StatusFlag::UNREAD) === StatusFlag::UNREAD); + } + + public function setUnread() { + $this->markFieldUpdated('status'); + $this->status |= StatusFlag::UNREAD; + } + + public function isUnread() { + return !$this->isRead(); + } + + public function setStarred() { + $this->markFieldUpdated('status'); + $this->status |= StatusFlag::STARRED; + } + + public function isStarred() { + return ($this->status & StatusFlag::STARRED) === StatusFlag::STARRED; + } + + public function setUnstarred() { + $this->markFieldUpdated('status'); + $this->status &= ~StatusFlag::STARRED; + } + + public function isUnstarred() { + return !$this->isStarred(); + } + + /** + * Turns entitie attributes into an array + */ + public function jsonSerialize() { + return [ + 'id' => $this->getId(), + 'guid' => $this->getGuid(), + 'guidHash' => $this->getGuidHash(), + 'url' => $this->getUrl(), + 'title' => $this->getTitle(), + 'author' => $this->getAuthor(), + 'pubDate' => $this->getPubDate(), + 'body' => $this->getBody(), + 'enclosureMime' => $this->getEnclosureMime(), + 'enclosureLink' => $this->getEnclosureLink(), + 'feedId' => $this->getFeedId(), + 'unread' => $this->isUnread(), + 'starred' => $this->isStarred(), + 'lastModified' => $this->getLastModified(), + 'rtl' => $this->getRtl(), + 'intro' => $this->getIntro(), + 'fingerprint' => $this->getFingerprint(), + ]; + } + + public function toAPI() { + return [ + 'id' => $this->getId(), + 'guid' => $this->getGuid(), + 'guidHash' => $this->getGuidHash(), + 'url' => $this->getUrl(), + 'title' => $this->getTitle(), + 'author' => $this->getAuthor(), + 'pubDate' => $this->getPubDate(), + 'body' => $this->getBody(), + 'enclosureMime' => $this->getEnclosureMime(), + 'enclosureLink' => $this->getEnclosureLink(), + 'feedId' => $this->getFeedId(), + 'unread' => $this->isUnread(), + 'starred' => $this->isStarred(), + 'lastModified' => $this->getLastModified(), + 'rtl' => $this->getRtl(), + 'fingerprint' => $this->getFingerprint(), + 'contentHash' => $this->getContentHash() + ]; + } + + public function toExport($feeds) { + return [ + 'guid' => $this->getGuid(), + 'url' => $this->getUrl(), + 'title' => $this->getTitle(), + 'author' => $this->getAuthor(), + 'pubDate' => $this->getPubDate(), + 'body' => $this->getBody(), + 'enclosureMime' => $this->getEnclosureMime(), + 'enclosureLink' => $this->getEnclosureLink(), + 'unread' => $this->isUnread(), + 'starred' => $this->isStarred(), + 'feedLink' => $feeds['feed' . $this->getFeedId()]->getLink(), + 'rtl' => $this->getRtl(), + ]; + } + + public function getIntro() { + return strip_tags($this->getBody()); + } + + public static function fromImport($import) { + $item = new static(); + $item->setGuid($import['guid']); + $item->setGuidHash($import['guid']); + $item->setUrl($import['url']); + $item->setTitle($import['title']); + $item->setAuthor($import['author']); + $item->setPubDate($import['pubDate']); + $item->setBody($import['body']); + $item->setEnclosureMime($import['enclosureMime']); + $item->setEnclosureLink($import['enclosureLink']); + $item->setRtl($import['rtl']); + if ($import['unread']) { + $item->setUnread(); + } else { + $item->setRead(); + } + if ($import['starred']) { + $item->setStarred(); + } else { + $item->setUnstarred(); + } + + return $item; + } + + public function setAuthor($name) { + parent::setAuthor(strip_tags($name)); + } + + public function setTitle($title) { + parent::setTitle(strip_tags($title)); + } + + public function generateSearchIndex() { + $this->setSearchIndex( + mb_strtolower( + html_entity_decode(strip_tags($this->getBody())) . + html_entity_decode($this->getAuthor()) . + html_entity_decode($this->getTitle()) . + $this->getUrl(), + 'UTF-8' + ) + ); + $this->setFingerprint($this->computeFingerprint()); + $this->setContentHash($this->computeContentHash()); + } + + private |