Completed
Push — master ( a64d0e...1e4648 )
by Martin
02:27
created

WeatherModel::startMultiCurl()   B

Complexity

Conditions 8
Paths 12

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nc 12
nop 3
dl 0
loc 33
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
namespace Anax\Weather;
4
5
// use Anax\Route\Exception\ForbiddenException;
6
// use Anax\Route\Exception\NotFoundException;
7
// use Anax\Route\Exception\InternalErrorException;
8
9
/**
10
 * Model class witch main responsability is handeling data for /vader
11
 *
12
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
13
 */
14
class WeatherModel
15
{
16
    /**
17
     * @var string $apiKey initializes the key
18
     */
19
    protected $apiKey;
20
21
    /**
22
     * Sets the api key.
23
     *
24
     * @return void
25
     */
26
    public function __construct()
27
    {
28
        $prep = require ANAX_INSTALL_PATH . "/config/keys.php";
29
        $this->apiKey = $prep["darksky"];
30
    }
31
32
    /**
33
     * Gets the weekly weather.
34
     *
35
     * @param array $coords contains the values longitude and latitude.
36
     *
37
     * @return array with the weekly weather data.
38
     */
39
    public function getData(array $coords) : array
40
    {
41
        if (!isset($coords[0]['lat']) || !isset($coords[0]['lon'])) {
42
            return [];
43
        }
44
45
        $accessKey = $this->apiKey;
46
        $location = $coords[0]['lat'] . ',' . $coords[0]['lon'];
47
48
        $chA = curl_init(
49
            'https://api.darksky.net/forecast/'.
50
            $accessKey . '/' . $location.
51
            '?exclude=minutely,hourly,currently,alerts,flags&extend=daily&lang=sv&units=auto'
52
        );
53
        curl_setopt($chA, CURLOPT_RETURNTRANSFER, true);
54
        $json = curl_exec($chA);
55
        curl_close($chA);
56
57
        $apiRes = json_decode($json, true);
58
        return [$apiRes];
59
    }
60
61
    /**
62
     * Gets todays date and subtract the number of days sent in
63
     *
64
     * @param string|int $nrOfDays the number of days
65
     *
66
     * @return string the date in unix format
67
     */
68
    public function getDate($nrOfDays) : string
69
    {
70
        $myDate = new \Datetime();
71
        $myDate->sub(new \DateInterval('P'. (intval($nrOfDays) + 1) .'D'));
72
        return $myDate->format('U');
73
    }
74
75
    /**
76
     * Takes a location and turns it into coordinates.
77
     *
78
     * @param string $adrs the location, can be anything like Zip, adress and so on
79
     *
80
     * @return array with longitude and latitude values NOTE: will be empty if nothing is found
81
     */
82
    public function geocode(string $adrs) : array
83
    {
84
        $city = urlencode($adrs);
85
86
        // Just a random email query (not returning anything wihtout it ??)
87
        $url = "https://nominatim.openstreetmap.org/?format=json&addressdetails=1&q={$city}&limit=1&[email protected]";
88
        
89
        $chA = curl_init($url);
90
        curl_setopt($chA, CURLOPT_RETURNTRANSFER, true);
91
        $json = curl_exec($chA);
92
        curl_close($chA);
93
94
        $apiRes = json_decode($json, true) ?? [];
95
        return $apiRes;
96
    }
97
98
    /**
99
     * Preforms a multi curl to get the previus weather
100
     *
101
     * @param string|int    $nrOfDays amount of previus days
102
     * @param string        $adrs the position
103
     *
104
     * @return array with all the weather details for each day
105
     */
106
    public function multiCurl($nrOfDays, string $adrs) : array
107
    {
108
        $urls = $this->getUrls($nrOfDays, $adrs);
109
110
        if ($urls == [[]] || $urls == []) {
111
            return [[]];
112
        }
113
114
        return $this->startMultiCurl($urls);
115
    }
116
117
    public function startMultiCurl(array $urls, array $handles = [], array $htmls = []) : array
118
    {
119
        $multi = curl_multi_init();
120
121
        foreach ($urls as $url) {
122
            $ch = curl_init($url);
123
            curl_setopt($ch, CURLOPT_HEADER, false);
124
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
125
126
            curl_multi_add_handle($multi, $ch);
127
            $handles[$url] = $ch;
128
        }
129
130
        do {
131
            $mrc = curl_multi_exec($multi, $active);
132
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
133
134
        while ($active && $mrc == CURLM_OK) {
135
            if (curl_multi_select($multi) == -1) {
136
                usleep(100);
137
            }
138
            do {
139
                $mrc = curl_multi_exec($multi, $active);
140
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
141
        }
142
        foreach ($handles as $channel) {
143
            $html = curl_multi_getcontent($channel);
144
            $htmls[] = json_decode($html, true);
145
            curl_multi_remove_handle($multi, $channel);
146
        }
147
148
        curl_multi_close($multi);
149
        return $htmls;
150
    }
151
152
    /**
153
     * Returns the api key for DarkS.N
154
     *
155
     * @return string api key
156
     */
157
    private function getKey() : string
158
    {
159
        return $this->apiKey;
160
    }
161
162
    /**
163
     * Returns a list of urls
164
     *
165
     * @param string|int $nrOfDays the total amount of days (MAX 30)
166
     * @param string $adrs the given adress/location
167
     *
168
     * @return array a list of urls to curl
169
     */
170
    private function getUrls($nrOfDays, string $adrs) : array
171
    {
172
        $coords = $this->geocode($adrs);
173
        $nrOfDays = ($nrOfDays > 30) ? 30 : $nrOfDays;
174
175
        if ($coords == []) {
176
            return [[]];
177
        }
178
179
        $urls = [];
180
        $accessKey = $this->getKey();
181
        $location = $coords[0]['lat'] . ',' . $coords[0]['lon'];
182
183
        for ($i = 0; $i < $nrOfDays; $i++) {
184
            $time = $this->getDate("$i");
185
            $urls[] = 'https://api.darksky.net/forecast/'.$accessKey.'/'.$location.','.$time.'?exclude=minutely,hourly,currently,alerts,flags&extend=daily&lang=sv&units=auto';
186
        }
187
188
        return $urls;
189
    }
190
    /**
191
     * Method to test dipendency injection
192
     * Might aswell be ignored
193
     *
194
     * @return string the title for a view
195
     */
196
    public function hello() : string
197
    {
198
        return 'Väder app (Test - Taget från $di->get("weather"))';
199
    }
200
}
201