Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
90.00% covered (success)
90.00%
54 / 60
90.48% covered (success)
90.48%
38 / 42
35.29% covered (danger)
35.29%
12 / 34
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
MultiInstance
90.00% covered (success)
90.00%
54 / 60
90.48% covered (success)
90.48%
38 / 42
35.29% covered (danger)
35.29%
12 / 34
77.78% covered (warning)
77.78%
7 / 9
180.05
0.00% covered (danger)
0.00%
0 / 1
 __construct
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
 curlErrorNumber
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
 curlErrorInfo
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
 setPreferred
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
6 / 6
25.00% covered (danger)
25.00%
1 / 4
100.00% covered (success)
100.00%
1 / 1
6.80
 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
 findBestContributorByAnalysisType
83.33% covered (warning)
83.33%
10 / 12
88.24% covered (warning)
88.24%
15 / 17
17.65% covered (danger)
17.65%
3 / 17
0.00% covered (danger)
0.00%
0 / 1
43.75
 fetch
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 keepOnlyRowsWithMdpSet
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
 findContributors
77.78% covered (warning)
77.78%
14 / 18
80.00% covered (warning)
80.00%
8 / 10
16.67% covered (danger)
16.67%
1 / 6
0.00% covered (danger)
0.00%
0 / 1
19.47
1<?php
2namespace Dbmi\Webservice\Contributor;
3
4use ArrayIterator;
5use IteratorAggregate;
6use Traversable;
7
8use Dbmi\Webservice\Quake\IdStruct as DS_QuakeId;
9use Dbmi\Webservice\Contributor\SingleInstance as Contributor;
10use Dbmi\Webservice\Contributor\Struct as DS_Contributor;
11
12/**
13 * Get contributors
14 */
15class MultiInstance implements IteratorAggregate{
16    private const templateUrl = 'https://emidius.mi.ingv.it/services/macroseismic/query?eventid=%s&includeallmdpsets=true&format=textmacro';
17    private const minValidResponseLines = 2;
18
19    private DS_QuakeId $quakeId;
20    private array $details = array();
21
22    private array $contributors = array();
23
24    private int $curlErrNum = 0;
25    private string $curlErrInfo = '';
26
27
28    public function __construct(DS_QuakeId $quakeId){
29        $this->quakeId = $quakeId;
30    }
31
32    public function curlErrorNumber(){ return $this->curlErrNum; }
33    public function curlErrorInfo(){ return $this->curlErrInfo; }
34
35    /** 
36     * string $contributor set already choose contributor
37     * 
38     * @return bool TRUE contributor found, false otherwise
39     */
40    public function setPreferred(DS_Contributor $contributor):bool{ 
41        $found = false;
42        foreach($this->contributors as $elem){
43            $elem->setPreferred( $elem->details()->name() == $contributor->name() );
44            if( ! $found )
45                $found = ($elem->details()->name() == $contributor->name());
46        }
47        return $found;
48    }
49
50    /**
51     * get all contributors
52     * 
53     * @return array array of strings with the found contributors
54     */
55    public function getIterator():Traversable{ return new ArrayIterator($this->contributors); }
56
57    /**
58     * get the "best" contributor based an array of analysis type
59     * 
60     * @param array $analysisName find the contributor with the analysis preferred based 
61     *                 on array of names, sorted by preference (for example: array('MCS', 'EMS', ...)
62     * @return Dbmi\Webservice\Contributor\SingleInstance the Contributor found or null
63     */
64    public function findBestContributorByAnalysisType(array $analysisNames):?Contributor {
65        if ( empty($analysisNames) )
66            return null;
67
68        $bestContributor = null;
69        foreach($analysisNames as $name){
70            foreach($this->contributors as $contributor){
71                //same analysis and isPreferred -> it's the best
72                if( $contributor->analisysExists($name) && $contributor->isPreferred() )
73                    return $contributor;
74
75                //same analysis -> i can take it but i loop for a better solution (maybe preferred is later...)
76                if( $contributor->analisysExists($name) )
77                    $bestContributor = $contributor;
78            }
79
80            //if a contributor is found, i'll get it before instead search it in other analysis
81            if( ! is_null($bestContributor) )
82                return $bestContributor;
83        }
84
85        return $bestContributor;
86    }
87    
88    /**
89     * find contributor based on quakeId
90     *
91     * @return int number of studies found
92     */
93    public function fetch():int{
94        $curlSession = curl_init();
95        curl_setopt_array($curlSession, array(
96            CURLOPT_URL         => sprintf(self::templateUrl, $this->quakeId->id()),
97            CURLOPT_HEADER         => false,
98            CURLOPT_CUSTOMREQUEST    => 'GET',
99            CURLOPT_RETURNTRANSFER    => true,
100            CURLOPT_FAILONERROR     => true
101            )
102        );
103        $downloadedData = curl_exec($curlSession);
104
105        $this->curlErrNum = curl_errno($curlSession);
106        $this->curlErrInfo = curl_error($curlSession);
107        curl_close($curlSession);
108
109        if(CURLE_OK != $this->curlErrNum){
110            // @codeCoverageIgnoreStart
111            error_log(sprintf("[%s] [CurlErr: %d] %s", __METHOD__, $this->curlErrNum, $this->curlErrInfo));
112            return -1;
113            // @codeCoverageIgnoreEnd
114        }
115
116        $rows = preg_split("/\n/", trim($downloadedData));
117
118        if( count($rows) < self::minValidResponseLines ){ //header+data
119            error_log(sprintf("[%s] Invalid contributors response, see below\n'%s'", __METHOD__, $downloadedData));
120            return -2;
121        }    
122
123        return $this->findContributors($downloadedData);
124    }
125
126    /** 
127     * filter rows with no mdpset    
128     */
129    private function keepOnlyRowsWithMdpSet($row){ return preg_match('@.*mdpset/(.*)/\d*@', $row); }
130
131    /**
132     * divide found contributors by intensity-type of study
133     */
134    private function findContributors($downloadedData):int{
135        $originaldataArray = preg_split("/\n/", $downloadedData);
136
137        $dataArray = array_filter($originaldataArray, array($this, 'keepOnlyRowsWithMdpSet'));
138        if(0 == count($dataArray)){
139            error_log(sprintf("[%s] No contributor lines with mdpset data\n'%s'", __METHOD__, $downloadedData));
140            return 0;
141        }
142
143        //default/dbmiPreferred contributor should be in the first line
144        $firstLine = true;
145        foreach($dataArray as $data){
146            list($eventId, $mdpsetId, $originTime, $region, $mdpCount, $maxIntensity, $macroseismicScale) = str_getcsv($data, '|');
147            if( ! isset($macroseismicScale) ){
148                error_log(sprintf("[%s] No macroseismic scale found at index[6]\n'%s'", __METHOD__, $data));
149                continue;
150            }
151
152            preg_match('@.*mdpset/(.*)/\d*@', $mdpsetId, $matchArray);
153            $contributorName = $matchArray[1];
154
155            if( ! array_key_exists($contributorName, $this->contributors) )
156                $this->contributors[ $contributorName ] = new Contributor( new DS_Contributor($contributorName, $mdpsetId), $this->quakeId, $firstLine );
157
158            $this->contributors[$contributorName]->addAnalysis($macroseismicScale);
159            $firstLine = false;
160        }
161
162        return count($this->contributors);
163    }
164}
165
166?>
167