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

Branches

Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

Intensity->__construct
32    function __construct ( DS_Id $eventId, ?string $shakemapsServer = Settings::defaultShakemapsServer, ?string $localFileFullPath = null ) {
33
34        $this->eventId = $eventId;
35        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
35        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
35        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
35        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
36
37        if ( is_null($localFileFullPath) )
38            return;
40                $this->localFileFullPath = $localFileFullPath;
41    }
Intensity->fetch
59        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
59        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
59        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
59        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
60
61        $xmlAsArray = preg_split("/\n/", $xmlString);
62        foreach($xmlAsArray as $line){
62        foreach($xmlAsArray as $line){
63            if( ! preg_match('/^[0-9]/', $line) ) 
64                continue;
62        foreach($xmlAsArray as $line){
63            if( ! preg_match('/^[0-9]/', $line) ) 
64                continue;
65
66            list($lon, $lat, $mmi, $pga, $pgv, $psa03, $psa10, $psa30, $svel) = preg_split('[\s]', trim($line) );
62        foreach($xmlAsArray as $line){
63            if( ! preg_match('/^[0-9]/', $line) ) 
64                continue;
65
66            list($lon, $lat, $mmi, $pga, $pgv, $psa03, $psa10, $psa30, $svel) = preg_split('[\s]', trim($line) );
67            $this->places[] = array(
68                'point' => new DS_LatLon($lat, $lon),
69                'mmi' => $mmi, 
70                'pga' => $pga, 
71                'pgv' => $pgv, 
72                'psa03' => $psa03, 
73                'psa10' => $psa10, 
74                'psa30' => $psa30, 
75                'svel' => $svel
76            );
77        }
78
79        return count($this->places);
80    }
Intensity->fetchFromLocalPath
89                if ( ! file_exists($this->localFileFullPath) || ! is_readable($this->localFileFullPath) )
89                if ( ! file_exists($this->localFileFullPath) || ! is_readable($this->localFileFullPath) )
89                if ( ! file_exists($this->localFileFullPath) || ! is_readable($this->localFileFullPath) )
90                        throw new \RuntimeException(sprintf("[%s] file %s not exists or is not readable", __METHOD__, $this->localFileFullPath));
92        return file_get_contents( $this->localFileFullPath); 
93    }
Intensity->fetchFromUrl
101        $curlSession = curl_init();
102        curl_setopt_array($curlSession, array(
103            CURLOPT_URL             => sprintf(Settings::basePath, $this->server, $this->eventId->value(), self::dataFile),
104            CURLOPT_HEADER          => false,
105            CURLOPT_CUSTOMREQUEST   => 'GET',
106            CURLOPT_RETURNTRANSFER  => 1,
107            CURLOPT_TIMEOUT         => 60
108            )
109        );
110
111        $response = curl_exec($curlSession);
112        $this->curlErrNum = curl_errno($curlSession);
113        $this->curlErrInfo = curl_error($curlSession);
114        if ( $this->isCurlCloseSupported() )
115            curl_close($curlSession);
116
117        if(CURLE_OK != $this->curlErrNum)
117        if(CURLE_OK != $this->curlErrNum)
118            throw new \RuntimeException( sprintf("[%s] [CurlErr: %d] %s", __METHOD__, $this->curlErrNum, $this->curlErrInfo));
120        return $response;
121    }
Intensity->getIterator
48        public function getIterator():Traversable{ return new ArrayIterator($this->places); }
Intensity->isCurlCloseSupported
127    private function isCurlCloseSupported():bool{ return PHP_MAJOR_VERSION <= self::curlCloceLatestPhpVersion; }