MusicBrainz::browseReleaseGroup()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 17

Duplication

Lines 22
Ratio 100 %

Importance

Changes 0
Metric Value
dl 22
loc 22
rs 9.2
c 0
b 0
f 0
cc 2
eloc 17
nc 2
nop 6
1
<?php
2
3
namespace MusicBrainz;
4
5
use MusicBrainz\HttpAdapters\AbstractHttpAdapter;
6
7
/**
8
 * Connect to the MusicBrainz web service
9
 *
10
 * http://musicbrainz.org/doc/Development
11
 *
12
 * @link http://github.com/mikealmond/musicbrainz
13
 * @package MusicBrainz
14
 */
15
class MusicBrainz
16
{
17
    /**
18
     * @var array
19
     */
20
    private static $validIncludes = array(
21
        'artist'        => array(
22
            "recordings",
23
            "releases",
24
            "release-groups",
25
            "works",
26
            "various-artists",
27
            "discids",
28
            "media",
29
            "aliases",
30
            "tags",
31
            "user-tags",
32
            "ratings",
33
            "user-ratings", // misc
34
            "artist-rels",
35
            "label-rels",
36
            "recording-rels",
37
            "release-rels",
38
            "release-group-rels",
39
            "url-rels",
40
            "work-rels",
41
            "annotation"
42
        ),
43
        'annotation'    => array(),
44
        'label'         => array(
45
            "releases",
46
            "discids",
47
            "media",
48
            "aliases",
49
            "tags",
50
            "user-tags",
51
            "ratings",
52
            "user-ratings", // misc
53
            "artist-rels",
54
            "label-rels",
55
            "recording-rels",
56
            "release-rels",
57
            "release-group-rels",
58
            "url-rels",
59
            "work-rels",
60
            "annotation"
61
        ),
62
        'recording'     => array(
63
            "artists",
64
            "releases", // sub queries
65
            "discids",
66
            "media",
67
            "artist-credits",
68
            "tags",
69
            "user-tags",
70
            "ratings",
71
            "user-ratings", // misc
72
            "artist-rels",
73
            "label-rels",
74
            "recording-rels",
75
            "release-rels",
76
            "release-group-rels",
77
            "url-rels",
78
            "work-rels",
79
            "annotation",
80
            "aliases"
81
        ),
82
        'release'       => array(
83
            "artists",
84
            "labels",
85
            "recordings",
86
            "release-groups",
87
            "media",
88
            "artist-credits",
89
            "discids",
90
            "puids",
91
            "echoprints",
92
            "isrcs",
93
            "artist-rels",
94
            "label-rels",
95
            "recording-rels",
96
            "release-rels",
97
            "release-group-rels",
98
            "url-rels",
99
            "work-rels",
100
            "recording-level-rels",
101
            "work-level-rels",
102
            "annotation",
103
            "aliases"
104
        ),
105
        'release-group' => array(
106
            "artists",
107
            "releases",
108
            "discids",
109
            "media",
110
            "artist-credits",
111
            "tags",
112
            "user-tags",
113
            "ratings",
114
            "user-ratings", // misc
115
            "artist-rels",
116
            "label-rels",
117
            "recording-rels",
118
            "release-rels",
119
            "release-group-rels",
120
            "url-rels",
121
            "work-rels",
122
            "annotation",
123
            "aliases"
124
        ),
125
        'work'          => array(
126
            "artists", // sub queries
127
            "aliases",
128
            "tags",
129
            "user-tags",
130
            "ratings",
131
            "user-ratings", // misc
132
            "artist-rels",
133
            "label-rels",
134
            "recording-rels",
135
            "release-rels",
136
            "release-group-rels",
137
            "url-rels",
138
            "work-rels",
139
            "annotation"
140
        ),
141
        'discid'        => array(
142
            "artists",
143
            "labels",
144
            "recordings",
145
            "release-groups",
146
            "media",
147
            "artist-credits",
148
            "discids",
149
            "puids",
150
            "echoprints",
151
            "isrcs",
152
            "artist-rels",
153
            "label-rels",
154
            "recording-rels",
155
            "release-rels",
156
            "release-group-rels",
157
            "url-rels",
158
            "work-rels",
159
            "recording-level-rels",
160
            "work-level-rels"
161
        ),
162
        'echoprint'     => array(
163
            "artists",
164
            "releases"
165
        ),
166
        'puid'          => array(
167
            "artists",
168
            "releases",
169
            "puids",
170
            "echoprints",
171
            "isrcs"
172
        ),
173
        'isrc'          => array(
174
            "artists",
175
            "releases",
176
            "puids",
177
            "echoprints",
178
            "isrcs"
179
        ),
180
        'iswc'          => array(
181
            "artists"
182
        ),
183
        'collection'    => array(
184
            'releases'
185
        )
186
    );
187
    /**
188
     * @var array
189
     */
190
    private static $validBrowseIncludes = array(
191
        'release'       => array(
192
            "artist-credits",
193
            "labels",
194
            "recordings",
195
            "release-groups",
196
            "media",
197
            "discids",
198
            "artist-rels",
199
            "label-rels",
200
            "recording-rels",
201
            "release-rels",
202
            "release-group-rels",
203
            "url-rels",
204
            "work-rels"
205
        ),
206
        'recording'     => array(
207
            "artist-credits",
208
            "tags",
209
            "ratings",
210
            "user-tags",
211
            "user-ratings"
212
        ),
213
        'label'         => array(
214
            "aliases",
215
            "tags",
216
            "ratings",
217
            "user-tags",
218
            "user-ratings"
219
        ),
220
        'artist'        => array(
221
            "aliases",
222
            "tags",
223
            "ratings",
224
            "user-tags",
225
            "user-ratings"
226
        ),
227
        'release-group' => array(
228
            "artist-credits",
229
            "tags",
230
            "ratings",
231
            "user-tags",
232
            "user-ratings"
233
        )
234
    );
235
    /**
236
     * @var array
237
     */
238
    private static $validReleaseTypes = array(
239
        "nat",
240
        "album",
241
        "single",
242
        "ep",
243
        "compilation",
244
        "soundtrack",
245
        "spokenword",
246
        "interview",
247
        "audiobook",
248
        "live",
249
        "remix",
250
        "other"
251
    );
252
    /**
253
     * @var array
254
     */
255
    private static $validReleaseStatuses = array(
256
        "official",
257
        "promotion",
258
        "bootleg",
259
        "pseudo-release"
260
    );
261
    /**
262
     * @var string
263
     */
264
    private $userAgent = 'MusicBrainz PHP Api/0.2.0';
265
    /**
266
     * The username a MusicBrainz user. Used for authentication.
267
     *
268
     * @var string
269
     */
270
    private $user = NULL;
271
    /**
272
     * The password of a MusicBrainz user. Used for authentication.
273
     *
274
     * @var string
275
     */
276
    private $password = NULL;
277
    /**
278
     * The Http adapter used to make requests
279
     *
280
     * @var \MusicBrainz\HttpAdapters\AbstractHttpAdapter
281
     */
282
    private $adapter;
283
284
    /**
285
     * Initializes the class. You can pass the user’s username and password
286
     * However, you can modify or add all values later.
287
     *
288
     * @param HttpAdapters\AbstractHttpAdapter $adapter The Http adapter used to make requests
289
     * @param string                           $user
290
     * @param string                           $password
291
     */
292
    public function __construct(AbstractHttpAdapter $adapter, $user = NULL, $password = NULL)
293
    {
294
        $this->adapter = $adapter;
295
296
        if (NULL !== $user) {
297
            $this->setUser($user);
298
        }
299
300
        if (NULL !== $password) {
301
            $this->setPassword($password);
302
        }
303
    }
304
305
    /**
306
     * Do a MusicBrainz lookup
307
     *
308
     * http://musicbrainz.org/doc/XML_Web_Service
309
     *
310
     * @param string $entity
311
     * @param string $mbid Music Brainz ID
312
     * @param array  $includes
313
     *
314
     * @throws Exception
315
     * @return array
316
     */
317
    public function lookup($entity, $mbid, array $includes = array())
318
    {
319
320
        if (!$this->isValidEntity($entity)) {
321
            throw new Exception('Invalid entity');
322
        }
323
324
        $this->validateInclude($includes, self::$validIncludes[$entity]);
325
326
        $authRequired = $this->isAuthRequired($entity, $includes);
327
328
        $params = array(
329
            'inc' => implode('+', $includes),
330
            'fmt' => 'json'
331
        );
332
333
        $response = $this->adapter->call($entity . '/' . $mbid, $params, $this->getHttpOptions(), $authRequired);
334
335
        return $response;
336
    }
337
338
    /**
339
     * @param Filters\FilterInterface $filter
340
     * @param                         $entity
341
     * @param                         $mbid
342
     * @param array                   $includes
343
     * @param int                     $limit
344
     * @param null                    $offset
345
     * @param array                   $releaseType
346
     * @param array                   $releaseStatus
347
     *
348
     * @return array
349
     * @throws Exception
350
     */
351
    protected function browse(
352
        Filters\FilterInterface $filter,
353
        $entity,
354
        $mbid,
355
        array $includes,
356
        $limit = 25,
357
        $offset = NULL,
358
        $releaseType = array(),
359
        $releaseStatus = array()
360
    ) {
361
        if (!$this->isValidMBID($mbid)) {
362
            throw new Exception('Invalid Music Brainz ID');
363
        }
364
365
        if ($limit > 100) {
366
            throw new Exception('Limit can only be between 1 and 100');
367
        }
368
369
        $this->validateInclude($includes, self::$validBrowseIncludes[$filter->getEntity()]);
370
371
        $authRequired = $this->isAuthRequired($filter->getEntity(), $includes);
372
373
        $params = $this->getBrowseFilterParams($filter->getEntity(), $includes, $releaseType, $releaseStatus);
374
        $params += array(
375
            $entity  => $mbid,
376
            'inc'    => implode('+', $includes),
377
            'limit'  => $limit,
378
            'offset' => $offset,
379
            'fmt'    => 'json'
380
        );
381
382
        $response = $this->adapter->call($filter->getEntity() . '/', $params, $this->getHttpOptions(), $authRequired);
383
384
        return $response;
385
    }
386
387
    /**
388
     * @param       $entity
389
     * @param       $mbid
390
     * @param array $includes
391
     * @param int   $limit
392
     * @param null  $offset
393
     *
394
     * @return array
395
     * @throws Exception
396
     */
397 View Code Duplication
    public function browseArtist($entity, $mbid, array $includes = array(), $limit = 25, $offset = NULL)
398
    {
399
        if (!in_array($entity, array('recording', 'release', 'release-group'))) {
400
            throw new Exception('Invalid browse entity for artist');
401
        }
402
403
        return $this->browse(new Filters\ArtistFilter(array()), $entity, $mbid, $includes, $limit, $offset);
404
    }
405
406
    /**
407
     * @param       $entity
408
     * @param       $mbid
409
     * @param array $includes
410
     * @param int   $limit
411
     * @param null  $offset
412
     *
413
     * @return array
414
     * @throws Exception
415
     */
416 View Code Duplication
    public function browseLabel($entity, $mbid, array $includes, $limit = 25, $offset = NULL)
417
    {
418
        if (!in_array($entity, array('release'))) {
419
            throw new Exception('Invalid browse entity for label');
420
        }
421
422
        return $this->browse(new Filters\LabelFilter(array()), $entity, $mbid, $includes, $limit, $offset);
423
    }
424
425
    /**
426
     * @param       $entity
427
     * @param       $mbid
428
     * @param array $includes
429
     * @param int   $limit
430
     * @param null  $offset
431
     *
432
     * @return array
433
     * @throws Exception
434
     */
435 View Code Duplication
    public function browseRecording($entity, $mbid, array $includes = array(), $limit = 25, $offset = NULL)
436
    {
437
        if (!in_array($entity, array('artist', 'release'))) {
438
            throw new Exception('Invalid browse entity for recording');
439
        }
440
441
        return $this->browse(new Filters\RecordingFilter(array()), $entity, $mbid, $includes, $limit, $offset);
442
    }
443
444
    /**
445
     * @param       string $entity
446
     * @param       string $mbid
447
     * @param array $includes
448
     * @param int   $limit
449
     * @param null  $offset
450
     * @param array $releaseType
451
     * @param array $releaseStatus
452
     *
453
     * @return array
454
     * @throws Exception
455
     */
456
    public function browseRelease(
457
        $entity,
458
        $mbid,
459
        array $includes = array(),
460
        $limit = 25,
461
        $offset = NULL,
462
        $releaseType = array(),
463
        $releaseStatus = array()
464
    ) {
465
        if (!in_array($entity, array('artist', 'label', 'recording', 'release-group'))) {
466
            throw new Exception('Invalid browse entity for release');
467
        }
468
469
        return $this->browse(
470
            new Filters\ReleaseFilter(array()),
471
            $entity,
472
            $mbid,
473
            $includes,
474
            $limit,
475
            $offset,
476
            $releaseType,
477
            $releaseStatus
478
        );
479
    }
480
481
    /**
482
     * @param       $entity
483
     * @param       $mbid
484
     * @param int   $limit
485
     * @param null  $offset
486
     * @param array $includes
487
     * @param array $releaseType
488
     *
489
     * @return array
490
     * @throws Exception
491
     */
492 View Code Duplication
    public function browseReleaseGroup(
493
        $entity,
494
        $mbid,
495
        $limit = 25,
496
        $offset = NULL,
497
        array $includes,
498
        $releaseType = array()
499
    ) {
500
        if (!in_array($entity, array('artist', 'release'))) {
501
            throw new Exception('Invalid browse entity for release group');
502
        }
503
504
        return $this->browse(
505
            new Filters\ReleaseGroupFilter(array()),
506
            $entity,
507
            $mbid,
508
            $includes,
509
            $limit,
510
            $offset,
511
            $releaseType
512
        );
513
    }
514
515
    /**
516
     * Performs a query based on the parameters supplied in the Filter object.
517
     * Returns an array of possible matches with scores, as returned by the
518
     * musicBrainz web service.
519
     *
520
     * Note that these types of queries only return some information, and not all the
521
     * information available about a particular item is available using this type of query.
522
     * You will need to get the MusicBrainz id (mbid) and perform a lookup with browse
523
     * to return complete information about a release. This method returns an array of
524
     * objects that are possible matches.
525
     *
526
     * @param Filters\FilterInterface $filter
527
     * @param int                     $limit
528
     * @param null|int                $offset
529
     *
530
     * @throws Exception
531
     * @return array
532
     */
533
    public function search(Filters\FilterInterface $filter, $limit = 25, $offset = NULL)
534
    {
535
        if (count($filter->createParameters()) < 1) {
536
            throw new Exception('The artist filter object needs at least 1 argument to create a query.');
537
        }
538
539
        if ($limit > 100) {
540
            throw new Exception('Limit can only be between 1 and 100');
541
        }
542
543
        $params = $filter->createParameters(array('limit' => $limit, 'offset' => $offset, 'fmt' => 'json'));
544
545
        $response = $this->adapter->call($filter->getEntity() . '/', $params, $this->getHttpOptions(), FALSE, TRUE);
546
547
        return $filter->parseResponse($response, $this);
548
    }
549
550
    /**
551
     * @param $mbid
552
     *
553
     * @return int
554
     */
555
    public function isValidMBID($mbid)
556
    {
557
        return preg_match("/^(\{)?[a-f\d]{8}(-[a-f\d]{4}){4}[a-f\d]{8}(?(1)\})$/i", $mbid);
558
    }
559
560
    /**
561
     * Check the list of allowed entities
562
     *
563
     * @param string $entity
564
     *
565
     * @return bool
566
     */
567
    private function isValidEntity($entity)
568
    {
569
        return array_key_exists($entity, self::$validIncludes);
570
    }
571
572
    /**
573
     * Some calls require authentication
574
     *
575
     * @param string $entity
576
     * @param $includes
577
     *
578
     * @return bool
579
     */
580
    protected function isAuthRequired($entity, $includes)
581
    {
582
        if (in_array('user-tags', $includes) || in_array('user-ratings', $includes)) {
583
            return TRUE;
584
        }
585
586
        if (substr($entity, 0, strlen('collection')) === 'collection') {
587
            return TRUE;
588
        }
589
590
        return FALSE;
591
    }
592
593
    /**
594
     * @param $includes
595
     * @param $validIncludes
596
     *
597
     * @return bool
598
     * @throws \OutOfBoundsException
599
     */
600
    public function validateInclude($includes, $validIncludes)
601
    {
602
        foreach ($includes as $include) {
603
            if (!in_array($include, $validIncludes)) {
604
                throw new \OutOfBoundsException(sprintf('%s is not a valid include', $include));
605
            }
606
        }
607
608
        return TRUE;
609
    }
610
611
    /**
612
     * @param $values
613
     * @param $valid
614
     *
615
     * @return bool
616
     * @throws Exception
617
     */
618
    public function validateFilter($values, $valid)
619
    {
620
        foreach ($values as $value) {
621
            if (!in_array($value, $valid)) {
622
                throw new Exception(sprintf('%s is not a valid filter', $value));
623
            }
624
        }
625
626
        return TRUE;
627
    }
628
629
    /**
630
     * Check that the status or type values are valid. Then, check that
631
     * the filters can be used with the given includes.
632
     *
633
     * @param  string $entity
634
     * @param  array  $includes
635
     * @param  array  $releaseType
636
     * @param  array  $releaseStatus
637
     *
638
     * @throws Exception
639
     * @return array
640
     */
641
    public function getBrowseFilterParams(
642
        $entity,
643
        $includes,
644
        array $releaseType = array(),
645
        array $releaseStatus = array()
646
    ) {
647
        $this->validateFilter($releaseStatus, self::$validReleaseStatuses);
648
        $this->validateFilter($releaseType, self::$validReleaseTypes);
649
650
        if (!empty($releaseStatus)
651
            && !in_array('releases', $includes)
652
        ) {
653
            throw new Exception("Can't have a status with no release include");
654
        }
655
656
        if (!empty($releaseType)
657
            && !in_array('release-groups', $includes)
658
            && !in_array('releases', $includes)
659
            && $entity != 'release-group'
660
        ) {
661
            throw new Exception("Can't have a release type with no release-group include");
662
        }
663
664
        $params = array();
665
666
        if (!empty($releaseType)) {
667
            $params['type'] = implode('|', $releaseType);
668
        }
669
670
        if (!empty($releaseStatus)) {
671
            $params['status'] = implode('|', $releaseStatus);
672
        }
673
674
        return $params;
675
    }
676
677
    /**
678
     * @return array
679
     */
680
    public function getHttpOptions()
681
    {
682
        return array(
683
            'method'     => 'GET',
684
            'user-agent' => $this->getUserAgent(),
685
            'user'       => $this->getUser(),
686
            'password'   => $this->getPassword()
687
        );
688
    }
689
690
    /**
691
     * Returns the user agent.
692
     *
693
     * @return string
694
     */
695
    public function getUserAgent()
696
    {
697
        return $this->userAgent;
698
    }
699
700
    /**
701
     * Set the user agent for POST requests (and GET requests for user tags)
702
     *
703
     * @param string $application The name of the application using this library
704
     * @param string $version The version of the application using this library
705
     * @param string $contactInfo E-mail or website of the application
706
     *
707
     * @throws Exception
708
     */
709
    public function setUserAgent($application, $version, $contactInfo)
710
    {
711
        if (strpos($version, '-') !== FALSE) {
712
            throw new Exception('User agent: version should not contain a "-" character.');
713
        }
714
715
        $this->userAgent = $application . '/' . $version . ' (' . $contactInfo . ')';
716
    }
717
718
    /**
719
     * Returns the MusicBrainz user
720
     *
721
     * @return string
722
     */
723
    public function getUser()
724
    {
725
        return $this->user;
726
    }
727
728
    /**
729
     * Sets the MusicBrainz user
730
     *
731
     * @param string $user
732
     */
733
    public function setUser($user)
734
    {
735
        $this->user = $user;
736
    }
737
738
    /**
739
     * Returns the user’s password
740
     *
741
     * @return string
742
     */
743
    public function getPassword()
744
    {
745
        return $this->password;
746
    }
747
748
    /**
749
     * Sets the user’s password
750
     *
751
     * @param string $password
752
     */
753
    public function setPassword($password)
754
    {
755
        $this->password = $password;
756
    }
757
}
758