Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Intensity
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
5 / 5
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fetch
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
4
 fetchFromLocalPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 fetchFromUrl
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace Shakemaps\Webservice;
3
4use ArrayIterator;
5use IteratorAggregate;
6use Traversable;
7
8use Fdsn\Webservices\Event\Structs\Id as DS_Id;
9use Fdsn\Webservices\Event\Structs\LatLon as DS_LatLon;
10
11/**
12 * Fetch grid.xml intensity file from Shakemaps portal 
13 * 
14 * @param Fdsn\Webservices\Event\Structs\Id $eventObj Quake to scan for data 
15 * @param string $shakemapsServer (nullable) Server FQDN to connect to (default is shakemaps.rm.ingv.it)
16 * @param string $localFileFullPath (nullable) path to fetch local file  (if exists AND is readable)
17 */
18class Intensity implements IteratorAggregate {
19    private const dataFile = 'grid.xml';
20
21    private string $server;
22    private DS_Id $eventId;
23    
24    private ?string $localFileFullPath = null;
25
26    private string $curlErrInfo;
27    private int $curlErrNum;
28    private array $places = array();
29
30    function __construct ( DS_Id $eventId, ?string $shakemapsServer = Settings::defaultShakemapsServer, ?string $localFileFullPath = null ) {
31
32        $this->eventId = $eventId;
33        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
34
35        if ( is_null($localFileFullPath) )
36            return;
37        
38                $this->localFileFullPath = $localFileFullPath;
39    }
40
41        /**
42         * get all places intensity
43         * 
44         * @return array locality intensity (array of associative arrays[DS_LatLon, mmi, pga, pgv, psa03, psa10, psa30, svel])
45         */
46        public function getIterator():Traversable{ return new ArrayIterator($this->places); }
47 
48        /**
49         * Fetch data (remote or local - if $localFileFullPath is set in __construct)
50         * 
51         * @return int number of data found
52         * 
53         * @internal DOMDocument::load(): <grid_data> contains a HUGE CSV text and xmlSAX2Characters crash
54         *         so i must parse it like an array
55         */
56    public function fetch():int{
57        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
58
59        $xmlAsArray = preg_split("/\n/", $xmlString);
60        foreach($xmlAsArray as $line){
61            if( ! preg_match('/^[0-9]/', $line) ) 
62                continue;
63
64            list($lon, $lat, $mmi, $pga, $pgv, $psa03, $psa10, $psa30, $svel) = preg_split('[\s]', trim($line) );
65            $this->places[] = array(
66                'point' => new DS_LatLon($lat, $lon),
67                'mmi' => $mmi, 
68                'pga' => $pga, 
69                'pgv' => $pgv, 
70                'psa03' => $psa03, 
71                'psa10' => $psa10, 
72                'psa30' => $psa30, 
73                'svel' => $svel
74            );
75        }
76
77        return count($this->places);
78    }
79
80
81        /**
82         * fetch data from local path - if $localFileFullPath is set in __construct()
83         * 
84         * @return string Datafile read in a string or, on missing/unreadable file a RuntimeException is thrown
85         */
86    private function fetchFromLocalPath():string { 
87                if ( ! file_exists($this->localFileFullPath) || ! is_readable($this->localFileFullPath) )
88                        throw new \RuntimeException(sprintf("[%s] file %s not exists or is not readable", __METHOD__, $this->localFileFullPath));
89
90        return file_get_contents( $this->localFileFullPath); 
91    }
92
93        /**
94         * fetch data from url  (remote or local - if $localFileFullPath is set in __construct)
95         * 
96         * @return int number of data found
97         */
98    private function fetchFromUrl():string{
99        $curlSession = curl_init();
100        curl_setopt_array($curlSession, array(
101            CURLOPT_URL             => sprintf(Settings::basePath, $this->server, $this->eventId->value(), self::dataFile),
102            CURLOPT_HEADER          => false,
103            CURLOPT_CUSTOMREQUEST   => 'GET',
104            CURLOPT_RETURNTRANSFER  => 1,
105            CURLOPT_TIMEOUT         => 60
106            )
107        );
108
109        $response = curl_exec($curlSession);
110        $this->curlErrNum = curl_errno($curlSession);
111        $this->curlErrInfo = curl_error($curlSession);
112        curl_close($curlSession);
113
114        if(CURLE_OK != $this->curlErrNum)
115            throw new \RuntimeException( sprintf("[%s] [CurlErr: %d] %s", __METHOD__, $this->curlErrNum, $this->curlErrInfo));
116
117        return $response;
118    }
119}
120?>