Popular downloads stuff.
authorCameron Ball <cameron@getapproved.com.au>
Wed, 10 Dec 2014 06:04:25 +0000 (14:04 +0800)
committerCameron Ball <cameron@getapproved.com.au>
Wed, 10 Dec 2014 06:04:25 +0000 (14:04 +0800)
Controllers/SimfileController.php
DataAccess/DownloadRepository.php
DataAccess/IDownloadRepository.php
DataAccess/Queries/IQueryBuilder.php
DataAccess/Queries/QueryBuilder.php
DataAccess/StepMania/IPackRepository.php
DataAccess/StepMania/ISimfileRepository.php
DataAccess/StepMania/PackRepository.php
DataAccess/StepMania/SimfileRepository.php
config/Routes.php

index ab63396..06fe869 100644 (file)
@@ -11,8 +11,10 @@ use Services\ISMOMatcher;
 use DataAccess\StepMania\ISimfileRepository;\r
 use DataAccess\StepMania\IPackRepository;\r
 use DataAccess\IFileRepository;\r
+use DataAccess\IDownloadRepository;\r
 use Domain\Entities\StepMania\ISimfile;\r
 use Domain\Entities\IFile;\r
+use Domain\Entities\StepMania\IPack;\r
 use Domain\Util;\r
 \r
 class SimfileController implements IDivineController\r
@@ -24,6 +26,7 @@ class SimfileController implements IDivineController
     private $_uploadManager;\r
     private $_zipParser;\r
     private $_smoMatcher;\r
+    private $_downloadRepository;\r
     \r
     public function __construct(\r
         IHttpResponse $response,\r
@@ -33,7 +36,8 @@ class SimfileController implements IDivineController
         IFileRepository $fileRepository,\r
         IUserSession $userSession,\r
         IZipParser $zipParser,\r
-        ISMOMatcher $smoMatcher\r
+        ISMOMatcher $smoMatcher,\r
+        IDownloadRepository $downloadRepository\r
     ) {\r
         $this->_response = $response;\r
         $this->_uploadManager = $uploadManager;\r
@@ -42,6 +46,7 @@ class SimfileController implements IDivineController
         $this->_fileRepository = $fileRepository;\r
         $this->_zipParser = $zipParser;\r
         $this->_smoMatcher = $smoMatcher;\r
+        $this->_downloadRepository = $downloadRepository;\r
     }\r
     \r
     public function indexAction() {\r
@@ -64,34 +69,14 @@ class SimfileController implements IDivineController
         \r
         foreach($packs as $pack)\r
         {\r
-            $packSimfiles = array();\r
-            foreach($pack->getSimfiles() as $simfile)\r
-            {\r
-                $packSimfiles[] = $this->simfileToArray($simfile);\r
-            }\r
-\r
-            $packMirrors = array();\r
-            \r
-            if($pack->getFile())\r
-            {\r
-                $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash());\r
-            }\r
-            \r
-            if($pack->getFile()->getMirrors())\r
-            {\r
-                foreach($pack->getFile()->getMirrors() as $mirror)\r
-                {\r
-                    $packMirrors[] = array('source' => $mirror->getSource(), 'uri' => $mirror->getUri());\r
-                }\r
-            }\r
-            \r
             $packArray[] = array(\r
                 'title'=> $pack->getTitle(),\r
                 'contributors' => $pack->getContributors(),\r
-                'simfiles' => $packSimfiles,\r
+                'simfiles' => $this->getPackSimfilesArray($pack),\r
                 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',\r
-                'mirrors' => $packMirrors,\r
-                'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null\r
+                'mirrors' => $this->getPackMirrorsArray($pack),\r
+                'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,\r
+                'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null\r
             );\r
         }\r
         \r
@@ -102,6 +87,65 @@ class SimfileController implements IDivineController
                         ->sendResponse();\r
     }\r
     \r
+    public function latestSimfileAction()\r
+    {\r
+        $simfile = $this->_simfileRepository->findRange(0, -1);\r
+        $this->_response->setHeader('Content-Type', 'application/json')\r
+                        ->setBody(json_encode($this->simfileToArray(reset($simfile))))\r
+                        ->sendResponse();\r
+    }\r
+    \r
+    public function latestPackAction()\r
+    {\r
+        $pack = $this->_packRepository->findRange(0, -1);\r
+        $pack = reset($pack);\r
+        \r
+        $packArray = array(\r
+            'title'=> $pack->getTitle(),\r
+            'contributors' => $pack->getContributors(),\r
+            'simfiles' => $this->getPackSimfilesArray($pack),\r
+            'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',\r
+            'mirrors' => $this->getPackMirrorsArray($pack),\r
+            'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,\r
+            'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null\r
+        );\r
+        \r
+        $this->_response->setHeader('Content-Type', 'application/json')\r
+                        ->setBody(json_encode($packArray))\r
+                        ->sendResponse();\r
+    }\r
+    \r
+    public function popularAction()\r
+    {\r
+        $returnArray = array();\r
+        $popularDownloads = $this->_downloadRepository->findPopular();\r
+        $popularDownloads = reset($popularDownloads);\r
+        $packOrFileId = $popularDownloads->getFile()->getId();\r
+        \r
+        $simfile = $this->_simfileRepository->findByFileId($packOrFileId);\r
+        if($simfile)\r
+        {\r
+            $returnArray = $this->simfileToArray(reset($simfile));\r
+        } else {\r
+            $pack = $this->_packRepository->findByFileId($packOrFileId);\r
+            $pack = reset($pack);\r
+            $returnArray = array(\r
+                'title'=> $pack->getTitle(),\r
+                'contributors' => $pack->getContributors(),\r
+                'simfiles' => $this->getPackSimfilesArray($pack),\r
+                'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',\r
+                'mirrors' => $this->getPackMirrorsArray($pack),\r
+                'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,\r
+                'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null\r
+            );\r
+        }\r
+        \r
+        $this->_response->setHeader('Content-Type', 'application/json')\r
+                        ->setBody(json_encode($returnArray))\r
+                        ->sendResponse();\r
+        \r
+    }\r
+    \r
     public function uploadAction()\r
     {                       \r
         //TODO: Put directory in config ?\r
@@ -139,6 +183,37 @@ class SimfileController implements IDivineController
         }\r
     }\r
     \r
+    private function getPackMirrorsArray(IPack $pack)\r
+    {\r
+        $packMirrors = array();\r
+\r
+        if($pack->getFile())\r
+        {\r
+            $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash());\r
+        }\r
+\r
+        if($pack->getFile()->getMirrors())\r
+        {\r
+            foreach($pack->getFile()->getMirrors() as $mirror)\r
+            {\r
+                $packMirrors[] = array('source' => $mirror->getSource(), 'uri' => $mirror->getUri());\r
+            }\r
+        }\r
+        \r
+        return $packMirrors;\r
+    }\r
+    \r
+    private function getPackSimfilesArray(IPack $pack)\r
+    {\r
+        $packSimfiles = array();\r
+        foreach($pack->getSimfiles() as $simfile)\r
+        {\r
+            $packSimfiles[] = $this->simfileToArray($simfile);\r
+        }\r
+        \r
+        return $packSimfiles;\r
+    }\r
+    \r
     private function findAndAddSmoMirror(IFile $file)\r
     {\r
         $basename = pathinfo($file->getFilename(), PATHINFO_FILENAME);\r
@@ -184,7 +259,8 @@ class SimfileController implements IDivineController
             'bpmChanges' => $simfile->hasBPMChanges() ? 'Yes' : 'No',\r
             'banner' => $simfile->getBanner() ? 'files/banner/' . $simfile->getBanner()->getHash() : 'files/banner/default',\r
             'download' => $simfile->getSimfile() ?  'files/simfile/' . $simfile->getSimfile()->getHash() : null,\r
-            'size' => $simfile->getSimfile() ? Util::bytesToHumanReadable($simfile->getSimfile()->getSize()) : null\r
+            'size' => $simfile->getSimfile() ? Util::bytesToHumanReadable($simfile->getSimfile()->getSize()) : null,\r
+            'uploaded' => $simfile->getSimfile() ? date('F jS, Y', $simfile->getSimfile()->getUploadDate()) : null\r
         );\r
     }\r
 }\r
index 544611e..e2bbf74 100644 (file)
@@ -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)
index e1052dd..a2df2db 100644 (file)
@@ -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);
 }
 
index 69df99b..fb5ace6 100644 (file)
@@ -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
index 56a82dc..b15aab3 100644 (file)
@@ -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
index c3d29a9..8112f4f 100644 (file)
@@ -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);
index bf15db2..043c937 100644 (file)
@@ -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);
index 20b50eb..09d5296 100644 (file)
@@ -35,11 +35,19 @@ class PackRepository implements IPackRepository
         return $result;\r
     }\r
     \r
+    public function findByFileId($id)\r
+    {\r
+        $queryBuilder = $this->_queryBuilderFactory->createInstance();\r
+        $queryBuilder->where('file_id', '=', $id);\r
+        return $this->_dataMapper->map('Pack', $queryBuilder);\r
+    }\r
+    \r
     public function findRange($id, $limit)\r
     {\r
         $queryBuilder = $this->_queryBuilderFactory->createInstance();\r
-        $queryBuilder->where('id', '>=', $id)->limit($limit);\r
-                \r
+        $queryBuilder->where('id', '>=', $id)->limit(abs($limit));\r
+        if($limit < 0) $queryBuilder->orderBy('id', 'DESC');\r
+        \r
         return $this->_dataMapper->map('Pack', $queryBuilder);\r
     }\r
     \r
index 3cbc015..443c967 100644 (file)
@@ -36,11 +36,19 @@ class SimfileRepository implements ISimfileRepository
         return $result;\r
     }\r
     \r
+    public function findByFileId($id)\r
+    {\r
+        $queryBuilder = $this->_queryBuilderFactory->createInstance();\r
+        $queryBuilder->where('simfile_file_id', '=', $id);\r
+        return $this->_dataMapper->map('Simfile', $queryBuilder);\r
+    }\r
+    \r
     public function findRange($id, $limit)\r
     {\r
         $queryBuilder = $this->_queryBuilderFactory->createInstance();\r
-        $queryBuilder->where('id', '>=', $id)->null('pack_id')->limit($limit);\r
-                \r
+        $queryBuilder->where('id', '>=', $id)->null('pack_id')->limit(abs($limit));\r
+        if($limit < 0) $queryBuilder->orderBy('id', 'DESC');\r
+        \r
         return $this->_dataMapper->map('Simfile', $queryBuilder);\r
     }\r
     \r
index b79aafd..a959b5a 100644 (file)
@@ -7,10 +7,22 @@ return [
         'action' => 'list'\r
     ],\r
     \r
-    //TODO: test controller, delete later\r
-    '/downloadtest' => [\r
+    '/simfiles/latest/simfile' => [\r
         'methods' => ['GET'],\r
-        'controller' => 'downloadTest'\r
+        'controller' => 'Simfile',\r
+        'action' => 'latestSimfile'\r
+    ],\r
+    \r
+    '/simfiles/latest/pack' => [\r
+        'methods' => ['GET'],\r
+        'controller' => 'Simfile',\r
+        'action' => 'latestPack'\r
+    ],\r
+    \r
+    '/simfiles/popular' => [\r
+        'methods' => ['GET'],\r
+        'controller' => 'Simfile',\r
+        'action' => 'popular'\r
     ],\r
     \r
     '/simfiles/upload' => [\r