From 6f75252f8be5e76f29458b710083d6379704ce3d Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Wed, 10 Dec 2014 14:04:25 +0800 Subject: [PATCH] Popular downloads stuff. --- Controllers/SimfileController.php | 128 ++++++++++++++++++++++------ DataAccess/DownloadRepository.php | 11 +++ DataAccess/IDownloadRepository.php | 1 + DataAccess/Queries/IQueryBuilder.php | 3 + DataAccess/Queries/QueryBuilder.php | 59 ++++++++++++- DataAccess/StepMania/IPackRepository.php | 1 + DataAccess/StepMania/ISimfileRepository.php | 1 + DataAccess/StepMania/PackRepository.php | 12 ++- DataAccess/StepMania/SimfileRepository.php | 12 ++- config/Routes.php | 18 +++- 10 files changed, 211 insertions(+), 35 deletions(-) diff --git a/Controllers/SimfileController.php b/Controllers/SimfileController.php index ab63396..06fe869 100644 --- a/Controllers/SimfileController.php +++ b/Controllers/SimfileController.php @@ -11,8 +11,10 @@ use Services\ISMOMatcher; use DataAccess\StepMania\ISimfileRepository; use DataAccess\StepMania\IPackRepository; use DataAccess\IFileRepository; +use DataAccess\IDownloadRepository; use Domain\Entities\StepMania\ISimfile; use Domain\Entities\IFile; +use Domain\Entities\StepMania\IPack; use Domain\Util; class SimfileController implements IDivineController @@ -24,6 +26,7 @@ class SimfileController implements IDivineController private $_uploadManager; private $_zipParser; private $_smoMatcher; + private $_downloadRepository; public function __construct( IHttpResponse $response, @@ -33,7 +36,8 @@ class SimfileController implements IDivineController IFileRepository $fileRepository, IUserSession $userSession, IZipParser $zipParser, - ISMOMatcher $smoMatcher + ISMOMatcher $smoMatcher, + IDownloadRepository $downloadRepository ) { $this->_response = $response; $this->_uploadManager = $uploadManager; @@ -42,6 +46,7 @@ class SimfileController implements IDivineController $this->_fileRepository = $fileRepository; $this->_zipParser = $zipParser; $this->_smoMatcher = $smoMatcher; + $this->_downloadRepository = $downloadRepository; } public function indexAction() { @@ -64,34 +69,14 @@ class SimfileController implements IDivineController foreach($packs as $pack) { - $packSimfiles = array(); - foreach($pack->getSimfiles() as $simfile) - { - $packSimfiles[] = $this->simfileToArray($simfile); - } - - $packMirrors = array(); - - if($pack->getFile()) - { - $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash()); - } - - if($pack->getFile()->getMirrors()) - { - foreach($pack->getFile()->getMirrors() as $mirror) - { - $packMirrors[] = array('source' => $mirror->getSource(), 'uri' => $mirror->getUri()); - } - } - $packArray[] = array( 'title'=> $pack->getTitle(), 'contributors' => $pack->getContributors(), - 'simfiles' => $packSimfiles, + 'simfiles' => $this->getPackSimfilesArray($pack), 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default', - 'mirrors' => $packMirrors, - 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null + 'mirrors' => $this->getPackMirrorsArray($pack), + 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null, + 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null ); } @@ -102,6 +87,65 @@ class SimfileController implements IDivineController ->sendResponse(); } + public function latestSimfileAction() + { + $simfile = $this->_simfileRepository->findRange(0, -1); + $this->_response->setHeader('Content-Type', 'application/json') + ->setBody(json_encode($this->simfileToArray(reset($simfile)))) + ->sendResponse(); + } + + public function latestPackAction() + { + $pack = $this->_packRepository->findRange(0, -1); + $pack = reset($pack); + + $packArray = array( + 'title'=> $pack->getTitle(), + 'contributors' => $pack->getContributors(), + 'simfiles' => $this->getPackSimfilesArray($pack), + 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default', + 'mirrors' => $this->getPackMirrorsArray($pack), + 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null, + 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null + ); + + $this->_response->setHeader('Content-Type', 'application/json') + ->setBody(json_encode($packArray)) + ->sendResponse(); + } + + public function popularAction() + { + $returnArray = array(); + $popularDownloads = $this->_downloadRepository->findPopular(); + $popularDownloads = reset($popularDownloads); + $packOrFileId = $popularDownloads->getFile()->getId(); + + $simfile = $this->_simfileRepository->findByFileId($packOrFileId); + if($simfile) + { + $returnArray = $this->simfileToArray(reset($simfile)); + } else { + $pack = $this->_packRepository->findByFileId($packOrFileId); + $pack = reset($pack); + $returnArray = array( + 'title'=> $pack->getTitle(), + 'contributors' => $pack->getContributors(), + 'simfiles' => $this->getPackSimfilesArray($pack), + 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default', + 'mirrors' => $this->getPackMirrorsArray($pack), + 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null, + 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null + ); + } + + $this->_response->setHeader('Content-Type', 'application/json') + ->setBody(json_encode($returnArray)) + ->sendResponse(); + + } + public function uploadAction() { //TODO: Put directory in config ? @@ -139,6 +183,37 @@ class SimfileController implements IDivineController } } + private function getPackMirrorsArray(IPack $pack) + { + $packMirrors = array(); + + if($pack->getFile()) + { + $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash()); + } + + if($pack->getFile()->getMirrors()) + { + foreach($pack->getFile()->getMirrors() as $mirror) + { + $packMirrors[] = array('source' => $mirror->getSource(), 'uri' => $mirror->getUri()); + } + } + + return $packMirrors; + } + + private function getPackSimfilesArray(IPack $pack) + { + $packSimfiles = array(); + foreach($pack->getSimfiles() as $simfile) + { + $packSimfiles[] = $this->simfileToArray($simfile); + } + + return $packSimfiles; + } + private function findAndAddSmoMirror(IFile $file) { $basename = pathinfo($file->getFilename(), PATHINFO_FILENAME); @@ -184,7 +259,8 @@ class SimfileController implements IDivineController 'bpmChanges' => $simfile->hasBPMChanges() ? 'Yes' : 'No', 'banner' => $simfile->getBanner() ? 'files/banner/' . $simfile->getBanner()->getHash() : 'files/banner/default', 'download' => $simfile->getSimfile() ? 'files/simfile/' . $simfile->getSimfile()->getHash() : null, - 'size' => $simfile->getSimfile() ? Util::bytesToHumanReadable($simfile->getSimfile()->getSize()) : null + 'size' => $simfile->getSimfile() ? Util::bytesToHumanReadable($simfile->getSimfile()->getSize()) : null, + 'uploaded' => $simfile->getSimfile() ? date('F jS, Y', $simfile->getSimfile()->getUploadDate()) : null ); } } diff --git a/DataAccess/DownloadRepository.php b/DataAccess/DownloadRepository.php index 544611e..e2bbf74 100644 --- a/DataAccess/DownloadRepository.php +++ b/DataAccess/DownloadRepository.php @@ -64,6 +64,17 @@ class DownloadRepository implements IDownloadRepository return $this->applyConstraintsAndReturn($constraints, $queryBuilder); } + public function findPopular() + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->count('file_id', 'hits') + ->group('file_id') + ->orderBy('hits', 'DESC') + ->limit(10); + + return $this->_dataMapper->map('Download', $queryBuilder); + } + private function applyConstraintsAndReturn(IDownloadQueryConstraints $constraints = NULL, IQueryBuilder $queryBuilder) { if($constraints) diff --git a/DataAccess/IDownloadRepository.php b/DataAccess/IDownloadRepository.php index e1052dd..a2df2db 100644 --- a/DataAccess/IDownloadRepository.php +++ b/DataAccess/IDownloadRepository.php @@ -10,6 +10,7 @@ interface IDownloadRepository extends IRepository { public function findByUserId($id, IDownloadQueryConstraints $constraints = null); public function findByFileId($id, IDownloadQueryConstraints $constraints = null); + public function findPopular(); public function save(IDownload $file); } diff --git a/DataAccess/Queries/IQueryBuilder.php b/DataAccess/Queries/IQueryBuilder.php index 69df99b..fb5ace6 100644 --- a/DataAccess/Queries/IQueryBuilder.php +++ b/DataAccess/Queries/IQueryBuilder.php @@ -15,5 +15,8 @@ interface IQueryBuilder public function where($column, $operator, $value); public function join($type, $tableA, $columnA, $tableB, $columnB); public function null($columnName); + public function orderBy($column, $direction); + public function count($column, $as = null); + public function group($column); public function buildQuery(); } \ No newline at end of file diff --git a/DataAccess/Queries/QueryBuilder.php b/DataAccess/Queries/QueryBuilder.php index 56a82dc..b15aab3 100644 --- a/DataAccess/Queries/QueryBuilder.php +++ b/DataAccess/Queries/QueryBuilder.php @@ -11,13 +11,19 @@ class QueryBuilder implements IQueryBuilder protected $_whereClauses = array(); protected $_limitClause; protected $_joinClauses = array(); + protected $_orderClause; + protected $_countClause; + protected $_groupClause; public function buildQuery() { $this->applyJoinClauses() ->applyWhereClauses() - ->applyLimitClause(); - + ->applyGroupClause() + ->applyOrderClause() + ->applyLimitClause() + ->applyCountClause(); + return $this->_queryString; } @@ -56,6 +62,40 @@ class QueryBuilder implements IQueryBuilder return $this->where($columnName, 'is', null); } + public function count($column, $as = null) + { + if($as) + { + $this->_countClause = sprintf(', count(%s) as %s', $column, $as); + } else { + $this->_countClause = sprintf(', count(%s)', $column); + } + + return $this; + } + + public function group($column) + { + $this->_groupClause = sprintf(' group by %s', $column); + + return $this; + } + + private function applyCountClause() + { + $pos = strpos($this->_queryString, '*')+1; + $this->_queryString = substr_replace($this->_queryString, $this->_countClause, $pos, 0); + + return $this; + } + + private function applyGroupClause() + { + $this->_queryString .= $this->_groupClause; + + return $this; + } + private function applyJoinClauses() { foreach($this->_joinClauses as $joinClause) @@ -66,8 +106,17 @@ class QueryBuilder implements IQueryBuilder return $this; } + public function orderBy($column, $direction) + { + $this->_orderClause = sprintf(' ORDER BY %s %s', $column, $direction); + + return $this; + } + private function applyWhereClauses() { + if(!$this->_whereClauses) return $this; + $this->_queryString .= ' WHERE '; foreach($this->_whereClauses as $whereClause) @@ -97,4 +146,10 @@ class QueryBuilder implements IQueryBuilder return $this; } + private function applyOrderClause() + { + $this->_queryString .= $this->_orderClause; + return $this; + } + } \ No newline at end of file diff --git a/DataAccess/StepMania/IPackRepository.php b/DataAccess/StepMania/IPackRepository.php index c3d29a9..8112f4f 100644 --- a/DataAccess/StepMania/IPackRepository.php +++ b/DataAccess/StepMania/IPackRepository.php @@ -7,6 +7,7 @@ use Domain\Entities\StepMania\IPack; interface IPackRepository extends IRepository { + public function findByFileId($id); public function findByTitle($title); public function findByContributor($contributor); public function save(IPack $entity); diff --git a/DataAccess/StepMania/ISimfileRepository.php b/DataAccess/StepMania/ISimfileRepository.php index bf15db2..043c937 100644 --- a/DataAccess/StepMania/ISimfileRepository.php +++ b/DataAccess/StepMania/ISimfileRepository.php @@ -8,6 +8,7 @@ use Domain\Entities\StepMania\ISimfile; interface ISimfileRepository extends IRepository { + public function findByFileId($id); public function findByTitle($title, ISimfileQueryConstraints $constraints); public function findByArtist($artist, ISimfileQueryConstraints $constraints); public function findByBpm($high, $low, ISimfileQueryConstraints $constraints); diff --git a/DataAccess/StepMania/PackRepository.php b/DataAccess/StepMania/PackRepository.php index 20b50eb..09d5296 100644 --- a/DataAccess/StepMania/PackRepository.php +++ b/DataAccess/StepMania/PackRepository.php @@ -35,11 +35,19 @@ class PackRepository implements IPackRepository return $result; } + public function findByFileId($id) + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('file_id', '=', $id); + return $this->_dataMapper->map('Pack', $queryBuilder); + } + public function findRange($id, $limit) { $queryBuilder = $this->_queryBuilderFactory->createInstance(); - $queryBuilder->where('id', '>=', $id)->limit($limit); - + $queryBuilder->where('id', '>=', $id)->limit(abs($limit)); + if($limit < 0) $queryBuilder->orderBy('id', 'DESC'); + return $this->_dataMapper->map('Pack', $queryBuilder); } diff --git a/DataAccess/StepMania/SimfileRepository.php b/DataAccess/StepMania/SimfileRepository.php index 3cbc015..443c967 100644 --- a/DataAccess/StepMania/SimfileRepository.php +++ b/DataAccess/StepMania/SimfileRepository.php @@ -36,11 +36,19 @@ class SimfileRepository implements ISimfileRepository return $result; } + public function findByFileId($id) + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('simfile_file_id', '=', $id); + return $this->_dataMapper->map('Simfile', $queryBuilder); + } + public function findRange($id, $limit) { $queryBuilder = $this->_queryBuilderFactory->createInstance(); - $queryBuilder->where('id', '>=', $id)->null('pack_id')->limit($limit); - + $queryBuilder->where('id', '>=', $id)->null('pack_id')->limit(abs($limit)); + if($limit < 0) $queryBuilder->orderBy('id', 'DESC'); + return $this->_dataMapper->map('Simfile', $queryBuilder); } diff --git a/config/Routes.php b/config/Routes.php index b79aafd..a959b5a 100644 --- a/config/Routes.php +++ b/config/Routes.php @@ -7,10 +7,22 @@ return [ 'action' => 'list' ], - //TODO: test controller, delete later - '/downloadtest' => [ + '/simfiles/latest/simfile' => [ 'methods' => ['GET'], - 'controller' => 'downloadTest' + 'controller' => 'Simfile', + 'action' => 'latestSimfile' + ], + + '/simfiles/latest/pack' => [ + 'methods' => ['GET'], + 'controller' => 'Simfile', + 'action' => 'latestPack' + ], + + '/simfiles/popular' => [ + 'methods' => ['GET'], + 'controller' => 'Simfile', + 'action' => 'popular' ], '/simfiles/upload' => [ -- 2.11.0