Completed
Push — master ( 0206c4...e90e98 )
by Guilh
9s
created

FormatNegotiator::getBest()   C

Complexity

Conditions 19
Paths 66

Size

Total Lines 58
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 21.4449

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 58
ccs 30
cts 37
cp 0.8108
rs 6.3822
cc 19
eloc 30
nc 66
nop 2
crap 21.4449

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
class FormatNegotiator extends BaseNegotiator
25
{
26
    private $map = [];
27
    private $requestStack;
28
    private $mimeTypes;
29
30 21
    public function __construct(RequestStack $requestStack, array $mimeTypes = array())
31
    {
32 21
        $this->requestStack = $requestStack;
33 21
        $this->mimeTypes = $mimeTypes;
34 21
    }
35
36
    /**
37
     * @param RequestMatcherInterface $requestMatcher
38
     * @param array                   $options
39
     */
40 16
    public function add(RequestMatcherInterface $requestMatcher, array $options = [])
41
    {
42 16
        $this->map[] = [$requestMatcher, $options];
43 16
    }
44
45
    /**
46
     * {@inheritdoc}
47
     * The best format is also determined in function of the bundle configuration.
48
     *
49
     * @throws StopFormatListenerException
50
     */
51 19
    public function getBest($header, array $priorities = [])
52
    {
53 19
        $request = $this->getRequest();
54 19
        $header = $header ?: $request->headers->get('Accept');
55
56 19
        foreach ($this->map as $elements) {
57
            // Check if the current RequestMatcherInterface matches the current request
58 14
            if (!$elements[0]->matches($request)) {
59 1
                continue;
60
            }
61 14
            $options = &$elements[1]; // Do not reallow memory for this variable
62
63 14
            if (!empty($options['stop'])) {
64 1
                throw new StopFormatListenerException('Stopped format listener');
65
            }
66 13
            if (empty($options['priorities']) && empty($priorities)) {
67 1
                if (!empty($options['fallback_format'])) {
68 1
                    return new Accept($request->getMimeType($options['fallback_format']));
69
                }
70 1
                continue;
71
            }
72
73 12
            if (isset($options['prefer_extension']) && $options['prefer_extension'] && !isset($extensionHeader)) {
74 7
                $extension = pathinfo($request->getPathInfo(), PATHINFO_EXTENSION);
75
76 7
                if (!empty($extension)) {
77
                    // $extensionHeader will now be either a non empty string or an empty string
78
                    $extensionHeader = $request->getMimeType($extension);
79
                    if ($header && $extensionHeader) {
80
                        $header .= ',';
81
                    }
82
                    $header .= $extensionHeader.'; q='.$options['prefer_extension'];
83
                }
84 7
            }
85
86 12
            if ($header) {
87 11
                $mimeTypes = $this->normalizePriorities($request,
88 11
                    empty($priorities) ? $options['priorities'] : $priorities
89 11
                );
90
91 11
                $mimeType = parent::getBest($header, $mimeTypes);
92
93 11
                if ($mimeType !== null) {
94 10
                    return $mimeType;
95
                }
96 1
            }
97
98 2
            if (isset($options['fallback_format'])) {
99
                // if false === fallback_format then we fail here instead of considering more rules
100 2
                if (false === $options['fallback_format']) {
101
                    return;
102
                }
103
104
                // stop looking at rules since we have a fallback defined
105 2
                return new Accept($request->getMimeType($options['fallback_format']));
106
            }
107 7
        }
108 7
    }
109
110
    /**
111
     * @param array $values
112
     *
113
     * @return array
114
     */
115
    private function sanitize(array $values)
116
    {
117 11
        return array_map(function ($value) {
118 11
            return preg_replace('/\s+/', '', strtolower($value));
119 11
        }, $values);
120
    }
121
122
    /**
123
     * Transform the format (json, html, ...) to their mimeType form (application/json, text/html, ...).
124
     *
125
     * @param Request  $request
126
     * @param string[] $priorities
127
     *
128
     * @return string[] formatted priorities
129
     */
130 11
    private function normalizePriorities(Request $request, array $priorities)
131
    {
132 11
        $priorities = $this->sanitize($priorities);
133
134 11
        $mimeTypes = array();
135 11
        foreach ($priorities as $priority) {
136 11
            if (strpos($priority, '/')) {
137 2
                $mimeTypes[] = $priority;
138 2
                continue;
139
            }
140
141 10 View Code Duplication
            if (method_exists(Request::class, 'getMimeTypes')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
142
                $mimeTypes = array_merge($mimeTypes, Request::getMimeTypes($priority));
0 ignored issues
show
Bug introduced by
The method getMimeTypes() does not exist on Symfony\Component\HttpFoundation\Request. Did you maybe mean getMimeType()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
143 10
            } elseif (null !== $request->getMimeType($priority)) {
144 10
                $class = new \ReflectionClass(Request::class);
145 10
                $properties = $class->getStaticProperties();
146 10
                $mimeTypes = array_merge($mimeTypes, $properties['formats'][$priority]);
147 10
            }
148
149 10
            if (isset($this->mimeTypes[$priority])) {
150 7
                foreach ($this->mimeTypes[$priority] as $mimeType) {
151 7
                    $mimeTypes[] = $mimeType;
152 7
                }
153 7
            }
154 11
        }
155
156 11
        return $mimeTypes;
157
    }
158
159
    /**
160
     * @throws \RuntimeException
161
     *
162
     * @return Request
163
     */
164 19 View Code Duplication
    private function getRequest()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
165
    {
166 19
        $request = $this->requestStack->getCurrentRequest();
167 19
        if ($request === null) {
168
            throw new \RuntimeException('There is no current request.');
169
        }
170
171 19
        return $request;
172
    }
173
}
174