MusicBrainz::browse()   B
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 24
nc 3
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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