Completed
Push — master ( 206c33...9e77c2 )
by Oscar
05:44
created

Geolocate::__invoke()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
rs 8.8571
cc 5
eloc 9
nc 9
nop 3
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Middleware;
6
use Psr7Middlewares\Utils;
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Geocoder\Geocoder;
10
use Geocoder\ProviderAggregator;
11
use Geocoder\Provider\FreeGeoIp;
12
use Geocoder\Model\AddressCollection;
13
use Ivory\HttpAdapter\FopenHttpAdapter;
14
use RuntimeException;
15
16
/**
17
 * Middleware to geolocate the client using the ip.
18
 */
19
class Geolocate
20
{
21
    use Utils\ContainerTrait;
22
23
    const KEY = 'GEOLOCATE';
24
25
    /**
26
     * @var Geocoder
27
     */
28
    protected $geocoder;
29
30
    /**
31
     * Returns the client location.
32
     *
33
     * @param ServerRequestInterface $request
34
     *
35
     * @return AddressCollection|null
36
     */
37
    public static function getLocation(ServerRequestInterface $request)
38
    {
39
        return Middleware::getAttribute($request, self::KEY);
40
    }
41
42
    /**
43
     * Constructor. Set the geocoder instance.
44
     *
45
     * @param null|Geocoder $geocoder
46
     */
47
    public function __construct(Geocoder $geocoder = null)
48
    {
49
        if ($geocoder !== null) {
50
            $this->geocoder($geocoder);
51
        }
52
    }
53
54
    /**
55
     * Set a geocoder instance.
56
     * 
57
     * @param Geocoder $geocoder
58
     * 
59
     * @return self
60
     */
61
    public function geocoder(Geocoder $geocoder)
62
    {
63
        $this->geocoder = $geocoder;
64
65
        return $this;
66
    }
67
68
    /**
69
     * Execute the middleware.
70
     *
71
     * @param ServerRequestInterface $request
72
     * @param ResponseInterface      $response
73
     * @param callable               $next
74
     *
75
     * @return ResponseInterface
76
     */
77
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
78
    {
79
        if (!Middleware::hasAttribute($request, ClientIp::KEY)) {
80
            throw new RuntimeException('Geolocate middleware needs ClientIp executed before');
81
        }
82
83
        $geocoder = $this->geocoder ?: $this->getFromContainer(Geocoder::CLASS, false) ?: $this->getGeocoder();
84
        $ip = ClientIp::getIp($request);
85
86
        if ($ip) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ip 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...
87
            $ip = '123.9.34.23';
88
            $request = Middleware::setAttribute($request, self::KEY, $geocoder->geocode($ip));
89
        }
90
91
        return $next($request, $response);
92
    }
93
94
    /**
95
     * Create a default geocoder instance.
96
     * 
97
     * @return Geocoder
98
     */
99
    protected function getGeocoder()
100
    {
101
        $geocoder = new ProviderAggregator();
102
        $httpAdapter = new FopenHttpAdapter();
103
        $geocoder->registerProvider(new FreeGeoIp($httpAdapter));
104
105
        return $geocoder;
106
    }
107
}
108