diff options
Diffstat (limited to 'db')
-rw-r--r-- | db/doesnotexistexception.php | 31 | ||||
-rw-r--r-- | db/entity.php | 222 | ||||
-rw-r--r-- | db/entityjsonserializer.php (renamed from db/multipleobjectsreturnedexception.php) | 19 | ||||
-rw-r--r-- | db/feed.php | 87 | ||||
-rw-r--r-- | db/feedmapper.php | 30 | ||||
-rw-r--r-- | db/folder.php | 37 | ||||
-rw-r--r-- | db/foldermapper.php | 23 | ||||
-rw-r--r-- | db/imapper.php | 13 | ||||
-rw-r--r-- | db/item.php | 71 | ||||
-rw-r--r-- | db/itemmapper.php | 114 | ||||
-rw-r--r-- | db/mapper.php | 273 | ||||
-rw-r--r-- | db/mapperfactory.php | 10 | ||||
-rw-r--r-- | db/postgres/itemmapper.php | 12 |
13 files changed, 255 insertions, 687 deletions
diff --git a/db/doesnotexistexception.php b/db/doesnotexistexception.php deleted file mode 100644 index ef2e9dd7d..000000000 --- a/db/doesnotexistexception.php +++ /dev/null @@ -1,31 +0,0 @@ -<?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; - - -/** - * This is returned or should be returned when a find request does not find an - * entry in the database - */ -class DoesNotExistException extends \Exception { - - /** - * Constructor - * @param string $msg the error message - */ - public function __construct($msg){ - parent::__construct($msg); - } - -}
\ No newline at end of file diff --git a/db/entity.php b/db/entity.php deleted file mode 100644 index 194895fee..000000000 --- a/db/entity.php +++ /dev/null @@ -1,222 +0,0 @@ -<?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; - -/** - * @method integer getId() - * @method void setId(integer $value) - */ -abstract class Entity { - - public $id; - - private $_updatedFields = array(); - private $_fieldTypes = array('id' => 'integer'); - - - /** - * Simple alternative constructor for building entities from a request - * @param array $params the array which was obtained via $this->params('key') - * in the controller - * @return Entity - */ - public static function fromParams(array $params) { - $instance = new static(); - - foreach($params as $key => $value) { - $method = 'set' . ucfirst($key); - $instance->$method($value); - } - - return $instance; - } - - - /** - * Maps the keys of the row array to the attributes - * @param array $row the row to map onto the entity - */ - public static function fromRow(array $row){ - $instance = new static(); - - foreach($row as $key => $value){ - $prop = ucfirst($instance->columnToProperty($key)); - $setter = 'set' . $prop; - $instance->$setter($value); - } - - $instance->resetUpdatedFields(); - - return $instance; - } - - - /** - * @return an array with attribute and type - */ - public function getFieldTypes() { - return $this->_fieldTypes; - } - - - /** - * Marks the entity as clean needed for setting the id after the insertion - */ - public function resetUpdatedFields(){ - $this->_updatedFields = array(); - } - - - protected function setter($name, $args) { - // setters should only work for existing attributes - if(property_exists($this, $name)){ - $this->markFieldUpdated($name); - - // if type definition exists, cast to correct type - if($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) { - settype($args[0], $this->_fieldTypes[$name]); - } - $this->$name = $args[0]; - - } else { - throw new \BadFunctionCallException($name . - ' is not a valid attribute'); - } - } - - - protected function getter($name) { - // getters should only work for existing attributes - if(property_exists($this, $name)){ - return $this->$name; - } else { - throw new \BadFunctionCallException($name . - ' is not a valid attribute'); - } - } - - - /** - * Each time a setter is called, push the part after set - * into an array: for instance setId will save Id in the - * updated fields array so it can be easily used to create the - * getter method - */ - public function __call($methodName, $args){ - $attr = lcfirst( substr($methodName, 3) ); - - if(strpos($methodName, 'set') === 0){ - $this->setter($attr, $args); - } elseif(strpos($methodName, 'get') === 0) { - return $this->getter($attr); - } else { - throw new \BadFunctionCallException($methodName . - ' does not exist'); - } - - } - - - /** - * Mark am attribute as updated - * @param string $attribute the name of the attribute - */ - protected function markFieldUpdated($attribute){ - $this->_updatedFields[$attribute] = true; - } - - - /** - * Transform a database columnname to a property - * @param string $columnName the name of the column - * @return string the property name - */ - public function columnToProperty($columnName){ - $parts = explode('_', $columnName); - $property = null; - - foreach($parts as $part){ - if($property === null){ - $property = $part; - } else { - $property .= ucfirst($part); - } - } - - return $property; - } - - - /** - * Transform a property to a database column name - * @param string $property the name of the property - * @return string the column name - */ - public function propertyToColumn($property){ - $parts = preg_split('/(?=[A-Z])/', $property); - $column = null; - - foreach($parts as $part){ - if($column === null){ - $column = $part; - } else { - $column .= '_' . lcfirst($part); - } - } - - return $column; - } - - - /** - * @return array array of updated fields for update query - */ - public function getUpdatedFields(){ - return $this->_updatedFields; - } - - - /** - * Adds type information for a field so that its automatically casted to - * that value once its being returned from the database - * @param string $fieldName the name of the attribute - * @param string $type the type which will be used to call settype() - */ - protected function addType($fieldName, $type){ - $this->_fieldTypes[$fieldName] = $type; - } - - - /** - * Slugify the value of a given attribute - * Warning: This doesn't result in a unique value - * @param string $attributeName the name of the attribute, which value should be slugified - * @return string slugified value - */ - public function slugify($attributeName){ - // toSlug should only work for existing attributes - if(property_exists($this, $attributeName)){ - $value = $this->$attributeName; - // replace everything except alphanumeric with a single '-' - $value = preg_replace('/[^A-Za-z0-9]+/', '-', $value); - $value = strtolower($value); - // trim '-' - return trim($value, '-'); - } else { - throw new \BadFunctionCallException($attributeName . - ' is not a valid attribute'); - } - } - -} diff --git a/db/multipleobjectsreturnedexception.php b/db/entityjsonserializer.php index 922d7a22a..7e3357304 100644 --- a/db/multipleobjectsreturnedexception.php +++ b/db/entityjsonserializer.php @@ -13,19 +13,16 @@ namespace OCA\News\Db; +trait EntityJSONSerializer { -/** - * This is returned or should be returned when a find request finds more than one - * row - */ -class MultipleObjectsReturnedException extends \Exception { - /** - * Constructor - * @param string $msg the error message - */ - public function __construct($msg){ - parent::__construct($msg); + public function serializeFields($properties) { + $result = []; + foreach($properties as $property) { + $result[$property] = $this->$property; + } + return $result; } + }
\ No newline at end of file diff --git a/db/feed.php b/db/feed.php index 280b7362f..c5b76656e 100644 --- a/db/feed.php +++ b/db/feed.php @@ -13,6 +13,8 @@ namespace OCA\News\Db; +use \OCP\AppFramework\Db\Entity; + /** * @method integer getId() * @method void setId(integer $value) @@ -21,7 +23,6 @@ namespace OCA\News\Db; * @method string getUrlHash() * @method void setUrlHash(string $value) * @method string getUrl() - * @method void setUrl(string $value) * @method string getTitle() * @method void setTitle(string $value) * @method string getFaviconLink() @@ -33,7 +34,6 @@ namespace OCA\News\Db; * @method integer getUnreadCount() * @method void setUnreadCount(integer $value) * @method string getLink() - * @method void setLink(string $value) * @method boolean getPreventUpdate() * @method void setPreventUpdate(boolean $value) * @method integer getDeletedAt() @@ -41,20 +41,22 @@ namespace OCA\News\Db; * @method integer getArticlesPerUpdate() * @method void setArticlesPerUpdate(integer $value) */ -class Feed extends Entity implements IAPI { - - public $userId; - public $urlHash; - public $url; - public $title; - public $faviconLink; - public $added; - public $folderId; - public $unreadCount; - public $link; - public $preventUpdate; - public $deletedAt; - public $articlesPerUpdate; +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; public function __construct(){ $this->addType('parentId', 'integer'); @@ -67,17 +69,50 @@ class Feed extends Entity implements IAPI { } + /** + * 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', + ]); + + $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 array( - 'id' => $this->getId(), - 'url' => $this->getUrl(), - 'title' => $this->getTitle(), - 'faviconLink' => $this->getFaviconLink(), - 'added' => $this->getAdded(), - 'folderId' => $this->getFolderId(), - 'unreadCount' => $this->getUnreadCount(), - 'link' => $this->getLink() - ); + return $this->serializeFields([ + 'id', + 'url', + 'title', + 'faviconLink', + 'added', + 'folderId', + 'unreadCount', + 'link' + ]); } diff --git a/db/feedmapper.php b/db/feedmapper.php index a69f1fa89..9753ed718 100644 --- a/db/feedmapper.php +++ b/db/feedmapper.php @@ -13,13 +13,15 @@ namespace OCA\News\Db; -use \OCA\News\Core\Db; +use \OCP\IDb; +use \OCP\AppFramework\Db\Mapper; +use \OCP\AppFramework\Db\Entity; class FeedMapper extends Mapper implements IMapper { - public function __construct(Db $db) { + public function __construct(IDb $db) { parent::__construct($db, 'news_feeds', '\OCA\News\Db\Feed'); } @@ -41,7 +43,7 @@ class FeedMapper extends Mapper implements IMapper { '`feeds`.`url`, `feeds`.`title`, `feeds`.`link`,'. '`feeds`.`favicon_link`, `feeds`.`added`, `feeds`.`articles_per_update`,'. '`feeds`.`folder_id`, `feeds`.`prevent_update`, `feeds`.`deleted_at`'; - $params = array($id, $userId); + $params = [$id, $userId]; return $this->findEntity($sql, $params); } @@ -69,7 +71,7 @@ class FeedMapper extends Mapper implements IMapper { '`feeds`.`url`, `feeds`.`title`, `feeds`.`link`,'. '`feeds`.`favicon_link`, `feeds`.`added`, `feeds`.`articles_per_update`,'. '`feeds`.`folder_id`, `feeds`.`prevent_update`, `feeds`.`deleted_at`'; - $params = array($userId); + $params = [$userId]; return $this->findEntities($sql, $params); } @@ -83,7 +85,7 @@ class FeedMapper extends Mapper implements IMapper { '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 + // because prepared statements don't work. This is a possible // SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. // think twice when changing this 'AND (`items`.`status` & ' . StatusFlag::UNREAD . ') = ' . @@ -118,13 +120,9 @@ class FeedMapper extends Mapper implements IMapper { '`feeds`.`url`, `feeds`.`title`, `feeds`.`link`,'. '`feeds`.`favicon_link`, `feeds`.`added`, `feeds`.`articles_per_update`,'. '`feeds`.`folder_id`, `feeds`.`prevent_update`, `feeds`.`deleted_at`'; - $params = array($hash, $userId); - - $row = $this->findOneQuery($sql, $params); - $feed = new Feed(); - $feed->fromRow($row); + $params = [$hash, $userId]; - return $feed; + return $this->findEntity($sql, $params); } @@ -134,7 +132,7 @@ class FeedMapper extends Mapper implements IMapper { // someone please slap me for doing this manually :P // we needz CASCADE + FKs please $sql = 'DELETE FROM `*PREFIX*news_items` WHERE `feed_id` = ?'; - $params = array($entity->getId()); + $params = [$entity->getId()]; $this->execute($sql, $params); } @@ -148,18 +146,18 @@ class FeedMapper extends Mapper implements IMapper { public function getToDelete($deleteOlderThan=null, $userId=null) { $sql = 'SELECT * FROM `*PREFIX*news_feeds` ' . 'WHERE `deleted_at` > 0 '; - $params = array(); + $params = []; // sometimes we want to delete all entries if ($deleteOlderThan !== null) { $sql .= 'AND `deleted_at` < ? '; - array_push($params, $deleteOlderThan); + $params[] = $deleteOlderThan; } // we need to sometimes only delete feeds of a user if($userId !== null) { $sql .= 'AND `user_id` = ?'; - array_push($params, $userId); + $params[] = $userId; } return $this->findEntities($sql, $params); @@ -173,7 +171,7 @@ class FeedMapper extends Mapper implements IMapper { */ public function deleteUser($userId) { $sql = 'DELETE FROM `*PREFIX*news_feeds` WHERE `user_id` = ?'; - $this->execute($sql, array($userId)); + $this->execute($sql, [$userId]); } diff --git a/db/folder.php b/db/folder.php index f8fb3df58..d5f50685f 100644 --- a/db/folder.php +++ b/db/folder.php @@ -13,6 +13,8 @@ namespace OCA\News\Db; +use \OCP\AppFramework\Db\Entity; + /** * @method integer getId() * @method void setId(integer $value) @@ -27,13 +29,15 @@ namespace OCA\News\Db; * @method integer getDeletedAt() * @method void setDeletedAt(integer $value) */ -class Folder extends Entity implements IAPI { +class Folder extends Entity implements IAPI, \JsonSerializable { + + use EntityJSONSerializer; - public $parentId; - public $name; - public $userId; - public $opened; - public $deletedAt; + protected $parentId; + protected $name; + protected $userId; + protected $opened; + protected $deletedAt; public function __construct(){ $this->addType('parentId', 'integer'); @@ -41,11 +45,24 @@ class Folder extends Entity implements IAPI { $this->addType('deletedAt', 'integer'); } + /** + * Turns entitie attributes into an array + */ + public function jsonSerialize() { + return $this->serializeFields([ + 'id', + 'parentId', + 'name', + 'userId', + 'opened', + 'deletedAt', + ]); + } public function toAPI() { - return array( - 'id' => $this->getId(), - 'name' => $this->getName() - ); + return $this->serializeFields([ + 'id', + 'name' + ]); } }
\ No newline at end of file diff --git a/db/foldermapper.php b/db/foldermapper.php index 017ccd0db..62ca09747 100644 --- a/db/foldermapper.php +++ b/db/foldermapper.php @@ -13,12 +13,13 @@ namespace OCA\News\Db; -use \OCA\News\Core\Db; - +use \OCP\IDb; +use \OCP\AppFramework\Db\Mapper; +use \OCP\AppFramework\Db\Entity; class FolderMapper extends Mapper implements IMapper { - public function __construct(Db $db) { + public function __construct(IDb $db) { parent::__construct($db, 'news_folders', '\OCA\News\Db\Folder'); } @@ -27,7 +28,7 @@ class FolderMapper extends Mapper implements IMapper { 'WHERE `id` = ? ' . 'AND `user_id` = ?'; - return $this->findEntity($sql, array($id, $userId)); + return $this->findEntity($sql, [$id, $userId]); } @@ -35,7 +36,7 @@ class FolderMapper extends Mapper implements IMapper { $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . 'WHERE `user_id` = ? ' . 'AND `deleted_at` = 0'; - $params = array($userId); + $params = [$userId]; return $this->findEntities($sql, $params); } @@ -45,7 +46,7 @@ class FolderMapper extends Mapper implements IMapper { $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . 'WHERE `name` = ? ' . 'AND `user_id` = ?'; - $params = array($folderName, $userId); + $params = [$folderName, $userId]; return $this->findEntities($sql, $params); } @@ -57,7 +58,7 @@ class FolderMapper extends Mapper implements IMapper { // someone please slap me for doing this manually :P // we needz CASCADE + FKs please $sql = 'DELETE FROM `*PREFIX*news_feeds` WHERE `folder_id` = ?'; - $params = array($entity->getId()); + $params = [$entity->getId()]; $this->execute($sql, $params); $sql = 'DELETE FROM `*PREFIX*news_items` WHERE `feed_id` NOT IN '. @@ -76,18 +77,18 @@ class FolderMapper extends Mapper implements IMapper { public function getToDelete($deleteOlderThan=null, $userId=null) { $sql = 'SELECT * FROM `*PREFIX*news_folders` ' . 'WHERE `deleted_at` > 0 '; - $params = array(); + $params = []; // sometimes we want to delete all entries if ($deleteOlderThan !== null) { $sql .= 'AND `deleted_at` < ? '; - array_push($params, $deleteOlderThan); + $params[] = $deleteOlderThan; } // we need to sometimes only delete feeds of a user if($userId !== null) { $sql .= 'AND `user_id` = ?'; - array_push($params, $userId); + $params[] = $userId; } return $this->findEntities($sql, $params); @@ -100,7 +101,7 @@ class FolderMapper extends Mapper implements IMapper { */ public function deleteUser($userId) { $sql = 'DELETE FROM `*PREFIX*news_folders` WHERE `user_id` = ?'; - $this->execute($sql, array($userId)); + $this->execute($sql, [$userId]); } diff --git a/db/imapper.php b/db/imapper.php index 5a5f0a3cc..18a924e24 100644 --- a/db/imapper.php +++ b/db/imapper.php @@ -13,10 +13,23 @@ namespace OCA\News\Db; +use \OCP\AppFramework\Db\Entity; + interface IMapper { + /** * @param int $id the id of the feed * @param string $userId the id of the user + * @return \OCP\AppFramework\Db\Entity */ public function find($id, $userId); + + /** + * Delete an entity + * @param Entity $entity the entity that should be deleted + * @throws \OCP\AppFramework\Db\DoesNotExistException if the entity does + * not exist, or there + * are more than one of it + */ + public function delete(Entity $entity); }
\ No newline at end of file diff --git a/db/item.php b/db/item.php index 7d3d4dce7..a53c825ff 100644 --- a/db/item.php +++ b/db/item.php @@ -13,23 +13,21 @@ namespace OCA\News\Db; +use \OCP\AppFramework\Db\Entity; + + /** * @method integer getId() * @method void setId(integer $value) * @method string getGuidHash() * @method void setGuidHash(string $value) * @method string getGuid() - * @method void setGuid(string $value) * @method string getUrl() - * @method void setUrl(string $value) * @method string getTitle() - * @method void setTitle(string $value) * @method string getAuthor() - * @method void setAuthor(string $value) * @method integer getPubDate() * @method void setPubDate(integer $value) * @method string getBody() - * @method void setBody(string $value) * @method string getEnclosureMime() * @method void setEnclosureMime(string $value) * @method string getEnclosureLink() @@ -41,21 +39,22 @@ namespace OCA\News\Db; * @method integer getLastModified() * @method void setLastModified(integer $value) */ -class Item extends Entity implements IAPI { - - public $guidHash; - public $guid; - public $url; - public $title; - public $author; - public $pubDate; - public $body; - public $enclosureMime; - public $enclosureLink; - public $feedId; - public $status = 0; - public $lastModified; - +class Item extends Entity implements IAPI, \JsonSerializable { + + use EntityJSONSerializer; + + 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; public function __construct(){ $this->addType('pubDate', 'integer'); @@ -101,9 +100,30 @@ class Item extends Entity implements IAPI { 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() + ]; + } public function toAPI() { - return array( + return [ 'id' => $this->getId(), 'guid' => $this->getGuid(), 'guidHash' => $this->getGuidHash(), @@ -118,12 +138,12 @@ class Item extends Entity implements IAPI { 'unread' => $this->isUnread(), 'starred' => $this->isStarred(), 'lastModified' => $this->getLastModified() - ); + ]; } public function toExport($feeds) { - return array( + return [ 'guid' => $this->getGuid(), 'url' => $this->getUrl(), 'title' => $this->getTitle(), @@ -135,7 +155,7 @@ class Item extends Entity implements IAPI { 'unread' => $this->isUnread(), 'starred' => $this->isStarred(), 'feedLink' => $feeds['feed'. $this->getFeedId()]->getLink() - ); + ]; } @@ -159,8 +179,7 @@ class Item extends Entity implements IAPI { } else { $item->setUnstarred(); } - - $item->setFeedId(null); + return $item; } diff --git a/db/itemmapper.php b/db/itemmapper.php index b223a8aaf..ff8643236 100644 --- a/db/itemmapper.php +++ b/db/itemmapper.php @@ -13,16 +13,24 @@ namespace OCA\News\Db; -use \OCA\News\Core\Db; +use \OCP\IDb; +use \OCP\AppFramework\Db\Mapper; + class ItemMapper extends Mapper implements IMapper { - public function __construct(Db $db){ + public function __construct(IDb $db){ parent::__construct($db, 'news_items', '\OCA\News\Db\Item'); } - private function makeSelectQuery($prependTo){ + private function makeSelectQuery($prependTo, $oldestFirst=false){ + if($oldestFirst) { + $ordering = 'ASC'; + } else { + $ordering = 'DESC'; + } + return 'SELECT `items`.* FROM `*PREFIX*news_items` `items` '. 'JOIN `*PREFIX*news_feeds` `feeds` ' . 'ON `feeds`.`id` = `items`.`feed_id` '. @@ -33,10 +41,10 @@ class ItemMapper extends Mapper implements IMapper { 'ON `folders`.`id` = `feeds`.`folder_id` ' . 'WHERE `feeds`.`folder_id` = 0 ' . 'OR `folders`.`deleted_at` = 0 ' . - 'ORDER BY `items`.`id` DESC'; + 'ORDER BY `items`.`id` ' . $ordering; } - private function makeSelectQueryStatus($prependTo, $status) { + private function makeSelectQueryStatus($prependTo, $status, $oldestFirst=false) { // Hi this is Ray and you're watching Jack Ass // Now look closely: this is how we adults handle weird bugs in our // code: we take them variables and we cast the shit out of them @@ -55,30 +63,31 @@ class ItemMapper extends Mapper implements IMapper { // SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT. // think twice when changing this 'AND ((`items`.`status` & ' . $status . ') = ' . $status . ') ' . - $prependTo + $prependTo, $oldestFirst ); } public function find($id, $userId){ $sql = $this->makeSelectQuery('AND `items`.`id` = ? '); - return $this->findEntity($sql, array($userId, $id)); + return $this->findEntity($sql, [$userId, $id]); } public function starredCount($userId){ - $sql = 'SELECT COUNT(*) AS size FROM `*PREFIX*news_feeds` `feeds` ' . - 'JOIN `*PREFIX*news_items` `items` ' . - 'ON `items`.`feed_id` = `feeds`.`id` ' . + $sql = 'SELECT COUNT(*) AS size FROM `*PREFIX*news_items` `items` '. + 'JOIN `*PREFIX*news_feeds` `feeds` ' . + 'ON `feeds`.`id` = `items`.`feed_id` '. + 'AND `feeds`.`deleted_at` = 0 ' . 'AND `feeds`.`user_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 - 'WHERE ((`items`.`status` & ' . StatusFlag::STARRED . ') = ' . - StatusFlag::STARRED . ')'; + 'AND ((`items`.`status` & ' . StatusFlag::STARRED . ') = ' . + StatusFlag::STARRED . ')' . + 'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' . + 'ON `folders`.`id` = `feeds`.`folder_id` ' . + 'WHERE `feeds`.`folder_id` = 0 ' . + 'OR `folders`.`deleted_at` = 0'; - $params = array($userId); + $params = [$userId]; $result = $this->execute($sql, $params)->fetch(); @@ -95,7 +104,7 @@ class ItemMapper extends Mapper implements IMapper { 'WHERE `user_id` = ? ' . ') '. 'AND `id` <= ?'; - $params = array(~StatusFlag::UNREAD, $time, $userId, $highestItemId); + $params = [~StatusFlag::UNREAD, $time, $userId, $highestItemId]; $this->execute($sql, $params); } @@ -110,8 +119,8 @@ class ItemMapper extends Mapper implements IMapper { 'AND `user_id` = ? ' . ') '. 'AND `id` <= ?'; - $params = array(~StatusFlag::UNREAD, $time, $folderId, $userId, - $highestItemId); + $params = [~StatusFlag::UNREAD, $time, $folderId, $userId, + $highestItemId]; $this->execute($sql, $params); } @@ -126,17 +135,26 @@ class ItemMapper extends Mapper implements IMapper { 'SELECT * FROM `*PREFIX*news_feeds` ' . 'WHERE `user_id` = ? ' . 'AND `id` = ? ) '; - $params = array(~StatusFlag::UNREAD, $time, $feedId, $highestItemId, - $userId, $feedId); + $params = [~StatusFlag::UNREAD, $time, $feedId, $highestItemId, + $userId, $feedId]; $this->execute($sql, $params); } + private function getOperator($oldestFirst) { + if($oldestFirst) { + return '>'; + } else { + return '<'; + } + } + + public function findAllNew($updatedSince, $status, $userId){ $sql = $this->makeSelectQueryStatus( 'AND `items`.`last_modified` >= ? ', $status); - $params = array($userId, $updatedSince); + $params = [$userId, $updatedSince]; return $this->findEntities($sql, $params); } @@ -145,7 +163,7 @@ class ItemMapper extends Mapper implements IMapper { $sql = 'AND `feeds`.`folder_id` = ? ' . 'AND `items`.`last_modified` >= ? '; $sql = $this->makeSelectQueryStatus($sql, $status); - $params = array($userId, $id, $updatedSince); + $params = [$userId, $id, $updatedSince]; return $this->findEntities($sql, $params); } @@ -154,49 +172,49 @@ class ItemMapper extends Mapper implements IMapper { $sql = 'AND `items`.`feed_id` = ? ' . 'AND `items`.`last_modified` >= ? '; $sql = $this->makeSelectQueryStatus($sql, $status); - $params = array($userId, $id, $updatedSince); + $params = [$userId, $id, $updatedSince]; return $this->findEntities($sql, $params); } - public function findAllFeed($id, $limit, $offset, $status, $userId){ - $params = array($userId, $id); + public function findAllFeed($id, $limit, $offset, $status, $oldestFirst, $userId){ + $params = [$userId, $id]; $sql = 'AND `items`.`feed_id` = ? '; if($offset !== 0){ - $sql .= 'AND `items`.`id` < ? '; - array_push($params, $offset); + $sql .= 'AND `items`.`id` ' . $this->getOperator($oldestFirst) . ' ? '; + $params[] = $offset; } - $sql = $this->make |