Completed
Push — master ( 07270e...430475 )
by Dominik
06:51
created

AcceptNegotiator::negotiate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\ApiHttp\Negotiation;
6
7
final class AcceptNegotiator implements NegotiatorInterface
8
{
9
    /**
10
     * @param string $header
11
     * @param array  $supported
12
     *
13
     * @return NegotiatedValue|null
14
     */
15 6
    public function negotiate(string $header, array $supported)
16
    {
17 6
        $aggregatedValues = $this->aggregatedValues($header);
18
19 6
        return $this->compareAgainstSupportedTypes($aggregatedValues, $supported);
20
    }
21
22
    /**
23
     * @param string $header
24
     *
25
     * @return array
26
     */
27 6
    private function aggregatedValues(string $header): array
28
    {
29 6
        $values = [];
30 6
        foreach (explode(',', $header) as $headerValue) {
31 6
            $headerValueParts = explode(';', $headerValue);
32 6
            $contentType = trim(array_shift($headerValueParts));
33 6
            $attributes = [];
34 6
            foreach ($headerValueParts as $attribute) {
35 5
                list($attributeKey, $attributeValue) = explode('=', $attribute);
36 5
                $attributes[trim($attributeKey)] = trim($attributeValue);
37
            }
38
39 6
            if (!isset($attributes['q'])) {
40 6
                $attributes['q'] = '1.0';
41
            }
42
43 6
            $values[$contentType] = $attributes;
44
        }
45
46 6
        uasort($values, function (array $a, array $b) {
47 6
            return $b['q'] <=> $a['q'];
48 6
        });
49
50 6
        return $values;
51
    }
52
53
    /**
54
     * @param array $aggregatedValues
55
     * @param array $supported
56
     *
57
     * @return NegotiatedValue|null
58
     */
59 6
    private function compareAgainstSupportedTypes(array $aggregatedValues, array $supported)
60
    {
61 6
        foreach ($aggregatedValues as $contentType => $attributes) {
62 6
            list($type, $subType) = explode('/', $contentType);
63 6
            if ('*' === $type) {
64 2
                if ('*' !== $subType) {
65 1
                    continue;
66
                }
67
68 1
                foreach ($supported as $supportedContentType) {
69 1
                    return new NegotiatedValue($supportedContentType, $attributes);
70
                }
71
72
                continue;
73
            }
74
75 5
            $subTypePattern = '*' !== $subType ? preg_quote($subType) : '[^\/]+';
76
77 5
            foreach ($supported as $supportedContentType) {
78 5
                if (1 === preg_match('/^'.preg_quote($type).'\/'.$subTypePattern.'$/', $supportedContentType)) {
79 5
                    return new NegotiatedValue($supportedContentType, $attributes);
80
                }
81
            }
82
        }
83
84 2
        return null;
85
    }
86
}
87