Completed
Push — master ( 0d2b02...169528 )
by Christian
02:34 queued 12s
created

FormatNegotiator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\RestBundle\Negotiation;
13
14
use FOS\RestBundle\Util\StopFormatListenerException;
15
use Negotiation\Accept;
16
use Negotiation\Negotiator as BaseNegotiator;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
21
/**
22
 * @author Ener-Getick <[email protected]>
23
 */
24
final class FormatNegotiator extends BaseNegotiator
25
{
26
    private $map = [];
27
    private $requestStack;
28
    private $mimeTypes;
29
30 27
    public function __construct(RequestStack $requestStack, array $mimeTypes = array())
31
    {
32 27
        $this->requestStack = $requestStack;
33 27
        $this->mimeTypes = $mimeTypes;
34 27
    }
35
36 25
    public function add(RequestMatcherInterface $requestMatcher, array $options = [])
37
    {
38 25
        $this->map[] = [$requestMatcher, $options];
39 25
    }
40
41 22
    public function getBest($header, array $priorities = [])
42
    {
43 22
        $request = $this->getRequest();
44 22
        $header = $header ?: $request->headers->get('Accept');
45
46 22
        foreach ($this->map as $elements) {
47
            // Check if the current RequestMatcherInterface matches the current request
48 20
            if (!$elements[0]->matches($request)) {
49 1
                continue;
50
            }
51 20
            $options = &$elements[1]; // Do not reallow memory for this variable
52
53 20
            if (!empty($options['stop'])) {
54 1
                throw new StopFormatListenerException('Stopped format listener');
55
            }
56 19
            if (empty($options['priorities']) && empty($priorities)) {
57 4
                if (!empty($options['fallback_format'])) {
58 4
                    return new Accept($request->getMimeType($options['fallback_format']));
59
                }
60
61 1
                continue;
62
            }
63
64 15
            if (isset($options['prefer_extension']) && $options['prefer_extension'] && !isset($extensionHeader)) {
65 10
                $extension = pathinfo($request->getPathInfo(), PATHINFO_EXTENSION);
66
67 10
                if (!empty($extension)) {
68
                    // $extensionHeader will now be either a non empty string or an empty string
69 5
                    $extensionHeader = $request->getMimeType($extension);
70
71 5
                    if ($extensionHeader) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extensionHeader of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
72 2
                        $header = $extensionHeader.'; q='.$options['prefer_extension'].($header ? ','.$header : '');
73
                    }
74
                }
75
            }
76
77 15
            if ($header) {
78 14
                $mimeTypes = $this->normalizePriorities(
79 14
                    $request,
80 14
                    empty($priorities) ? $options['priorities'] : $priorities
81
                );
82
83 14
                $mimeType = parent::getBest($header, $mimeTypes);
84
85 14
                if (null !== $mimeType) {
86 13
                    return $mimeType;
87
                }
88
            }
89
90 2
            if (isset($options['fallback_format'])) {
91
                // if false === fallback_format then we fail here instead of considering more rules
92 2
                if (false === $options['fallback_format']) {
93
                    return;
94
                }
95
96
                // stop looking at rules since we have a fallback defined
97 2
                return new Accept($request->getMimeType($options['fallback_format']));
98
            }
99
        }
100 4
    }
101
102 14
    private function sanitize(array $values): array
103
    {
104
        return array_map(function ($value) {
105 14
            return preg_replace('/\s+/', '', strtolower($value));
106 14
        }, $values);
107
    }
108
109
    /**
110
     * @param string[] $priorities
111
     *
112
     * @return string[] formatted priorities
113
     */
114 14
    private function normalizePriorities(Request $request, array $priorities): array
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
115
    {
116 14
        $priorities = $this->sanitize($priorities);
117
118 14
        $mimeTypes = array();
119 14
        foreach ($priorities as $priority) {
120 14
            if (strpos($priority, '/')) {
121 4
                $mimeTypes[] = $priority;
122
123 4
                continue;
124
            }
125
126 11
            $mimeTypes = array_merge($mimeTypes, Request::getMimeTypes($priority));
127
128 11
            if (isset($this->mimeTypes[$priority])) {
129 3
                foreach ($this->mimeTypes[$priority] as $mimeType) {
130 3
                    $mimeTypes[] = $mimeType;
131
                }
132
            }
133
        }
134
135 14
        return $mimeTypes;
136
    }
137
138 22
    private function getRequest(): Request
139
    {
140 22
        $request = $this->requestStack->getCurrentRequest();
141 22
        if (null === $request) {
142
            throw new \RuntimeException('There is no current request.');
143
        }
144
145 22
        return $request;
146
    }
147
}
148