From 1c9661e06ebd00e1bdc7d956bcce1f6ecd34c018 Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Fri, 21 Nov 2014 16:59:32 +0800 Subject: [PATCH] Zip parsing kinda works. Seems to be an issue with packs. Committing so I can work at home if I get time. --- Controllers/PackTestController.php | 26 ++++ Controllers/SimfileController.php | 84 +++++-------- DataAccess/DataMapper/DataMapper.php | 3 +- .../Helpers/AbstractPopulationHelper.php | 48 +++++--- .../DataMapper/Helpers/EntityArrayMapsHelper.php | 82 +++++++++++++ DataAccess/FileRepository.php | 1 - DataAccess/StepMania/IPackRepository.php | 16 +++ DataAccess/StepMania/PackRepository.php | 64 ++++++++++ DataAccess/StepMania/SimfileRepository.php | 5 +- DataAccess/functions.php | 6 + Domain/Entities/StepMania/IPack.php | 3 +- Domain/Entities/StepMania/IPackBuilder.php | 1 + Domain/Entities/StepMania/Pack.php | 10 +- Domain/Entities/StepMania/PackBuilder.php | 6 + Domain/Entities/StepMania/PackFactory.php | 3 + .../Entities/StepMania/PackStepByStepBuilder.php | 14 ++- .../StepMania/SimfileStepByStepBuilder.php | 2 +- Services/BannerExtracter.php | 57 +++++++-- Services/IBannerExtracter.php | 3 +- Services/IZipParser.php | 14 +++ Services/SimfileParser.php | 1 - Services/Uploads/UploadManager.php | 4 +- Services/ZipParser.php | 134 +++++++++++++++++++++ config/DI.php | 65 +++++----- config/DataMaps.php | 12 ++ config/Routes.php | 6 + 26 files changed, 541 insertions(+), 129 deletions(-) create mode 100644 Controllers/PackTestController.php create mode 100644 DataAccess/DataMapper/Helpers/EntityArrayMapsHelper.php create mode 100644 DataAccess/StepMania/IPackRepository.php create mode 100644 DataAccess/StepMania/PackRepository.php create mode 100644 Services/IZipParser.php create mode 100644 Services/ZipParser.php diff --git a/Controllers/PackTestController.php b/Controllers/PackTestController.php new file mode 100644 index 0000000..656f9f9 --- /dev/null +++ b/Controllers/PackTestController.php @@ -0,0 +1,26 @@ +_packRepository = $repository; + } + + public function indexAction() { + $pack = $this->_packRepository->findById(1); + + echo '
';
+        print_r($pack);
+        echo '
'; + } +} diff --git a/Controllers/SimfileController.php b/Controllers/SimfileController.php index 47ffd7b..00dc15c 100644 --- a/Controllers/SimfileController.php +++ b/Controllers/SimfileController.php @@ -2,44 +2,41 @@ namespace Controllers; -use ZipArchive; -use Exception; use Controllers\IDivineController; use Services\Http\IHttpResponse; use Services\Uploads\IUploadManager; -use Services\ISimfileParser; use Services\IUserSession; -use Services\IBannerExtracter; +use Services\IZipParser; use DataAccess\StepMania\ISimfileRepository; -use Domain\Entities\StepMania\ISimfileStepByStepBuilder; +use DataAccess\StepMania\IPackRepository; +use DataAccess\IFileRepository; class SimfileController implements IDivineController { private $_simfileRepository; + private $_packRepository; + private $_fileRepository; private $_response; private $_uploadManager; - private $_simfileParser; - private $_simfileBuilder; - private $_userRepository; private $_userSession; - private $_bannerExtracter; + private $_zipParser; public function __construct( IHttpResponse $response, IUploadManager $uploadManager, - ISimfileRepository $repository, + ISimfileRepository $simfileRepository, + IPackRepository $packRepository, + IFileRepository $fileRepository, IUserSession $userSession, - ISimfileParser $simfileParser, - ISimfileStepByStepBuilder $simfileBuilder, - IBannerExtracter $bannerExtracter + IZipParser $zipParser ) { $this->_response = $response; $this->_uploadManager = $uploadManager; - $this->_simfileRepository = $repository; + $this->_simfileRepository = $simfileRepository; + $this->_packRepository = $packRepository; + $this->_fileRepository = $fileRepository; $this->_userSession = $userSession; - $this->_simfileParser = $simfileParser; - $this->_simfileBuilder = $simfileBuilder; - $this->_bannerExtracter = $bannerExtracter; + $this->_zipParser = $zipParser; } public function indexAction() { @@ -102,49 +99,24 @@ class SimfileController implements IDivineController foreach($files as $file) { - $za = new ZipArchive(); - //XXX: We assume all files are zips. Should be enforced by validation elsewhere. - $res = $za->open('../files/StepMania/' . $file->getHash() . '.zip'); + $zipParser = $this->_zipParser; + $zipParser->parse($file); - if($res !== true) throw new Exception ('Could not open zip for reading.'); - - for($i=0; $i<$za->numFiles; $i++) + //save the actual zip in the db + //$this->_fileRepository->save($file); + foreach($zipParser->simfiles() as $simfile) { - $stat = $za->statIndex($i); - if(pathinfo($stat['name'], PATHINFO_EXTENSION) == 'sm') - { - $smData = file_get_contents('zip://../files/StepMania/' . $file->getHash() . '.zip#' . $stat['name']); - break; - } + $this->_fileRepository->save($simfile->getBanner()); + $this->_fileRepository->save($simfile->getSimfile()); + $this->_simfileRepository->save($simfile); } - - if(!$smData) throw new Exception('Could not extract simfile.'); - - /* @var $parser \Services\ISimfileParser */ - $parser = $this->_simfileParser; - $parser->parse($smData); - - $banner = $this->_bannerExtracter->extractBanner('../files/StepMania/' . $file->getHash() . '.zip', $parser->banner()); - - //TODO: Create file object for banner and .zip then link them up - //shouldn't need to use repository as the mapper can create the db entries - //all in one go (I think ...) - // - //Need to make FileBuilder and FileStepByStepBuilder - $simfile = $this->_simfileBuilder->With_Title($parser->title()) - ->With_Artist($parser->artist()) - ->With_Uploader($this->_userSession->getCurrentUser()) //obj - ->With_BPM($parser->bpm()) - ->With_BpmChanges($parser->bpmChanges()) - ->With_Stops($parser->stops()) - ->With_FgChanges($parser->fgChanges()) - ->With_BgChanges($parser->bgChanges()) - ->With_Steps($parser->steps()) - ->With_Simfile($file) - ->With_Banner($banner) - ->build(); - $this->_simfileRepository->save($simfile); + if($zipParser->isPack()) + { + $pack = $zipParser->pack(); + $this->_fileRepository->save($pack->getBanner()); + $this->_packRepository->save($pack); + } } } } diff --git a/DataAccess/DataMapper/DataMapper.php b/DataAccess/DataMapper/DataMapper.php index 624e03e..24b7994 100644 --- a/DataAccess/DataMapper/DataMapper.php +++ b/DataAccess/DataMapper/DataMapper.php @@ -49,7 +49,7 @@ class DataMapper implements IDataMapper $class->setId($row['id']); $entities[$row['id']] = $class; } - + return $entities; } @@ -136,7 +136,6 @@ class DataMapper implements IDataMapper foreach($queries as $query) { $query = str_replace('%MAIN_QUERY_ID%', end($idMap), $query); - echo $query; $statement = $this->_db->prepare($query); $statement->execute(); } diff --git a/DataAccess/DataMapper/Helpers/AbstractPopulationHelper.php b/DataAccess/DataMapper/Helpers/AbstractPopulationHelper.php index a3e518b..d32f464 100644 --- a/DataAccess/DataMapper/Helpers/AbstractPopulationHelper.php +++ b/DataAccess/DataMapper/Helpers/AbstractPopulationHelper.php @@ -2,8 +2,6 @@ namespace DataAccess\DataMapper\Helpers; -use DataAccess\DataMapper\Helpers\VOMapsHelper; -use Domain\Entities\IDivineEntity; use Exception; class AbstractPopulationHelper @@ -18,7 +16,7 @@ class AbstractPopulationHelper static function getConstrutorArray($maps, $entity, $row, $db) { $constructors = array(); - + foreach($maps[$entity]['maps'] as $constructor => $mapsHelper) { switch(get_class($mapsHelper)) @@ -30,11 +28,11 @@ class AbstractPopulationHelper case 'DataAccess\DataMapper\Helpers\VOMapsHelper': case 'DataAccess\DataMapper\Helpers\VOArrayMapsHelper': case 'DataAccess\DataMapper\Helpers\EntityMapsHelper': + case 'DataAccess\DataMapper\Helpers\EntityArrayMapsHelper': $constructors[$constructor] = $mapsHelper->populate($maps, $db, $entity, $row); break; } } - return $constructors; } @@ -225,18 +223,32 @@ class AbstractPopulationHelper // in the case of setting up a new entity, the VOs should never // exist in the first place, so we just make them. case 'DataAccess\DataMapper\Helpers\VOArrayMapsHelper': + case 'DataAccess\DataMapper\Helpers\EntityArrayMapsHelper': if($id && isset($property[0])) { // If we assume that all elements in the array are the same then // we can just use the first one to figure out which maps entry to use $subEntityMapsIndex = self::getMapsNameFromEntityObject($property[0], $maps); + //TODO: I think this function will work with Entities too, but I should probably rename it at some point $voIds = self::mapVOArrayToIds($maps[$subEntityMapsIndex]['table'], array(strtolower($entityMapsIndex . '_id'), $id), $db); foreach($property as $index => $propertyArrayElement) { + //XXX: I wanted this to only run on VOs, not entities. But there's a problem with that. + //when creating a pack, the simfile entities need to reference the pack, and the only way for + //that to happen is here. What I do instead is check that the entity has an id (which implies + //it has already been created and save) if it is a IDivineEntity. If it doesn't, complain. + //this ensures consistent behaviour with other parts of this mapper. + if($property instanceof \Domain\Entities\IDivineEntity && !$property->getId()) + { + throw new Exception(sprintf( + 'Could not find referenced entity, %s, in the database. Has it been saved yet?', + $mapsHelper->getEntityName())); + } + $extra = array(strtolower($entityMapsIndex . '_id') => $id); if(isset($voIds[$index])) { @@ -250,6 +262,18 @@ class AbstractPopulationHelper } else { foreach($property as $propertyArrayElement) { + //XXX: I wanted this to only run on VOs, not entities. But there's a problem with that. + //when creating a pack, the simfile entities need to reference the pack, and the only way for + //that to happen is here. What I do instead is check that the entity has an id (which implies + //it has already been created and save) if it is a IDivineEntity. If it doesn't, complain. + //this ensures consistent behaviour with other parts of this mapper. + if($property instanceof \Domain\Entities\IDivineEntity && !$property->getId()) + { + throw new Exception(sprintf( + 'Could not find referenced entity, %s, in the database. Has it been saved yet?', + $mapsHelper->getEntityName())); + } + // TODO: TRICKY! Since this is a back-reference, it // needs the ID of the object we're trying to save // to complete @@ -260,22 +284,6 @@ class AbstractPopulationHelper } } } -// -// if($id) -// { -// $query = substr($query, 0, -2); -// $query .= sprintf(' WHERE id=%u', $id); -// $queries['TYPE'] = self::QUERY_TYPE_UPDATE; -// } else { -// $queryColumnNamesAndValues = array_merge($queryColumnNamesAndValues, $extraColumns); -// $query = sprintf('INSERT INTO %s (%s) VALUES (%s)', -// $maps[$entityMapsIndex]['table'], -// implode(', ', array_keys($queryColumnNamesAndValues)), -// implode(', ', $queryColumnNamesAndValues)); -// $queries['TYPE'] = self::QUERY_TYPE_CREATE; -// } -// print_r($queryColumnNamesAndValues); -// echo '
'; if($id) { diff --git a/DataAccess/DataMapper/Helpers/EntityArrayMapsHelper.php b/DataAccess/DataMapper/Helpers/EntityArrayMapsHelper.php new file mode 100644 index 0000000..21f342e --- /dev/null +++ b/DataAccess/DataMapper/Helpers/EntityArrayMapsHelper.php @@ -0,0 +1,82 @@ +_entityName = $entityName; + + if($tableName) { + $this->_tableName = $tableName; + } else { + $this->_tableName = strtolower($entityName); + } + + if($accessor) + { + $this->_accessor = $accessor; + } else + { + $this->_accessor = 'get'. str_replace('_', '', $entityName); + } + } + + public function getEntityName() + { + return $this->_entityName; + } + + public function getAccessor() + { + return $this->_accessor; + } + + public function getTableName() + { + return $this->_tableName; + } + + public function populate($maps, $db, $parent, $row) + { + $className = $maps[$this->_entityName]['class']; + $table = $maps[$this->_entityName]['table']; + $entityArray = array(); + + // in this case we look in another table for this row's id + $join_id = $row['id']; + $statement = $db->prepare(sprintf('SELECT * from %s WHERE %s=%u', + $table, + strtolower($parent . '_id'), + $join_id + )); + + $statement->execute(); + $rows = $statement->fetchAll(); + + foreach($rows as $row) + { + $constructors = AbstractPopulationHelper::getConstrutorArray($maps, $this->_entityName, $row, $db); + + if(count($constructors) == 0) + { + $class = new $className; + } else { + $r = new ReflectionClass($className); + $class = $r->newInstanceArgs($constructors); + } + + $class->setId($row['id']); + $entityArray[] = $class; + } + + return $entityArray; + } +} \ No newline at end of file diff --git a/DataAccess/FileRepository.php b/DataAccess/FileRepository.php index 075b7d0..bba8703 100644 --- a/DataAccess/FileRepository.php +++ b/DataAccess/FileRepository.php @@ -5,7 +5,6 @@ namespace DataAccess; use DataAccess\IFileRepository; use DataAccess\DataMapper\IDataMapper; use DataAccess\Queries\IQueryBuilderFactory; -use Domain\Entities\IFile; class FileRepository implements IFileRepository { diff --git a/DataAccess/StepMania/IPackRepository.php b/DataAccess/StepMania/IPackRepository.php new file mode 100644 index 0000000..c3d29a9 --- /dev/null +++ b/DataAccess/StepMania/IPackRepository.php @@ -0,0 +1,16 @@ +_dataMapper = $dataMapper; + $this->_queryBuilderFactory = $queryBuilderFactory; + } + + public function findById($id) { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('id', '=', $id); + + $result = $this->_dataMapper->map('Pack', $queryBuilder); + return reset($result); + } + + public function findRange($id, $limit) + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('id', '>=', $id)->limit($limit); + + return $this->_dataMapper->map('Pack', $queryBuilder); + } + + public function save(IPack $entity) { + return $this->_dataMapper->save($entity); + } + + //TODO: Implement + public function remove(IPack $entity) { + ; + } + + public function findByTitle($title) + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('title', 'LIKE', "%%$title%%"); + + return $this->_dataMapper->map('Pack', $queryBuilder); + } + + public function findByContributor($artistName) + { + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->join('inner', 'packs', 'id', 'simfiles', 'pack_id') + ->join('inner', 'simfiles', 'id', 'steps', 'simfile_id') + ->join('inner', 'steps', 'step_artist_id', 'step_artists', 'id') + ->where('tag', 'LIKE', "%%$artistName%%"); + + return $this->_dataMapper->map('Pack', $queryBuilder); + } +} diff --git a/DataAccess/StepMania/SimfileRepository.php b/DataAccess/StepMania/SimfileRepository.php index d80efd5..5803c21 100644 --- a/DataAccess/StepMania/SimfileRepository.php +++ b/DataAccess/StepMania/SimfileRepository.php @@ -23,8 +23,9 @@ class SimfileRepository implements ISimfileRepository public function findById($id) { $queryBuilder = $this->_queryBuilderFactory->createInstance(); $queryBuilder->where('id', '=', $id); - - return $this->_dataMapper->map('Simfile', $queryBuilder); + + $result = $this->_dataMapper->map('Simfile', $queryBuilder); + return reset($result); } public function findRange($id, $limit) diff --git a/DataAccess/functions.php b/DataAccess/functions.php index df43446..82669e9 100644 --- a/DataAccess/functions.php +++ b/DataAccess/functions.php @@ -3,6 +3,7 @@ namespace DataAccess; use DataAccess\DataMapper\Helpers\EntityMapsHelper; +use DataAccess\DataMapper\Helpers\EntityArrayMapsHelper; use DataAccess\DataMapper\Helpers\VOMapsHelper; use DataAccess\DataMapper\Helpers\VOArrayMapsHelper; use DataAccess\DataMapper\Helpers\IntMapsHelper; @@ -13,6 +14,11 @@ function Entity($mapName, $accessor=null, $tableName = null) return new EntityMapsHelper($mapName, $accessor, $tableName); } +function EntityArray($mapName, $accessor=null, $tableName = null) +{ + return new EntityArrayMapsHelper($mapName, $accessor, $tableName); +} + function VO($mapName, $accessor=null, $tableName = null) { return new VOMapsHelper($mapName, $accessor, $tableName); diff --git a/Domain/Entities/StepMania/IPack.php b/Domain/Entities/StepMania/IPack.php index 0f7eddf..124c776 100644 --- a/Domain/Entities/StepMania/IPack.php +++ b/Domain/Entities/StepMania/IPack.php @@ -1,6 +1,6 @@ _title = $title; $this->_uploader = $uploader; + $this->_banner = $banner; $this->_file = $file; foreach($simfiles as $simfile) { @@ -68,6 +71,11 @@ class Pack extends AbstractEntity implements IPack return $this->_uploader; } + public function getBanner() + { + return $this->_banner; + } + private function getAllStepArtistsFromSimfile(ISimfile $simfile) { $artists = array(); diff --git a/Domain/Entities/StepMania/PackBuilder.php b/Domain/Entities/StepMania/PackBuilder.php index e9f1099..3a52a36 100644 --- a/Domain/Entities/StepMania/PackBuilder.php +++ b/Domain/Entities/StepMania/PackBuilder.php @@ -14,6 +14,7 @@ class PackBuilder implements IPackBuilder private $_title; private $_uploader; private $_simfiles; + private $_banner; private $_file; //override parent @@ -28,6 +29,11 @@ class PackBuilder implements IPackBuilder return $this; } + public function With_Banner(IFile $banner) + { + $this->_banner = $banner; + } + public function With_File(IFile $file) { $this->_file = $file; diff --git a/Domain/Entities/StepMania/PackFactory.php b/Domain/Entities/StepMania/PackFactory.php index 6723466..b59c49a 100644 --- a/Domain/Entities/StepMania/PackFactory.php +++ b/Domain/Entities/StepMania/PackFactory.php @@ -11,6 +11,7 @@ interface IPackFactory $title, IUser $uploader, array $simfiles, + IFile $banner = null, IFile $file = null ); } @@ -21,12 +22,14 @@ class PackFactory implements IPackFactory $title, IUser $uploader, array $simfiles, + IFile $banner = null, IFile $file = null ) { return new Pack( $title, $uploader, $simfiles, + $banner, $file ); } diff --git a/Domain/Entities/StepMania/PackStepByStepBuilder.php b/Domain/Entities/StepMania/PackStepByStepBuilder.php index 89261b3..cc53507 100644 --- a/Domain/Entities/StepMania/PackStepByStepBuilder.php +++ b/Domain/Entities/StepMania/PackStepByStepBuilder.php @@ -23,6 +23,7 @@ interface IPackStepByStepBuilder_With_Uploader interface IPackStepByStepBuilder_With_Simfiles { + public function With_Banner(IFile $banner); public function With_File(IFile $file); public function build(); } @@ -52,8 +53,8 @@ class PackStepByStepBuilder_With_Title extends AbstractPackStepByStepBuilder imp { public function With_Uploader(IUser $user) { - $this->_packBuilder->With_Artist($artist); - return new PackStepByStepBuilder_With_Artist($this->_packBuilder); + $this->_packBuilder->With_Uploader($user); + return new PackStepByStepBuilder_With_Uploader($this->_packBuilder); } } @@ -68,11 +69,18 @@ class PackStepByStepBuilder_With_Uploader extends AbstractPackStepByStepBuilder class PackStepByStepBuilder_With_Simfiles extends AbstractPackStepByStepBuilder implements IPackStepByStepBuilder_With_Simfiles { + public function With_Banner(IFile $banner) + { + $this->_packBuilder->With_File($banner); + return $this; + } + public function With_File(Ifile $file) { $this->_packBuilder->With_File($file); + return $this; } - + public function build() { return $this->_simfileBuilder diff --git a/Domain/Entities/StepMania/SimfileStepByStepBuilder.php b/Domain/Entities/StepMania/SimfileStepByStepBuilder.php index 8f03a2f..d0b9971 100644 --- a/Domain/Entities/StepMania/SimfileStepByStepBuilder.php +++ b/Domain/Entities/StepMania/SimfileStepByStepBuilder.php @@ -158,7 +158,7 @@ class SimfileStepByStepBuilder_With_Steps extends AbstractSimfileStepByStepBuild public function With_Banner(IFile $banner) { $this->_simfileBuilder->With_Banner($banner); - return new SimfileStepByStepBuilder_With_Steps($this->_simfileBuilder); + return new SimfileStepByStepBuilder_With_Steps($this->_simfileBuilder); //TODO: Pretty sure return $this will be OK } public function With_Simfile(IFile $simfile) diff --git a/Services/BannerExtracter.php b/Services/BannerExtracter.php index 843fd8b..1fc49f3 100644 --- a/Services/BannerExtracter.php +++ b/Services/BannerExtracter.php @@ -6,22 +6,20 @@ use ZipArchive; use finfo; use Exception; use Services\IBannerExtracter; -use DataAccess\IFileRepository; use Domain\Entities\IFileStepByStepBuilder; +//TODO: This class can probably be refactored to be nicer. Also perhaps the methods could be static? class BannerExtracter implements IBannerExtracter { private $_builder; private $_destinationFileName; private $_hash; - private $_fileRepository; - public function __construct(IFileStepByStepBuilder $builder, IFileRepository $fileRepository) { + public function __construct(IFileStepByStepBuilder $builder) { $this->_builder = $builder; - $this->_fileRepository = $fileRepository; } - public function extractBanner($zipfile, $bannerName) { + public function extractSongBanner($zipfile, $bannerName) { $za = new ZipArchive(); //XXX: We assume all files are zips. Should be enforced by validation elsewhere. $res = $za->open($zipfile); @@ -40,21 +38,64 @@ class BannerExtracter implements IBannerExtracter } } - if(!isset($result) || !$result) throw new Exception('Could not extract banner.'); + if(!isset($result) || !$result) return null; $finfo = new finfo(FILEINFO_MIME); $mimetype = $finfo->file('../files/banners/' . $this->_destinationFileName); $size = filesize('../files/banners/' . $this->_destinationFileName); /* @var $fff \Domain\Entities\FileStepByStepBuilder */ - $file= $this->_builder->With_Hash($this->_hash) + return $this->_builder->With_Hash($this->_hash) ->With_Path('banners') ->With_Filename($bannerName) ->With_Mimetype($mimetype) ->With_Size($size) ->With_UploadDate(time()) ->build(); + } + + public function extractPackBanner($zipfile, $packname) + { + $bannerName = ''; + $za = new ZipArchive(); + //XXX: We assume all files are zips. Should be enforced by validation elsewhere. + $res = $za->open($zipfile); + + if($res !== true) throw new Exception ('Could not open zip for reading.'); + + for($i=0; $i<$za->numFiles; $i++) + { + $stat = $za->statIndex($i); + $type = @exif_imagetype('zip://' . $zipfile . '#' . $stat['name']); + + if($type !== false) + { + $pathComponents = explode('/',$stat['name']); + + //replace 3spooty with packname variable + if(count($pathComponents) == 2 && $pathComponents[0] == $packname) + { + $this->_hash = $this->randomFilename($stat['name']); + $this->_destinationFileName = $this->_hash . '.' . pathinfo($stat['name'], PATHINFO_EXTENSION); + $bannerName = $pathComponents[1]; + $result = copy('zip://' . $zipfile . '#' . $stat['name'], '../files/banners/' . $this->_destinationFileName); + break; + } + } + } - return $this->_fileRepository->save($file); + if(!isset($result) || !$result) return null; + + $finfo = new finfo(FILEINFO_MIME); + $mimetype = $finfo->file('../files/banners/' . $this->_destinationFileName); + $size = filesize('../files/banners/' . $this->_destinationFileName); + /* @var $fff \Domain\Entities\FileStepByStepBuilder */ + return $this->_builder->With_Hash($this->_hash) + ->With_Path('banners') + ->With_Filename($bannerName) + ->With_Mimetype($mimetype) + ->With_Size($size) + ->With_UploadDate(time()) + ->build(); } private function randomFilename($seed) diff --git a/Services/IBannerExtracter.php b/Services/IBannerExtracter.php index 7407367..a56a31f 100644 --- a/Services/IBannerExtracter.php +++ b/Services/IBannerExtracter.php @@ -4,5 +4,6 @@ namespace Services; interface IBannerExtracter { - public function extractBanner($zipfile, $bannerName); + public function extractSongBanner($zipfile, $bannerName); + public function extractPackBanner($zipfile, $packname); } diff --git a/Services/IZipParser.php b/Services/IZipParser.php new file mode 100644 index 0000000..9b74480 --- /dev/null +++ b/Services/IZipParser.php @@ -0,0 +1,14 @@ +_smFileLines = explode(";", $simfileData); } diff --git a/Services/Uploads/UploadManager.php b/Services/Uploads/UploadManager.php index 0bfa03e..7f381c1 100644 --- a/Services/Uploads/UploadManager.php +++ b/Services/Uploads/UploadManager.php @@ -94,15 +94,13 @@ class UploadManager implements IUploadManager{ $hash = $this->saveFile($file); /* @var $file \Services\Uploads\IFile */ - $file = $this->_fileBuilder->With_Hash($hash) + $results[] = $this->_fileBuilder->With_Hash($hash) ->With_Path(rtrim($this->_destination, '/')) ->With_Filename($file->getName()) ->With_Mimetype($file->getType()) ->With_Size($file->getSize()) ->With_UploadDate(time()) ->build(); - - $results[] = $this->_fileRepository->save($file); } return $results; diff --git a/Services/ZipParser.php b/Services/ZipParser.php new file mode 100644 index 0000000..822c0fd --- /dev/null +++ b/Services/ZipParser.php @@ -0,0 +1,134 @@ +_smParser = $smParser; + $this->_smBuilder = $smBuilder; + $this->_packBuilder = $packBuilder; + $this->_bannerExtracter = $bannerExtracter; + $this->_userSession = $userSession; + } + + public function parse(IFile $file) + { + $this->_file = $file; + $this->_za = new ZipArchive(); + //XXX: We assume all files are zips. Should be enforced by validation elsewhere. + $res = $this->_za->open('../files/StepMania/' . $file->getHash() . '.zip'); + + if($res !== true) throw new Exception ('Could not open zip for reading.'); + $this->findSms(); + } + + public function pack() + { + if(count($this->_smFiles) > 1) + { + $packname = $this->packNameFromFiles(); + $banner = $this->_bannerExtracter->extractPackBanner('../files/StepMania/' . $this->_file->getHash() . '.zip', $packname); + + /* @var $builder \Domain\Entities\StepMania\PackStepByStepBuilder */ + $builder = $this->_packBuilder; + return $builder->With_Title($packname) + ->With_Uploader($this->_userSession->getCurrentUser()) + ->With_Simfiles($this->_smFiles) + ->With_Banner($banner) + ->With_File($this->_file) + ->build(); + } + } + + public function simfiles() + { + return $this->_smFiles; + } + + public function isPack() + { + return count($this->_smFiles) > 1; + } + + public function isSingle() + { + return count($this->_smFiles) == 1; + } + + private function findSms() + { + for($i=0; $i<$this->_za->numFiles; $i++) + { + $stat = $this->_za->statIndex($i); + if(pathinfo($stat['name'], PATHINFO_EXTENSION) == 'sm') + { + $smData = file_get_contents('zip://../files/StepMania/' . $this->_file->getHash() . '.zip#' . $stat['name']); + $this->_smFiles[$stat['name']] = $this->SmDataToSmClass($smData); + } + } + } + + private function packNameFromFiles() + { + $packName = ''; + $smpaths = array_keys($this->_smFiles); + foreach($smpaths as $path) + { + $pathComponents = explode('/', $path); + + if(empty($packName)) $packName = $pathComponents[0]; + + if($packName != $pathComponents[0]) + throw new Exception('Malformed zip. I found more than 1 sm file but the directory structure is not consistent with a pack.'); + } + + return $packName; + } + + private function SmDataToSmClass($smData) + { + $parser = $this->_smParser; + $parser->parse($smData); + + $banner = $this->_bannerExtracter->extractSongBanner('../files/StepMania/' . $this->_file->getHash() . '.zip', $parser->banner()); + + return $this->_smBuilder->With_Title($parser->title()) + ->With_Artist($parser->artist()) + ->With_Uploader($this->_userSession->getCurrentUser()) //obj + ->With_BPM($parser->bpm()) + ->With_BpmChanges($parser->bpmChanges()) + ->With_Stops($parser->stops()) + ->With_FgChanges($parser->fgChanges()) + ->With_BgChanges($parser->bgChanges()) + ->With_Steps($parser->steps()) + ->With_Simfile($this->_file) + ->With_Banner($banner) + ->build(); + } +} \ No newline at end of file diff --git a/config/DI.php b/config/DI.php index 298fe53..574d4c1 100644 --- a/config/DI.php +++ b/config/DI.php @@ -8,38 +8,45 @@ return [ 'facebook.app' => '../config/FacebookApp.php', //entites - 'Domain\Entities\StepMania\ISimfile' => DI\object('Domain\Entities\StepMania\Simfile'), - 'Domain\Entities\IUserStepByStepBuilder' => DI\object('Domain\Entities\UserStepByStepBuilder'), - 'Domain\Entities\IUserBuilder' => DI\object('Domain\Entities\UserBuilder'), - 'Domain\Entities\IUserFactory' => DI\object('Domain\Entities\UserFactory'), + 'Domain\Entities\StepMania\ISimfileFactory' => DI\object('Domain\Entities\StepMania\SimfileFactory'), + 'Domain\Entities\StepMania\ISimfileBuilder' => DI\object('Domain\Entities\StepMania\SimfileBuilder'), 'Domain\Entities\StepMania\ISimfileStepByStepBuilder' => DI\object('Domain\Entities\StepMania\SimfileStepByStepBuilder'), - 'Domain\Entities\StepMania\ISimfileBuilder' => DI\object('Domain\Entities\StepMania\SimfileBuilder'), - 'Domain\Entities\StepMania\ISimfileFactory' => DI\object('Domain\Entities\StepMania\SimfileFactory'), - 'Domain\Entities\IFileStepByStepBuilder' => DI\object('Domain\Entities\FileStepByStepBuilder'), - 'Domain\Entities\IFileBuilder' => DI\object('Domain\Entities\FileBuilder'), - 'Domain\Entities\IFileFactory' => DI\object('Domain\Entities\FileFactory'), - + + 'Domain\Entities\StepMania\IPackFactory' => DI\object('Domain\Entities\StepMania\PackFactory'), + 'Domain\Entities\StepMania\IPackBuilder' => DI\object('Domain\Entities\StepMania\PackBuilder'), + 'Domain\Entities\StepMania\IPackStepByStepBuilder' => DI\object('Domain\Entities\StepMania\PackStepByStepBuilder'), + + 'Domain\Entities\IUserFactory' => DI\object('Domain\Entities\UserFactory'), + 'Domain\Entities\IUserBuilder' => DI\object('Domain\Entities\UserBuilder'), + 'Domain\Entities\IUserStepByStepBuilder' => DI\object('Domain\Entities\UserStepByStepBuilder'), + + 'Domain\Entities\IFileFactory' => DI\object('Domain\Entities\FileFactory'), + 'Domain\Entities\IFileBuilder' => DI\object('Domain\Entities\FileBuilder'), + 'Domain\Entities\IFileStepByStepBuilder' => DI\object('Domain\Entities\FileStepByStepBuilder'), + //services - 'Services\Http\IHttpResponse' => DI\object('Services\Http\HttpResponse'), - 'Services\Http\IHttpRequest' => DI\object('Services\Http\HttpRequest'), - 'Services\Routing\IRouter' => DI\object('Services\Routing\Router') - ->constructor(DI\link('router.maps')), - 'Services\Uploads\IUploadManager' => DI\object('Services\Uploads\UploadManager'), - 'Services\IUserSession' => DI\object('Services\UserSession'), - 'Services\Uploads\IFileFactory' => DI\object('Services\Uploads\FileFactory'), - 'Services\IFacebookSessionFactory' => DI\object('Services\FacebookSessionFactory') - ->constructor(DI\link('facebook.app')), - 'Services\ISimfileParser' => DI\object('Services\SimfileParser'), - 'Services\IBannerExtracter' => DI\object('Services\BannerExtracter'), + 'Services\Http\IHttpResponse' => DI\object('Services\Http\HttpResponse'), + 'Services\Http\IHttpRequest' => DI\object('Services\Http\HttpRequest'), + 'Services\Routing\IRouter' => DI\object('Services\Routing\Router') + ->constructor(DI\link('router.maps')), + 'Services\Uploads\IUploadManager' => DI\object('Services\Uploads\UploadManager'), + 'Services\IUserSession' => DI\object('Services\UserSession'), + 'Services\Uploads\IFileFactory' => DI\object('Services\Uploads\FileFactory'), + 'Services\IFacebookSessionFactory' => DI\object('Services\FacebookSessionFactory') + ->constructor(DI\link('facebook.app')), + 'Services\ISimfileParser' => DI\object('Services\SimfileParser'), + 'Services\IZipParser' => DI\object('Services\ZipParser'), + 'Services\IBannerExtracter' => DI\object('Services\BannerExtracter'), //DA - 'DataAccess\StepMania\ISimfileRepository' => DI\object('DataAccess\StepMania\SimfileRepository'), - 'DataAccess\IUserRepository' => DI\object('DataAccess\UserRepository'), - 'DataAccess\IFileRepository' => DI\object('DataAccess\FileRepository'), - 'DataAccess\IDatabaseFactory' => DI\object('DataAccess\DatabaseFactory') - ->constructor(DI\link('db.credentials')), - 'DataAccess\DataMapper\IDataMapper' => DI\object('DataAccess\DataMapper\DataMapper') - ->constructor(DI\link('datamapper.maps')), - 'DataAccess\Queries\IQueryBuilderFactory' => DI\object('DataAccess\Queries\QueryBuilderFactory'), + 'DataAccess\StepMania\ISimfileRepository' => DI\object('DataAccess\StepMania\SimfileRepository'), + 'DataAccess\StepMania\IPackRepository' => DI\object('DataAccess\StepMania\PackRepository'), + 'DataAccess\IUserRepository' => DI\object('DataAccess\UserRepository'), + 'DataAccess\IFileRepository' => DI\object('DataAccess\FileRepository'), + 'DataAccess\IDatabaseFactory' => DI\object('DataAccess\DatabaseFactory') + ->constructor(DI\link('db.credentials')), + 'DataAccess\DataMapper\IDataMapper' => DI\object('DataAccess\DataMapper\DataMapper') + ->constructor(DI\link('datamapper.maps')), + 'DataAccess\Queries\IQueryBuilderFactory' => DI\object('DataAccess\Queries\QueryBuilderFactory'), ]; diff --git a/config/DataMaps.php b/config/DataMaps.php index fb9da91..1d6a2e7 100644 --- a/config/DataMaps.php +++ b/config/DataMaps.php @@ -26,6 +26,18 @@ return [ ] ], + 'Pack' => [ + 'class' => 'Domain\Entities\StepMania\Pack', + 'table' => 'packs', + 'maps' => [ + 'title' => DataAccess\Varchar('title'), + 'uploader' => DataAccess\Entity('User', 'getUploader'), + 'simfiles' => DataAccess\EntityArray('Simfile', 'getSimfiles'), + 'banner' => DataAccess\Entity('File', 'getBanner', 'banner_file'), + 'file' => DataAccess\Entity('File', 'getFile') + ] + ], + 'BPM' => [ 'class' => 'Domain\VOs\StepMania\BPM', 'table' => 'simfiles', diff --git a/config/Routes.php b/config/Routes.php index 1d0eda5..de8cf4b 100644 --- a/config/Routes.php +++ b/config/Routes.php @@ -12,6 +12,12 @@ return [ 'controller' => 'Simfile', 'action' => 'upload' ], + + //XXX: Test, delete later + '/simfiles/pack' => [ + 'methods' => ['GET'], + 'controller' => 'PackTest', + ], '/simfiles/argTest/:testarg' => [ 'methods' => ['GET'], -- 2.11.0