Completed
Pull Request — 3.x (#127)
by Joschi
02:04
created

Accepts   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 10
lcom 0
cbo 2
dl 0
loc 84
c 3
b 0
f 0
ccs 27
cts 27
cp 1
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A matches() 0 15 4
A __invoke() 0 13 3
A match() 0 18 3
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\Router\Rule;
10
11
use Aura\Router\Route;
12
use Psr\Http\Message\ServerRequestInterface;
13
14
/**
15
 *
16
 * A rule for "Accept" headers.
17
 *
18
 * @package Aura.Router
19
 *
20
 */
21
class Accepts implements RuleInterface
22
{
23
    /**
24
     *
25
     * Check that the request Accept headers match one Route accept value.
26
     *
27
     * @param ServerRequestInterface $request The HTTP request.
28
     *
29
     * @param Route $route The route.
30
     *
31
     * @return bool True on success, false on failure.
32
     *
33
     */
34 4
    public function __invoke(ServerRequestInterface $request, Route $route)
35
    {
36 4
        if (! $route->accepts) {
0 ignored issues
show
Documentation introduced by
The property $accepts is declared protected in Aura\Router\Route. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug Best Practice introduced by
The expression $route->accepts of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
37 3
            return true;
38
        }
39
40 1
        $requestAccepts = $request->getHeader('Accept');
41 1
        if (! $requestAccepts) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $requestAccepts of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
42 1
            return true;
43
        }
44
45 1
        return $this->matches($route->accepts, $requestAccepts);
0 ignored issues
show
Documentation introduced by
The property $accepts is declared protected in Aura\Router\Route. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
46
    }
47
48
    /**
49
     *
50
     * Does what the route accepts match what the request accepts?
51
     *
52
     * @param array $routeAccepts What the route accepts.
53
     *
54
     * @param array $requestAccepts What the request accepts.
55
     *
56
     * @return bool
57
     *
58
     */
59 1
    protected function matches($routeAccepts, $requestAccepts)
60
    {
61 1
        $requestAccepts = implode(';', $requestAccepts);
62 1
        if ($this->match('*/*', $requestAccepts)) {
63 1
            return true;
64
        }
65
66 1
        foreach ($routeAccepts as $type) {
67 1
            if ($this->match($type, $requestAccepts)) {
68 1
                return true;
69
            }
70 1
        }
71
72 1
        return false;
73
    }
74
75
    /**
76
     *
77
     * Is the Accept header a match?
78
     *
79
     * @param string $type The Route accept type.
80
     *
81
     * @param string $header The Request accept header.
82
     *
83
     * @return bool True on a match, false if not.
84
     *
85
     */
86 1
    protected function match($type, $header)
87
    {
88 1
        list($type, $subtype) = explode('/', $type);
89 1
        $type = preg_quote($type);
90 1
        $subtype = preg_quote($subtype);
91 1
        $regex = "#$type/($subtype|\*)(;q=(\d\.\d))?#";
92
93 1
        $found = preg_match($regex, $header, $matches);
94 1
        if (! $found) {
95 1
            return false;
96
        }
97
98 1
        if (isset($matches[3])) {
99 1
            return $matches[3] !== '0.0';
100
        }
101
102 1
        return true;
103
    }
104
}
105