Improvements based on import test.
[rock.divinelegy.git] / Controllers / SimfileController.php
1 <?php
2
3 namespace Controllers;
4
5 use Exception;
6 use Controllers\IDivineController;
7 use Services\Http\IHttpResponse;
8 use Services\Uploads\IUploadManager;
9 use Services\IUserSession;
10 use Services\IZipParser;
11 use Services\ISMOMatcher;
12 use Services\IStatusReporter;
13 use DataAccess\StepMania\ISimfileRepository;
14 use DataAccess\StepMania\IPackRepository;
15 use DataAccess\IFileRepository;
16 use DataAccess\IDownloadRepository;
17 use Domain\Entities\StepMania\ISimfile;
18 use Domain\Entities\IFile;
19 use Domain\Entities\StepMania\IPack;
20 use Domain\Util;
21
22 class SimfileController implements IDivineController
23 {
24 private $_simfileRepository;
25 private $_packRepository;
26 private $_fileRepository;
27 private $_response;
28 private $_uploadManager;
29 private $_zipParser;
30 private $_smoMatcher;
31 private $_downloadRepository;
32 private $_statusReporter;
33 private $_userSession;
34
35 public function __construct(
36 IHttpResponse $response,
37 IUploadManager $uploadManager,
38 ISimfileRepository $simfileRepository,
39 IPackRepository $packRepository,
40 IFileRepository $fileRepository,
41 IUserSession $userSession,
42 IZipParser $zipParser,
43 ISMOMatcher $smoMatcher,
44 IDownloadRepository $downloadRepository,
45 IStatusReporter $statusReporter
46 ) {
47 $this->_response = $response;
48 $this->_uploadManager = $uploadManager;
49 $this->_simfileRepository = $simfileRepository;
50 $this->_packRepository = $packRepository;
51 $this->_fileRepository = $fileRepository;
52 $this->_zipParser = $zipParser;
53 $this->_smoMatcher = $smoMatcher;
54 $this->_downloadRepository = $downloadRepository;
55 $this->_statusReporter = $statusReporter;
56 $this->_userSession = $userSession;
57 }
58
59 public function indexAction() {
60 ;
61 }
62
63 // list simfiles
64 public function listAction()
65 {
66 /* @var $simfile Domain\Entities\StepMania\ISimfile */
67 $simfiles = $this->_simfileRepository->findAll();
68 $packs = $this->_packRepository->findAll();
69 $simfileArray = array();
70 $packArray = array();
71
72 foreach($simfiles as $simfile)
73 {
74 $simfileArray[] = $this->simfileToArray($simfile);
75 }
76
77 foreach($packs as $pack)
78 {
79 $packArray[] = array(
80 'title'=> $pack->getTitle(),
81 'contributors' => $pack->getContributors(),
82 'simfiles' => $this->getPackSimfilesArray($pack),
83 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',
84 'mirrors' => $this->getPackMirrorsArray($pack),
85 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,
86 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null
87 );
88 }
89
90 $returnArray = array('simfiles' => $simfileArray, 'packs' => $packArray);
91
92 $this->_response->setHeader('Content-Type', 'application/json')
93 ->setBody(json_encode($returnArray))
94 ->sendResponse();
95 }
96
97 public function latestSimfileAction()
98 {
99 $simfile = $this->_simfileRepository->findRange(0, -1);
100 $this->_response->setHeader('Content-Type', 'application/json')
101 ->setBody(json_encode($this->simfileToArray(reset($simfile))))
102 ->sendResponse();
103 }
104
105 public function latestPackAction()
106 {
107 $pack = $this->_packRepository->findRange(0, -1);
108 $pack = reset($pack);
109
110 $packArray = array(
111 'title'=> $pack->getTitle(),
112 'contributors' => $pack->getContributors(),
113 'simfiles' => $this->getPackSimfilesArray($pack),
114 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',
115 'mirrors' => $this->getPackMirrorsArray($pack),
116 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,
117 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null
118 );
119
120 $this->_response->setHeader('Content-Type', 'application/json')
121 ->setBody(json_encode($packArray))
122 ->sendResponse();
123 }
124
125 public function popularAction()
126 {
127 $returnArray = array();
128 $popularDownloads = $this->_downloadRepository->findPopular();
129 $popularDownloads = reset($popularDownloads);
130 $packOrFileId = $popularDownloads->getFile()->getId();
131
132 $simfile = $this->_simfileRepository->findByFileId($packOrFileId);
133 if($simfile)
134 {
135 $returnArray = $this->simfileToArray(reset($simfile));
136 } else {
137 $pack = $this->_packRepository->findByFileId($packOrFileId);
138 $pack = reset($pack);
139 $returnArray = array(
140 'title'=> $pack->getTitle(),
141 'contributors' => $pack->getContributors(),
142 'simfiles' => $this->getPackSimfilesArray($pack),
143 'banner' => $pack->getBanner() ? 'files/banner/' . $pack->getBanner()->getHash() : 'files/banner/default',
144 'mirrors' => $this->getPackMirrorsArray($pack),
145 'size' => $pack->getFile() ? Util::bytesToHumanReadable($pack->getFile()->getSize()) : null,
146 'uploaded' => $pack->getFile() ? date('F jS, Y', $pack->getFile()->getUploadDate()) : null
147 );
148 }
149
150 $this->_response->setHeader('Content-Type', 'application/json')
151 ->setBody(json_encode($returnArray))
152 ->sendResponse();
153
154 }
155
156 public function uploadAction()
157 {
158 if(!$this->_userSession->getCurrentUser()) $this->_statusReporter->error('You must be authenticated to upload files');
159
160 //TODO: Put directory in config ?
161 $files = $this->_uploadManager->setFilesDirectory('../files')
162 ->setDestination('StepMania/')
163 ->process();
164
165 foreach($files as $file)
166 {
167 $zipParser = $this->_zipParser;
168 $zipParser->parse($file);
169
170 if(!$zipParser->simfiles()) $this->_statusReporter->error('That zip doesn\'t seem to have any simfiles in it.');
171
172 //save the actual zip in the db
173 $this->findAndAddSmoMirror($file);
174 $this->_fileRepository->save($file);
175
176 if($zipParser->isPack())
177 {
178 //XXX: Tricky! pack() uses packbuilder and so returns a new pack each time.
179 //I tried to be clever and call pack() multiple times thinking I was getting the same
180 //object. Should I cache it in zipparser?
181 $pack = $zipParser->pack();
182 $packBanner = $pack->getBanner() ? $this->_fileRepository->save($pack->getBanner()) : null;
183 $this->_packRepository->save($pack);
184 }
185
186 foreach($zipParser->simfiles() as $simfile)
187 {
188 $banner = $simfile->getBanner() ? $this->_fileRepository->save($simfile->getBanner()) : null;
189 $simfileZip = $simfile->getSimfile() ? $this->_fileRepository->save($simfile->getSimfile()) : null;
190
191 if(isset($pack)) $simfile->addToPack($pack);
192 $this->_simfileRepository->save($simfile);
193 }
194 }
195
196 $this->_statusReporter->success('Uploaded succesfully');
197 }
198
199 private function getPackMirrorsArray(IPack $pack)
200 {
201 $packMirrors = array();
202
203 if($pack->getFile())
204 {
205 $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash());
206 }
207
208 if($pack->getFile()->getMirrors())
209 {
210 foreach($pack->getFile()->getMirrors() as $mirror)
211 {
212 $packMirrors[] = array('source' => $mirror->getSource(), 'uri' => $mirror->getUri());
213 }
214 }
215
216 return $packMirrors;
217 }
218
219 private function getPackSimfilesArray(IPack $pack)
220 {
221 $packSimfiles = array();
222 foreach($pack->getSimfiles() as $simfile)
223 {
224 $packSimfiles[] = $this->simfileToArray($simfile);
225 }
226
227 return $packSimfiles;
228 }
229
230 private function findAndAddSmoMirror(IFile $file)
231 {
232 $basename = pathinfo($file->getFilename(), PATHINFO_FILENAME);
233 $match = $this->_smoMatcher->match($basename, $file->getSize());
234
235 //XXX: Direct instantiation of FileMirror bad?
236 if($match && $match['confidence'] > 90)
237 {
238 $file->addMirror(new \Domain\VOs\FileMirror($match['href'], 'Stepmania Online'));
239 }
240 }
241
242 private function simfileToArray(ISimfile $simfile)
243 {
244 $singleSteps = array();
245 $doubleSteps = array();
246
247 foreach($simfile->getSteps() as $steps)
248 {
249 $stepDetails = array(
250 'artist' => $steps->getArtist()->getTag(),
251 'difficulty' => $steps->getDifficulty()->getITGName(),
252 'rating' => $steps->getRating()
253 );
254
255 if($steps->getMode()->getPrettyName() == 'Single')
256 {
257 $singleSteps[] = $stepDetails;
258 } else {
259 $doubleSteps[] = $stepDetails;
260 }
261 }
262
263 return array(
264 'title' => $simfile->getTitle(),
265 'artist' => $simfile->getArtist()->getName(),
266 'steps' => array(
267 'single' => $singleSteps,
268 'double' => $doubleSteps
269 ),
270 'bgChanges' => $simfile->hasBgChanges() ? 'Yes' : 'No',
271 'fgChanges' => $simfile->hasFgChanges() ? 'Yes' : 'No',
272 'bpmChanges' => $simfile->hasBPMChanges() ? 'Yes' : 'No',
273 'banner' => $simfile->getBanner() ? 'files/banner/' . $simfile->getBanner()->getHash() : 'files/banner/default',
274 'download' => $simfile->getSimfile() ? 'files/simfile/' . $simfile->getSimfile()->getHash() : null,
275 'size' => $simfile->getSimfile() ? Util::bytesToHumanReadable($simfile->getSimfile()->getSize()) : null,
276 'uploaded' => $simfile->getSimfile() ? date('F jS, Y', $simfile->getSimfile()->getUploadDate()) : null
277 );
278 }
279 }