From 464ff6c4c1bda3edbd0f132c4d3d866539d3a117 Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Mon, 15 Apr 2013 16:02:32 +0200 Subject: renamed bl to businesslayer, handle exception in update routine, fix #69 --- businesslayer/businesslayer.php | 59 +++++++++++ businesslayer/businesslayerexception.php | 39 ++++++++ businesslayer/feedbusinesslayer.php | 167 +++++++++++++++++++++++++++++++ businesslayer/folderbusinesslayer.php | 94 +++++++++++++++++ businesslayer/itembusinesslayer.php | 143 ++++++++++++++++++++++++++ 5 files changed, 502 insertions(+) create mode 100644 businesslayer/businesslayer.php create mode 100644 businesslayer/businesslayerexception.php create mode 100644 businesslayer/feedbusinesslayer.php create mode 100644 businesslayer/folderbusinesslayer.php create mode 100644 businesslayer/itembusinesslayer.php (limited to 'businesslayer') diff --git a/businesslayer/businesslayer.php b/businesslayer/businesslayer.php new file mode 100644 index 000000000..4ce6f1625 --- /dev/null +++ b/businesslayer/businesslayer.php @@ -0,0 +1,59 @@ +. +* +*/ + +namespace OCA\News\BusinessLayer; + +use \OCA\AppFramework\Db\DoesNotExistException; +use \OCA\AppFramework\Db\MultipleObjectsReturnedException; + +use \OCA\News\Db\IMapper; + + +abstract class BusinessLayer { + + protected $mapper; + + public function __construct(IMapper $mapper){ + $this->mapper = $mapper; + } + + + public function delete($id, $userId){ + $entity = $this->find($id, $userId); + $this->mapper->delete($entity); + } + + + public function find($id, $userId){ + try { + return $this->mapper->find($id, $userId); + } catch(DoesNotExistException $ex){ + throw new BusinessLayerException($ex->getMessage()); + } catch(MultipleObjectsReturnedException $ex){ + throw new BusinessLayerException($ex->getMessage()); + } + } + +} \ No newline at end of file diff --git a/businesslayer/businesslayerexception.php b/businesslayer/businesslayerexception.php new file mode 100644 index 000000000..03219a20f --- /dev/null +++ b/businesslayer/businesslayerexception.php @@ -0,0 +1,39 @@ +. +* +*/ + +namespace OCA\News\BusinessLayer; + + +class BusinessLayerException 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/businesslayer/feedbusinesslayer.php b/businesslayer/feedbusinesslayer.php new file mode 100644 index 000000000..f7666fc1c --- /dev/null +++ b/businesslayer/feedbusinesslayer.php @@ -0,0 +1,167 @@ +. +* +*/ + +namespace OCA\News\BusinessLayer; + +use \OCA\AppFramework\Db\DoesNotExistException; +use \OCA\AppFramework\Core\API; + +use \OCA\News\Db\Feed; +use \OCA\News\Db\FeedMapper; +use \OCA\News\Db\ItemMapper; +use \OCA\News\Utility\Fetcher; +use \OCA\News\Utility\FetcherException; + +class FeedBusinessLayer extends BusinessLayer { + + private $feedFetcher; + private $itemMapper; + private $api; + + public function __construct(FeedMapper $feedMapper, Fetcher $feedFetcher, + ItemMapper $itemMapper, API $api){ + parent::__construct($feedMapper); + $this->feedFetcher = $feedFetcher; + $this->itemMapper = $itemMapper; + $this->api = $api; + } + + + public function findAll($userId){ + return $this->mapper->findAllFromUser($userId); + } + + + public function create($feedUrl, $folderId, $userId){ + // first try if the feed exists already + try { + $this->mapper->findByUrlHash(md5($feedUrl), $userId); + throw new BusinessLayerException( + $this->api->getTrans()->t('Can not add feed: Exists already')); + } catch(DoesNotExistException $ex){} + + try { + list($feed, $items) = $this->feedFetcher->fetch($feedUrl); + + // insert feed + $feed->setFolderId($folderId); + $feed->setUserId($userId); + $feed = $this->mapper->insert($feed); + + // insert items in reverse order because the first one is usually the + // newest item + for($i=count($items)-1; $i>=0; $i--){ + $item = $items[$i]; + $item->setFeedId($feed->getId()); + $this->itemMapper->insert($item); + } + + // set unread count + $feed->setUnreadCount(count($items)); + + return $feed; + } catch(FetcherException $ex){ + $this->api->log($ex->getMessage()); + throw new BusinessLayerException( + $this->api->getTrans()->t( + 'Can not add feed: URL does not exist or has invalid xml')); + } + } + + + // FIXME: this method is not covered by any tests + public function updateAll(){ + $feeds = $this->mapper->findAll(); + foreach($feeds as $feed){ + try { + $this->update($feed->getId(), $feed->getUserId()); + } catch(BusinessLayerException $ex){ + continue; + } + } + } + + + public function update($feedId, $userId){ + try { + $existingFeed = $this->mapper->find($feedId, $userId); + try { + list($feed, $items) = $this->feedFetcher->fetch($existingFeed->getUrl()); + + // insert items in reverse order because the first one is usually the + // newest item + for($i=count($items)-1; $i>=0; $i--){ + $item = $items[$i]; + $item->setFeedId($existingFeed->getId()); + + // if a doesnotexist exception is being thrown the entry does not + // exist and the item needs to be created, otherwise + // update it + try { + $existing = $this->itemMapper->findByGuidHash( + $item->getGuidHash(), $feedId, $userId); + + // in case of an update the existing item has to be deleted + // if the pub_date changed because we sort by id on the + // client side since this is the only reliable way to do it + // to not get weird behaviour + if($existing->getPubDate() !== $item->getPubDate()){ + + // because the item is being replaced we need to keep + // status flags but we want the new entry to be unread + $item->setStatus($existing->getStatus()); + $item->setUnread(); + + $this->itemMapper->delete($existing); + $this->itemMapper->insert($item); + } + + } catch(DoesNotExistException $ex){ + $this->itemMapper->insert($item); + } + } + + } catch(FetcherException $ex){ + // failed updating is not really a problem, so only log it + $this->api->log('Can not update feed with url' . $existingFeed->getUrl() . + ': Not found or bad source'); + } + + return $this->mapper->find($feedId, $userId); + + } catch (DoesNotExistException $ex){ + throw new BusinessLayerException('Feed does not exist'); + } + } + + + public function move($feedId, $folderId, $userId){ + $feed = $this->find($feedId, $userId); + $feed->setFolderId($folderId); + $this->mapper->update($feed); + } + + +} diff --git a/businesslayer/folderbusinesslayer.php b/businesslayer/folderbusinesslayer.php new file mode 100644 index 000000000..916476896 --- /dev/null +++ b/businesslayer/folderbusinesslayer.php @@ -0,0 +1,94 @@ +. +* +*/ + +namespace OCA\News\BusinessLayer; + +use \OCA\AppFramework\Core\API; + +use \OCA\News\Db\Folder; +use \OCA\News\Db\FolderMapper; + + +class FolderBusinessLayer extends BusinessLayer { + + private $api; + + public function __construct(FolderMapper $folderMapper, + API $api){ + parent::__construct($folderMapper); + $this->api = $api; + } + + + public function findAll($userId) { + return $this->mapper->findAllFromUser($userId); + } + + + private function allowNoNameTwice($folderName, $userId){ + $existingFolders = $this->mapper->findByName($folderName, $userId); + if(count($existingFolders) > 0){ + + throw new BusinessLayerException( + $this->api->getTrans()->t('Can not add folder: Exists already')); + } + } + + /** + * @throws BusinessLayerException if name exists already + */ + public function create($folderName, $userId, $parentId=0) { + $this->allowNoNameTwice($folderName, $userId); + + $folder = new Folder(); + $folder->setName($folderName); + $folder->setUserId($userId); + $folder->setParentId($parentId); + $folder->setOpened(true); + return $this->mapper->insert($folder); + } + + + public function open($folderId, $opened, $userId){ + $folder = $this->find($folderId, $userId); + $folder->setOpened($opened); + $this->mapper->update($folder); + } + + + /** + * @throws BusinessLayerException if name exists already + */ + public function rename($folderId, $folderName, $userId){ + $this->allowNoNameTwice($folderName, $userId); + + $folder = $this->find($folderId, $userId); + $folder->setName($folderName); + $this->mapper->update($folder); + } + + + +} diff --git a/businesslayer/itembusinesslayer.php b/businesslayer/itembusinesslayer.php new file mode 100644 index 000000000..fd01506a6 --- /dev/null +++ b/businesslayer/itembusinesslayer.php @@ -0,0 +1,143 @@ +. +* +*/ + +namespace OCA\News\BusinessLayer; + +use \OCA\News\Db\Item; +use \OCA\News\Db\ItemMapper; +use \OCA\News\Db\StatusFlag; +use \OCA\News\Db\FeedType; + + +class ItemBusinessLayer extends BusinessLayer { + + private $statusFlag; + private $autoPurgeCount; + + public function __construct(ItemMapper $itemMapper, StatusFlag $statusFlag, + $autoPurgeCount=0){ + parent::__construct($itemMapper); + $this->statusFlag = $statusFlag; + $this->autoPurgeCount = $autoPurgeCount; + } + + + public function findAllNew($id, $type, $updatedSince, + $showAll, $userId){ + $status = $this->statusFlag->typeToStatus($type, $showAll); + + switch($type){ + case FeedType::FEED: + $items = $this->mapper->findAllNewFeed($id, $updatedSince, + $status, $userId); + break; + case FeedType::FOLDER: + $items = $this->mapper->findAllNewFolder($id, $updatedSince, + $status, $userId); + break; + default: + $items = $this->mapper->findAllNew($updatedSince, $status, + $userId); + } + + return $items; + } + + + public function findAll($id, $type, $limit, $offset, + $showAll, $userId){ + $status = $this->statusFlag->typeToStatus($type, $showAll); + + switch($type){ + case FeedType::FEED: + $items = $this->mapper->findAllFeed($id, $limit, $offset, + $status, $userId); + break; + case FeedType::FOLDER: + $items = $this->mapper->findAllFolder($id, $limit, $offset, + $status, $userId); + break; + default: + $items = $this->mapper->findAll($limit, $offset, $status, + $userId); + } + + return $items; + } + + + public function starredCount($userId){ + return $this->mapper->starredCount($userId); + } + + + public function star($feedId, $guidHash, $isStarred, $userId){ + // FIXME: this can throw two possible exceptions + $item = $this->mapper->findByGuidHash($guidHash, $feedId, $userId); + if($isStarred){ + $item->setStarred(); + } else { + $item->setUnstarred(); + } + $this->mapper->update($item); + } + + + public function read($itemId, $isRead, $userId){ + $item = $this->find($itemId, $userId); + if($isRead){ + $item->setRead(); + } else { + $item->setUnread(); + } + $this->mapper->update($item); + } + + + public function readFeed($feedId, $highestItemId, $userId){ + $this->mapper->readFeed($feedId, $highestItemId, $userId); + } + + + /** + * This method deletes all unread feeds that are not starred and over the + * count of $this->autoPurgeCount starting by the oldest. This is to clean + * up the database so that old entries dont spam your db. As criteria for + * old, the id is taken + */ + public function autoPurgeOld(){ + $readAndNotStarred = + $this->mapper->getReadOlderThanThreshold($this->autoPurgeCount); + + // delete entries with a lower id than last item + if($this->autoPurgeCount > 0 + && isset($readAndNotStarred[$this->autoPurgeCount-1])){ + $this->mapper->deleteReadOlderThanId( + $readAndNotStarred[$this->autoPurgeCount-1]->getId()); + } + } + + +} -- cgit v1.2.3