Artist is allowed to be null.
[rock.divinelegy.git] / Services / ZipParser.php
1 <?php
2
3 namespace Services;
4
5 use Exception;
6 use ZipArchive;
7 use Services\ISimfileParser;
8 use Services\IBannerExtracter;
9 use Domain\Entities\IFile;
10 use Domain\Entities\StepMania\ISimfileStepByStepBuilder;
11 use Domain\Entities\StepMania\IPackStepByStepBuilder;
12 use Services\IZipParser;
13 use Services\IUserSession;
14
15 class ZipParser implements IZipParser
16 {
17 private $_za;
18 private $_smFiles = array();
19 private $_smParser;
20 private $_smBuilder;
21 private $_packBuilder;
22 private $_bannerExtracter;
23 private $_userSession;
24 private $_file;
25
26 public function __construct(
27 ISimfileParser $smParser,
28 ISimfileStepByStepBuilder $smBuilder,
29 IPackStepByStepBuilder $packBuilder,
30 IBannerExtracter $bannerExtracter,
31 IUserSession $userSession
32 ) {
33 $this->_smParser = $smParser;
34 $this->_smBuilder = $smBuilder;
35 $this->_packBuilder = $packBuilder;
36 $this->_bannerExtracter = $bannerExtracter;
37 $this->_userSession = $userSession;
38 }
39
40 public function parse(IFile $file)
41 {
42 $this->_file = $file;
43 $this->_za = new ZipArchive();
44 //XXX: We assume all files are zips. Should be enforced by validation elsewhere.
45 $res = $this->_za->open('../files/StepMania/' . $file->getHash() . '.zip');
46
47 if($res !== true) throw new Exception ('Could not open zip for reading.');
48 $this->findSms();
49 }
50
51 public function pack()
52 {
53 if(count($this->_smFiles) > 1)
54 {
55 $packname = $this->packNameFromFiles();
56 $banner = $this->_bannerExtracter->extractPackBanner('../files/StepMania/' . $this->_file->getHash() . '.zip', $packname);
57
58 /* @var $builder \Domain\Entities\StepMania\PackStepByStepBuilder */
59 $builder = $this->_packBuilder;
60 return $builder->With_Title($packname)
61 ->With_Uploader($this->_userSession->getCurrentUser())
62 //->With_Simfiles($this->_smFiles)
63 ->With_Simfiles(array())
64 ->With_Banner($banner)
65 ->With_File($this->_file)
66 ->build();
67 }
68 }
69
70 public function simfiles()
71 {
72 return $this->_smFiles;
73 }
74
75 public function isPack()
76 {
77 return count($this->_smFiles) > 1;
78 }
79
80 public function isSingle()
81 {
82 return count($this->_smFiles) == 1;
83 }
84
85 private function findSms()
86 {
87 for($i=0; $i<$this->_za->numFiles; $i++)
88 {
89 $stat = $this->_za->statIndex($i);
90 if(pathinfo($stat['name'], PATHINFO_EXTENSION) == 'sm')
91 {
92 $path = realpath('../files/StepMania/' . $this->_file->getHash() . '.zip');
93 $smData = file_get_contents('zip://' . $path . '#' . $stat['name']);
94 $this->_smFiles[$stat['name']] = $smData;
95 }
96 }
97
98 //XXX: Hack. SmDataToSmClass needs to know whether we are dealing with a pack
99 //or single, but to do that we simply check the number of found sm files. To overcome this
100 //first populate the smFiles array with the raw sm data, then apply SmDataToSmClass on each
101 //array element. This way the check is accurate and the array gets populated as expected.
102 $this->_smFiles = array_map(array($this, 'SmDataToSmClass'), $this->_smFiles);
103 }
104
105 private function packNameFromFiles()
106 {
107 $packName = '';
108 $smpaths = array_keys($this->_smFiles);
109 foreach($smpaths as $path)
110 {
111 $pathComponents = explode('/', $path);
112
113 if(empty($packName)) $packName = $pathComponents[0];
114
115 if($packName != $pathComponents[0])
116 throw new Exception('Malformed zip. I found more than 1 sm file but the directory structure is not consistent with a pack.');
117 }
118
119 return utf8_encode($packName);
120 }
121
122 private function SmDataToSmClass($smData)
123 {
124 $parser = $this->_smParser;
125 $parser->parse($smData);
126 $banner = $this->_bannerExtracter->extractSongBanner(realpath('../files/StepMania/' . $this->_file->getHash() . '.zip'), $parser->banner());
127 $file = $this->isPack() ? null : $this->_file;
128
129 return $this->_smBuilder->With_Title($parser->title())
130 ->With_Artist($parser->artist())
131 ->With_Uploader($this->_userSession->getCurrentUser()) //obj
132 ->With_BPM($parser->bpm())
133 ->With_BpmChanges($parser->bpmChanges())
134 ->With_Stops($parser->stops())
135 ->With_FgChanges($parser->fgChanges())
136 ->With_BgChanges($parser->bgChanges())
137 ->With_Steps($parser->steps())
138 ->With_Simfile($file)
139 ->With_Banner($banner)
140 ->build();
141 }
142 }