NoaaIndexParser::parse()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 20
ccs 10
cts 10
cp 1
crap 3
rs 9.9666
1
<?php
2
3
namespace NoaaCapAlerts\Parser;
4
5
class NoaaIndexParser
6
{
7
    protected XmlParser $xmlParser;
8
9 3
    public function __construct(?XmlParser $xmlParser = null)
10
    {
11 3
        if ($xmlParser === null) {
12 2
            $this->xmlParser = new XmlParser();
13
        } else {
14 1
            $this->xmlParser = $xmlParser;
15
        }
16 3
    }
17
18 3
    public function parse(string $xml): array
19
    {
20
        // parse XML into an array of alerts
21 3
        $rawDataArray = $this->xmlParser->getArrayFromXml($xml);
22 2
        $alertDataArray = $rawDataArray[0]['children'];
23
24
        // Process each alert ("ENTRY")
25 2
        $resultArray = array();
26
27 2
        foreach ($alertDataArray as $alert) {
28 2
            if (!$this->isAlert($alert)) {
29 2
                continue;
30
            }
31
32 2
            $parsedAlert = $this->parseAlert($alert);
33
34 2
            $resultArray[] = $parsedAlert;
35
        }
36
37 2
        return $resultArray;
38
    }
39
40 2
    protected function isAlert(array $alert): bool
41
    {
42 2
        return isset($alert['name']) && $alert['name'] == 'ENTRY';
43
    }
44
45 2
    protected function parseAlert(array $alert): array
46
    {
47 2
        $parsedAlert = $this->getDefaultAlertValues();
48
49
        // Loop through attributes and set values
50 2
        foreach ($alert['children'] as $element) {
51 2
            list($elementName, $elementAttrs, $elementData) = $this->parseElementItems($element);
52
53 2
            switch ($elementName) {
54 2
                case 'ID':
55 2
                    $parsedAlert['idString'] = $elementData;
56 2
                    break;
57 2
                case 'UPDATED':
58 2
                    $parsedAlert['updatedDateTime'] = new \DateTime($elementData);
59 2
                    $parsedAlert['updatedTime'] = $parsedAlert['updatedDateTime']->format('Y-m-d H:i:s');
60 2
                    break;
61 2
                case 'PUBLISHED':
62 2
                    $parsedAlert['publishedDateTime'] = new \DateTime($elementData);
63 2
                    $parsedAlert['publishedTime'] = $parsedAlert['publishedDateTime']->format('Y-m-d H:i:s');
64 2
                    break;
65 2
                case 'AUTHOR':
66 2
                    $parsedAlert['authorName'] = $element['children'][0]['tagData'];
67 2
                    break;
68 2
                case 'TITLE':
69 2
                    $parsedAlert['title'] = $elementData;
70 2
                    break;
71 2
                case 'LINK':
72 2
                    $parsedAlert['link'] = $elementAttrs['HREF'];
73 2
                    break;
74 2
                case 'SUMMARY':
75 2
                    $parsedAlert['summary'] = $elementData;
76 2
                    break;
77 2
                case 'CAP:EVENT':
78 2
                    $parsedAlert['capEvent'] = $elementData;
79 2
                    break;
80 2
                case 'CAP:EFFECTIVE':
81 2
                    $effectiveDateTime = new \DateTime($elementData);
82 2
                    $parsedAlert['capEffectiveTime'] = $effectiveDateTime->format('Y-m-d H:i:s');
83 2
                    $parsedAlert['capEffectiveDateTime'] = $effectiveDateTime;
84 2
                    break;
85 2
                case 'CAP:EXPIRES':
86 2
                    $expiresDateTime = new \DateTime($elementData);
87 2
                    $parsedAlert['capExpiresTime'] = $expiresDateTime->format('Y-m-d H:i:s');
88 2
                    $parsedAlert['capExpiresDateTime'] = $expiresDateTime;
89 2
                    break;
90 2
                case 'CAP:STATUS':
91 2
                    $parsedAlert['capStatus'] = $elementData;
92 2
                    break;
93 2
                case 'CAP:MSGTYPE':
94 2
                    $parsedAlert['capMsgType'] = $elementData;
95 2
                    break;
96 2
                case 'CAP:CATEGORY':
97 2
                    $parsedAlert['capCategory'] = $elementData;
98 2
                    break;
99 2
                case 'CAP:URGENCY':
100 2
                    $parsedAlert['capUrgencyExpected'] = $elementData;
101 2
                    break;
102 2
                case 'CAP:SEVERITY':
103 2
                    $parsedAlert['capSeverity'] = $elementData;
104 2
                    break;
105 2
                case 'CAP:CERTAINTY':
106 2
                    $parsedAlert['capCertainty'] = $elementData;
107 2
                    break;
108 2
                case 'CAP:AREADESC':
109 2
                    $parsedAlert['capAreaDesc'] = $elementData;
110 2
                    break;
111 2
                case 'CAP:POLYGON':
112 2
                    $capPolygonString = $elementData;
113 2
                    $parsedAlert['capPolygon'] = explode(' ', $capPolygonString);
114 2
                    break;
115 2
                case 'CAP:GEOCODE':
116 2
                    $geoArray = $this->parseGeoArray($element);
117 2
                    $cleanGeoArray = $this->formatGeoArray($geoArray);
118 2
                    $parsedAlert['capGeoString'] = implode(', ', $geoArray);
119 2
                    $parsedAlert['capGeo'] = $cleanGeoArray;
120 2
                    break;
121 2
                case 'CAP:PARAMETER':
122 2
                    $vtec = $this->parseVtec($element);
123 2
                    $parsedAlert['vtec'] = $vtec;
124 2
                    break;
125
            }
126
127 2
            $parsedAlert['idKey'] = $this->generateIdKey($parsedAlert['idString']);
128
129
        }
130
131 2
        return $parsedAlert;
132
    }
133
134 2
    protected function formatGeoArray(array $geoArray): array
135
    {
136
        // organize array by format type
137
        $locationFormatTypes = array(
138 2
            'FIPS6',
139
            'UGC',
140
        );
141
142 2
        $currentLocationKey = 'null';
143 2
        $geoLocArray = array();
144
145 2
        foreach ($geoArray as $geoLoc) {
146 2
            if (in_array($geoLoc, $locationFormatTypes)) {
147 2
                $currentLocationKey = $geoLoc;
148 2
                $geoLocArray[$geoLoc] = array();
149
            } else {
150 2
                $geoLocArray[$currentLocationKey] = explode(' ', $geoLoc);
151
            }
152
        }
153
154 2
        return $geoLocArray;
155
    }
156
157 2
    /**
158
     * idString contains important data in it as well.
159
     * Use it to generate a unique key for the alert.
160
     *
161
     * Example:
162
     *    alerts.weather.gov/cap/wwacapget.php?x=AK12539092A414.WinterWeatherAdvisory.125390A09AB0AK.AFGWSWNSB.a59f94b5da45867f6f45272a36df61cc
163
     *
164
     * The pieces of idString appears to be
165
     * 0. State abrev + some strange timestamp format
166
     * 1. Type
167
     * 2. Another timestamp with state abrev.
168
     * 3. ??
169
     * 4. Hash of some data (32 bit)
170
     *
171
     * Since 0,1,2, and 3 aren't unique on their own, but it looks like 4 is, I'll plan on using 0 and 4 just to be sure.
172
     *
173
     * @param string $idString
174 2
     * @return string
175 2
     */
176 2
    protected function generateIdKey(string $idString): string
177
    {
178 2
179
        $idParts = explode('=', $idString);
180
        $idSplit = explode('.', $idParts[1]);
181
        $idKey = $idSplit[0] . '.' . $idSplit[4];
182
183
        return $idKey;
184 2
    }
185
186
187 2
    protected function getDefaultAlertValues(): array
188
    {
189
        return array(
190
            'idString' => '',
191
            'idKey' => '',
192
            'updatedDateTime' => null,
193
            'publishedDateTime' => null,
194
            'updatedTime' => '',
195
            'publishedTime' => '',
196
            'authorName' => '',
197
            'title' => '',
198
            'link' => '',
199
            'summary' => '',
200
            'capEvent' => '',
201
            'capEffectiveTime' => '',
202
            'capExpiresTime' => '',
203
            'capEffectiveDateTime' => null,
204
            'capExpiresDateTime' => null,
205
            'capStatus' => '',
206
            'capMsgType' => '',
207
            'capCategory' => '',
208
            'capUrgencyExpected' => '',
209
            'capSeverity' => '',
210
            'capCertainty' => '',
211
            'capAreaDesc' => '',
212
            'capPolygon' => '',
213
            'capGeo' => array(),
214 2
            'capGeoString' => '',
215
            'vtec' => '',
216
        );
217 2
    }
218
219 2
    protected function parseGeoArray(array $element): array
220
    {
221 2
        $geoArray = array();
222 2
223 2
        foreach ($element['children'] as $geo) {
224
            if (isset($geo['tagData'])) {
225
                $geoArray[] = $geo['tagData'];
226
            }
227 2
        }
228
229
        return $geoArray;
230 2
    }
231
232 2
    protected function parseVtec(array $element): string
233 2
    {
234
        if (isset($element['children'][1]['tagData'])) {
235
            return $element['children'][1]['tagData'];
236 1
        }
237
238
        return "";
239 2
    }
240
241 2
    protected function parseElementItems($element): array
242 2
    {
243 2
        $elementName = $element['name'];
244 2
        $elementAttrs = $element['attrs'];
245
        $elementData = $element['tagData'] ?? '';
246 2
        return array($elementName, $elementAttrs, $elementData);
247
    }
248 2
249
}
250