Issues (4)

src/Ridvanbaluyos/Mmda/MMDA.php (4 issues)

1
<?php 
2
3
namespace Ridvanbaluyos\Mmda;
4
5
/**
6
 * Metro Manila Development Authority - Traffic Data
7
 * http://mmdatraffic.interaksyon.com/livefeed/
8
 *
9
 * @package    MMDA Traffic Data
10
 * @author     Ridvan Baluyos <[email protected]>
11
 * @link       https://github.com/ridvanbaluyos/mmda
12
 * @license    MIT
13
 */
14
class MMDA
15
{
16
    const FEED_URL = 'http://mmdatraffic.interaksyon.com';
17
18
    private $trafficData;
19
    private $channel;
20
21
    /**
22
     * MMDA constructor.
23
     */
24
    public function __construct()
25
    {
26
        $metroManilaFeedUrl = self::FEED_URL . '/livefeed/';
27
        $nlexFeedUrl = self::FEED_URL . '/nlex/livefeed/';
28
        
29
        $metroManilaTrafficData = $this->getTrafficData($metroManilaFeedUrl);
30
        $nlexTrafficData = $this->getTrafficData($nlexFeedUrl);
31
        
32
        $this->trafficData = array_merge($metroManilaTrafficData, $nlexTrafficData);
33
    }
34
35
    /**
36
     * This function retrieves the traffic data.
37
     * @return array
38
     */
39
    public function traffic()
40
    {
41
        $traffic = $this->trafficData;
42
43
        return $traffic;
44
    }
45
46
    /**
47
     * This function returns the list of highways.
48
     *
49
     * @return array|null
50
     */
51
    public function highways()
52
    {
53
        if ($this->trafficData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->trafficData 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...
54
            return array_keys($this->trafficData);
55
        }
56
57
        return null;
58
    }
59
60
    /**
61
     * This function returns the list of segments in a given highway.
62
     *
63
     * @param $highway
64
     * @return array|null
65
     */
66
    public function segments($highway = NULL)
67
    {
68
        if ($highway && isset($this->trafficData[$highway]['segments'])) {
69
            return array_keys($this->trafficData[$highway]['segments']);
70
        }
71
72
        return null;
73
    }
74
75
    /**
76
     * This function retrieves the traffic data from the MMDA Traffic API.
77
     *
78
     * @return array
79
     */
80
    final private function getTrafficData($feedUrl)
81
    {
82
        $ch = curl_init();
83
        curl_setopt($ch, CURLOPT_URL, $feedUrl);
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

83
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, $feedUrl);
Loading history...
84
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
85
        $response = curl_exec($ch);
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

85
        $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
86
        curl_close($ch);
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

86
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
87
88
        $xml = simplexml_load_string($response);
89
90
        return $this->sanitizeTrafficData($this->parseTrafficData($xml));
91
    }
92
93
    /**
94
     * This function parses the XML response from the MMDA Traffic API into JSON.
95
     *
96
     * @param $xml
97
     * @return array
98
     */
99
    final private function parseTrafficData($xml)
100
    {
101
        $traffic = [];
102
103
        foreach ($xml->channel->item as $item) {
104
            $item = get_object_vars($item);
105
            $title = $item['title'];
106
            $description = $item['description'];
107
            $pubDate = $item['pubDate'];
108
109
            $highway = explode('-', $title, 2)[0];
110
            $segment = substr(explode('-', $title, 2)[1], 0, -3);
111
            $direction = substr(explode('-', $title, 2)[1], -2);
112
113
            if (empty($traffic[$highway])) $traffic[$highway] = [];
114
            if (empty($traffic[$highway][$segment])) $traffic[$highway][$segment] = [];
115
116
            $traffic[$highway][$segment][$direction] = $description;
117
            $traffic[$highway][$segment]['pubDate'] = $pubDate;
118
        }
119
120
        return $traffic;
121
    }
122
123
    /**
124
     * This function sanitizes the traffic data and organizes them into an envelope
125
     *
126
     * @param array $trafficData
127
     * @return array
128
     */
129
    final private function sanitizeTrafficData(Array $trafficData)
130
    {
131
        $traffic = [];
132
        foreach ($trafficData as $highway=>$segments) {
133
            $traffic[$highway] = [
134
                'name' => $highway,
135
                'label' => $this->convertToTitle($highway),
136
            ];
137
            $traffic[$highway]['segments'] = [];
138
            $dataSegments = [];
139
140
            foreach ($segments as $segment=>$status) {
141
                $dataSegments[$segment] = [
142
                    'name' => $segment,
143
                    'label' => $this->convertToTitle($segment),
144
                    'status' => $this->convertToStatus($status),
145
146
                ];
147
                $traffic[$highway]['segments'] = $dataSegments;
148
            }
149
        }
150
151
        return $traffic;
152
    }
153
154
    /**
155
     * This function converts traffic data status to readable format.
156
     *
157
     * @param array $data
158
     * @return array
159
     */
160
    final private function convertToStatus(Array $data)
161
    {
162
        $statusMatrix = [
163
            '-'  => 'No data',
164
            'L'  => 'Light',
165
            'ML' => 'Light to Moderate',
166
            'M'  => 'Moderate',
167
            'MH' => 'Moderate to Heavy',
168
            'H'  => 'Heavy'
169
        ];
170
171
        $northBound = ($data['SB']) ?? '-';
172
        $southBound = ($data['SB']) ?? '-';
173
174
        $status = [
175
            'NB' => [
176
                'name' => $northBound,
177
                'label' => $statusMatrix[$northBound] . ' Traffic',
178
                'last_updated' => $data['pubDate']
179
            ],
180
            'SB' => [
181
                'name' => $southBound,
182
                'label' => $statusMatrix[$southBound] . ' Traffic',
183
                'last_updated' => $data['pubDate']
184
            ]
185
        ];
186
187
        return $status;
188
    }
189
190
    /**
191
     * This function sanitizes certain abbreviations into readable format.
192
     *
193
     * @param $string
194
     * @return string
195
     */
196
    final private function convertToTitle($string)
197
    {
198
        $string2 = [];
199
        $string = str_replace(['_', 'AVE.', 'BLVD.'], [' ', 'AVENUE', 'BOULEVARD'], $string);
200
        $words = explode(' ', $string);
201
202
        foreach ($words as $word) {
203
            if (!in_array($word, ['EDSA', 'U.N.'])) {
204
                $word = ucwords(mb_strtolower($word));
205
            }
206
            array_push($string2, $word);
207
        }
208
209
        return implode(' ', $string2);
210
    }
211
}