Test Failed
Push — master ( 0a7302...827e28 )
by Carsten
04:14 queued 11s
created

ClientIpLocationMiddleware::setLocationFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
namespace Germania\ClientIpLocation;
3
4
use Psr\Http\Message\ServerRequestInterface;
5
use Psr\Http\Message\ResponseInterface;
6
use Psr\Http\Server\RequestHandlerInterface;
7
use Psr\Http\Server\MiddlewareInterface;
8
9
use Psr\Log\LoggerInterface;
10
use Psr\Log\LogLevel;
11
12
13
/**
14
 * Stores the client's location in the Request.
15
 *
16
 * The location is determined using the client IP coming from a request attribute
17
 * and a location factory callable passed to the constructor.
18
 *
19
 * The client location is not special kind of data;
20
 * any kind of location information coming from the location factory
21
 * will be stored in the request attribute.
22
 */
23
class ClientIpLocationMiddleware implements MiddlewareInterface
24
{
25
26
27
    /**
28
     * Callable that determines Location from Client IP address
29
     *
30
     * @var callable
31
     */
32
    public $location_factory;
33
34
    /**
35
     * @var \Psr\Log\LoggerInterface
36
     */
37
    public $logger;
38
39
40
    /**
41
     * PSR-3 Loglevel name for errors
42
     * @var string
43
     */
44
    protected $error_loglevel = LogLevel::ERROR;
45
46
47
    /**
48
     * Request attribute where the canonical URI shall be stored in.
49
     * @var string
50
     */
51
    public $client_location_attribute_name = "client-location";
52
53
54
    /**
55
     * Request attribute where the Client IP is stored in.
56
     * @var string
57
     */
58
    public $client_ip_attribute_name = 'client-ip';
59
60
61
62
63
    /**
64
     * @param callable        $location_factory   Location factory
65
     * @param LoggerInterface $logger             PSR-3 Logger for errors
66
     * @param LogLevel        $error_loglevel     Optional: PSR-3 Loglevel name for errors (defaults to `error`)
67
     */
68 6
    public function __construct( callable $location_factory, LoggerInterface $logger, string $error_loglevel = LogLevel::ERROR)
69
    {
70 6
        $this->setLocationFactory( $location_factory );
71 6
        $this->error_loglevel = $error_loglevel;
0 ignored issues
show
Documentation Bug introduced by
It seems like $error_loglevel can also be of type object<Psr\Log\LogLevel>. However, the property $error_loglevel is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
72 6
        $this->logger = $logger;
73 6
    }
74
75
76
    public function setLocationFactory( callable $location_factory ) : self
77
    {
78
        $this->location_factory = $location_factory;
79
        return $this;
80
    }
81
82
83
84
    /**
85 4
     * Single-pass (PSR-15 style)
86
     *
87
     * @param  ServerRequestInterface  $request
88 4
     * @param  RequestHandlerInterface $handler
89
     *
90 4
     * @return ResponseInterface
91 2
     */
92
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
93
    {
94
95
        $client_ip = $request->getAttribute( $this->client_ip_attribute_name ) ?: null;
96 2
97 2
        if (empty($client_ip)) {
98
            return $handler->handle($request);
99
        }
100
101
102
        try {
103
            $location = ($this->location_factory)( $client_ip );
104
            $request = $request->withAttribute($this->client_location_attribute_name, $location);
105
        }
106
        catch (\Throwable $e) {
107
            $msg = sprintf("ClientIpLocationMiddleware: %s", $e->getMessage());
108
            $msg_location = sprintf("%s:%s", $e->getFile(), $e->getLine());
109
            $this->logger->log( $this->error_loglevel, $msg, [
110 2
                'type' => get_class($e),
111
                'code' => $e->getCode(),
112
                'location' => $msg_location,
113
                'clientIp' => $client_ip
114
            ]);
115
        }
116
117
118 6
        return $handler->handle($request);
119
    }
120 6
121 6
122
123
    /**
124
     * @param string $attr_name Client IP Attribute Name
125
     */
126
    public function setClientIpAttributeName( string $attr_name ) : self
127
    {
128
        $this->client_ip_attribute_name = $attr_name;
129 6
        return $this;
130
    }
131 6
132 6
133
134
    /**
135
     * @param string $attr_name Client Location Attribute Name
136
     */
137
    public function setClientLocationAttributeName( string $attr_name ) : self
138
    {
139
        $this->client_location_attribute_name = $attr_name;
140
        return $this;
141
    }
142
143
144
}
145