Completed
Push — master ( 7dba56...6875ae )
by Oscar
10:21
created

Geolocate::__invoke()   A

Complexity

Conditions 4
Paths 5

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