1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: wechsler |
5
|
|
|
* Date: 25/02/2017 |
6
|
|
|
* Time: 16:54 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Phase\TakeATicket\SongLoader; |
10
|
|
|
|
11
|
|
|
use Phase\TakeATicket\DataSource\AbstractSql; |
12
|
|
|
use Phase\TakeATicket\Model\Instrument; |
13
|
|
|
use Phase\TakeATicket\Model\Platform; |
14
|
|
|
use Phase\TakeATicket\Model\Song; |
15
|
|
|
use Phase\TakeATicket\Model\Source; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Input file row mapper for the Rock Club London XLS file format |
19
|
|
|
* |
20
|
|
|
* To load other file formats, extend / replace this class and implement RowMapperInterface |
21
|
|
|
*/ |
22
|
|
|
class RclRockBandRowMapper implements RowMapperInterface |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* @var AbstractSql |
26
|
|
|
*/ |
27
|
|
|
protected $dataStore; |
28
|
|
|
/** |
29
|
|
|
* @var bool |
30
|
|
|
*/ |
31
|
|
|
protected $manualIds; |
32
|
|
|
/** |
33
|
|
|
* @var int |
34
|
|
|
*/ |
35
|
|
|
protected $lastId; |
36
|
|
|
|
37
|
|
|
const RESULT_OK = 0; |
38
|
|
|
const RESULT_ERROR = 1; |
39
|
|
|
const RESULT_DUPLICATE = 2; |
40
|
|
|
|
41
|
|
|
const INPUT_FIELD_ARTIST = 'artist'; |
42
|
|
|
const INPUT_FIELD_TITLE = 'title'; |
43
|
|
|
const INPUT_FIELD_HAS_HARMONY = 'hasHarmony'; |
44
|
|
|
const INPUT_FIELD_HAS_KEYS = 'hasKeys'; |
45
|
|
|
const INPUT_FIELD_SOURCE = 'source'; |
46
|
|
|
const INPUT_FIELD_IN_RB3 = 'inRb3'; |
47
|
|
|
const INPUT_FIELD_IN_RB4 = 'inRb4'; |
48
|
|
|
const INPUT_FIELD_DURATION_MMSS = 'duration_mmss'; |
49
|
|
|
const INPUT_FIELD_DURATION = 'duration'; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Column map for input file |
53
|
|
|
* |
54
|
|
|
* @var string[] |
55
|
|
|
*/ |
56
|
|
|
protected $fileFields = [ |
57
|
|
|
'B' => self::INPUT_FIELD_ARTIST, |
58
|
|
|
'C' => self::INPUT_FIELD_TITLE, |
59
|
|
|
'D' => self::INPUT_FIELD_HAS_HARMONY, |
60
|
|
|
'E' => self::INPUT_FIELD_HAS_KEYS, |
61
|
|
|
'I' => self::INPUT_FIELD_SOURCE, |
62
|
|
|
'F' => self::INPUT_FIELD_IN_RB3, |
63
|
|
|
'G' => self::INPUT_FIELD_IN_RB4, |
64
|
|
|
'H' => self::INPUT_FIELD_DURATION_MMSS, |
65
|
|
|
]; |
66
|
|
|
|
67
|
|
|
protected $fieldLookup = []; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* RclRowMapper constructor. |
71
|
|
|
* @param $dataStore |
72
|
|
|
*/ |
73
|
|
|
public function __construct(AbstractSql $dataStore) |
74
|
|
|
{ |
75
|
|
|
$this->dataStore = $dataStore; |
76
|
|
|
$this->manualIds = $dataStore->getDbConn()->getDriver() === 'pdo_mysql'; |
77
|
|
|
$this->lastId = 0; |
78
|
|
|
$this->fieldLookup = array_flip($this->fileFields); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Perform any once-only operations |
83
|
|
|
* |
84
|
|
|
* @return void |
85
|
|
|
*/ |
86
|
|
|
public function init() |
87
|
|
|
{ |
88
|
|
|
//TODO Either load icons from config or remove config option |
89
|
|
|
$instruments = [ |
90
|
|
|
(new Instrument())->setId(1)->setName('Vocals')->setAbbreviation('V') |
91
|
|
|
->setIconHtml('<img src="local/rb-mic.png" class="instrumentIcon"/>'), |
92
|
|
|
(new Instrument())->setId(2)->setName('Guitar')->setAbbreviation('G') |
93
|
|
|
->setIconHtml('<img src="local/rb-guitar.png" class="instrumentIcon"/>'), |
94
|
|
|
(new Instrument())->setId(3)->setName('Bass')->setAbbreviation('B') |
95
|
|
|
->setIconHtml('<img src="local/rb-bass.png" class="instrumentIcon"/>'), |
96
|
|
|
(new Instrument())->setId(4)->setName('Drums')->setAbbreviation('D') |
97
|
|
|
->setIconHtml('<img src="local/rb-drums.png" class="instrumentIcon"/>'), |
98
|
|
|
(new Instrument())->setId(5)->setName('Keyboard')->setAbbreviation('K') |
99
|
|
|
->setIconHtml('<img src="local/rb-keys.png" class="instrumentIcon"/>'), |
100
|
|
|
]; |
101
|
|
|
|
102
|
|
|
foreach ($instruments as $instrument) { |
103
|
|
|
$this->dataStore->storeInstrument($instrument); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
$platforms = [ |
107
|
|
|
new Platform('RB3'), |
108
|
|
|
new Platform('RB4'), |
109
|
|
|
]; |
110
|
|
|
|
111
|
|
|
foreach ($platforms as $platform) { |
112
|
|
|
$this->dataStore->storePlatform($platform); |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Takes a row with column indexes and stores it to the database |
118
|
|
|
* |
119
|
|
|
* Primary table is songs (one per input line) |
120
|
|
|
* Must also manage instruments, platforms, sources |
121
|
|
|
* |
122
|
|
|
* @param array $row Simple array representation of row (character-indexed) |
123
|
|
|
* @return bool |
124
|
|
|
*/ |
125
|
|
|
public function storeRawRow(array $row) |
126
|
|
|
{ |
127
|
|
|
$song = new Song(); |
128
|
|
|
$song |
129
|
|
|
->setArtist($row[$this->fieldLookup[self::INPUT_FIELD_ARTIST]]) |
130
|
|
|
->setTitle($row[$this->fieldLookup[self::INPUT_FIELD_TITLE]]); |
131
|
|
|
|
132
|
|
|
$durationMS = trim($row[$this->fieldLookup[self::INPUT_FIELD_DURATION_MMSS]]); |
133
|
|
View Code Duplication |
if ($durationMS && preg_match('/^\s*(\d+):(\d+)\s*$/', $durationMS, $matches)) { |
|
|
|
|
134
|
|
|
$song->setDuration(($matches[1] * 60) + $matches[2]); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
$sourceName = trim($row[$this->fieldLookup[self::INPUT_FIELD_SOURCE]]); |
138
|
|
|
if ($sourceName) { |
139
|
|
|
$source = $this->dataStore->fetchSourceByName($sourceName); |
140
|
|
|
if (!$source) { |
141
|
|
|
$source = new Source($sourceName); |
142
|
|
|
$this->dataStore->storeSource($source); |
143
|
|
|
} |
144
|
|
|
if ($source) { |
145
|
|
|
$song->setSourceId($source->getId()); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$this->dataStore->storeSong($song); // Store song before all xrefs as we need ID |
150
|
|
|
|
151
|
|
|
// Platforms |
152
|
|
|
$platformIds = []; |
153
|
|
|
$platformFields = [ |
154
|
|
|
self::INPUT_FIELD_IN_RB3 => 'RB3', |
155
|
|
|
self::INPUT_FIELD_IN_RB4 => 'RB4', |
156
|
|
|
]; |
157
|
|
|
foreach ($platformFields as $field => $platformName) { |
158
|
|
|
if (trim($row[$this->fieldLookup[$field]])) { |
159
|
|
|
$platform = $this->dataStore->fetchPlatformByName($platformName); |
160
|
|
|
if (!$platform) { |
161
|
|
|
$platform = new Platform($platformName); |
162
|
|
|
$this->dataStore->storePlatform($platform); |
163
|
|
|
} |
164
|
|
|
$platformIds[] = $platform->getId(); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
$this->dataStore->storeSongPlatformLinks($song->getId(), $platformIds); |
168
|
|
|
|
169
|
|
|
// Instruments - all stored at init(); // TODO add harmony |
170
|
|
|
$instruments = ['Vocals', 'Guitar', 'Bass', 'Drums']; |
171
|
|
|
if (trim($row[$this->fieldLookup[self::INPUT_FIELD_HAS_KEYS]])) { |
172
|
|
|
$instruments[] = 'Keyboard'; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$datastore = $this->dataStore; |
176
|
|
|
$instrumentIds = array_map( |
177
|
|
|
function ($name) use ($datastore) { |
178
|
|
|
$instrument = $datastore->fetchInstrumentByName($name); |
179
|
|
|
return $instrument ? $instrument->getId() : null; |
180
|
|
|
}, |
181
|
|
|
$instruments |
182
|
|
|
); |
183
|
|
|
|
184
|
|
|
$this->dataStore->storeSongInstrumentLinks($song->getId(), $instrumentIds); |
185
|
|
|
|
186
|
|
|
|
187
|
|
|
return true; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
public function getFormatterName() |
191
|
|
|
{ |
192
|
|
|
return 'RCL multi-instrument formatter'; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* @param $row |
198
|
|
|
* |
199
|
|
|
* @return array |
200
|
|
|
*/ |
201
|
|
|
protected function rowToStorable($row) |
202
|
|
|
{ |
203
|
|
|
$directMapFields = [ |
204
|
|
|
self::INPUT_FIELD_ARTIST, |
205
|
|
|
self::INPUT_FIELD_TITLE, |
206
|
|
|
self::INPUT_FIELD_HAS_HARMONY, |
207
|
|
|
self::INPUT_FIELD_HAS_KEYS, |
208
|
|
|
self::INPUT_FIELD_SOURCE, |
209
|
|
|
self::INPUT_FIELD_DURATION, |
210
|
|
|
]; |
211
|
|
|
|
212
|
|
|
$trueIfPresentFields = [ |
213
|
|
|
self::INPUT_FIELD_HAS_HARMONY, |
214
|
|
|
self::INPUT_FIELD_HAS_KEYS, |
215
|
|
|
self::INPUT_FIELD_IN_RB3, |
216
|
|
|
self::INPUT_FIELD_IN_RB4, |
217
|
|
|
]; |
218
|
|
|
|
219
|
|
|
$storable = []; |
220
|
|
|
|
221
|
|
|
foreach ($directMapFields as $k) { |
222
|
|
|
$storable[$k] = empty($row[$k]) ? null : $row[$k]; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
foreach ($trueIfPresentFields as $k) { |
226
|
|
|
$storable[$k] = empty($row[$k]) ? 0 : 1; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
if (isset($row[self::INPUT_FIELD_DURATION_MMSS]) |
230
|
|
|
&& preg_match('/^\s*(\d+):(\d+)\s*$/', $row[self::INPUT_FIELD_DURATION_MMSS], $matches) |
231
|
|
|
) { |
232
|
|
|
$storable[self::INPUT_FIELD_DURATION] = ($matches[1] * 60) + $matches[2]; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
return $storable; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Get short name for form keys, CLI etc. Must be unique |
240
|
|
|
* |
241
|
|
|
* @return string |
242
|
|
|
*/ |
243
|
|
|
public function getShortName() |
244
|
|
|
{ |
245
|
|
|
return 'RclRockBand'; |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.