Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
88.71% covered (warning)
88.71%
55 / 62
88.89% covered (warning)
88.89%
40 / 45
35.14% covered (danger)
35.14%
13 / 37
70.00% covered (warning)
70.00%
7 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
ContributorCollection
88.71% covered (warning)
88.71%
55 / 62
88.89% covered (warning)
88.89%
40 / 45
35.14% covered (danger)
35.14%
13 / 37
70.00% covered (warning)
70.00%
7 / 10
210.49
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
95.00% covered (success)
95.00%
19 / 20
83.33% covered (warning)
83.33%
5 / 6
50.00% covered (danger)
50.00%
2 / 4
0.00% covered (danger)
0.00%
0 / 1
6.00
 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
 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 Dbmi\Webservice\Contributor;
3
4use ArrayIterator;
5use IteratorAggregate;
6use Traversable;
7
8use Dbmi\Webservice\Quake\QuakeId;
9
10/**
11 * Get contributors
12 */
13class ContributorCollection implements IteratorAggregate{
14    private const templateUrl = 'https://emidius.mi.ingv.it/services/macroseismic/query?eventid=%s&includeallmdpsets=true&format=textmacro';
15    private const minValidResponseLines = 2;
16
17    private const curlCloceLatestPhpVersion = 7;
18
19    private 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(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(ContributorData $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\Contributor 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        if ( $this->isCurlCloseSupported() )
108            curl_close($curlSession);
109
110        if(CURLE_OK != $this->curlErrNum){
111            // @codeCoverageIgnoreStart
112            error_log(sprintf("[%s] [CurlErr: %d] %s", __METHOD__, $this->curlErrNum, $this->curlErrInfo));
113            return -1;
114            // @codeCoverageIgnoreEnd
115        }
116
117        $rows = preg_split("/\n/", trim($downloadedData));
118
119        if( count($rows) < self::minValidResponseLines ){ //header+data
120            error_log(sprintf("[%s] Invalid contributors response, see below\n'%s'", __METHOD__, $downloadedData));
121            return -2;
122        }    
123
124        return $this->findContributors($downloadedData);
125    }
126
127    /** 
128     * filter rows with no mdpset    
129     */
130    private function keepOnlyRowsWithMdpSet($row){ return preg_match('@.*mdpset/(.*)/\d*@', $row); }
131
132    /**
133     * divide found contributors by intensity-type of study
134     */
135    private function findContributors($downloadedData):int{
136        $originaldataArray = preg_split("/\n/", $downloadedData);
137
138        $dataArray = array_filter($originaldataArray, array($this, 'keepOnlyRowsWithMdpSet'));
139        if(0 == count($dataArray)){
140            error_log(sprintf("[%s] No contributor lines with mdpset data\n'%s'", __METHOD__, $downloadedData));
141            return 0;
142        }
143
144        //default/dbmiPreferred contributor should be in the first line
145        $firstLine = true;
146        foreach($dataArray as $data){
147            list($eventId, $mdpsetId, $originTime, $region, $mdpCount, $maxIntensity, $macroseismicScale) = str_getcsv($data, '|', "\"", "\\");
148            if( ! isset($macroseismicScale) ){
149                error_log(sprintf("[%s] No macroseismic scale found at index[6]\n'%s'", __METHOD__, $data));
150                continue;
151            }
152
153            preg_match('@.*mdpset/(.*)/\d*@', $mdpsetId, $matchArray);
154            $contributorName = $matchArray[1];
155
156            if( ! array_key_exists($contributorName, $this->contributors) )
157                $this->contributors[ $contributorName ] = new Contributor( new ContributorData($contributorName, $mdpsetId), $this->quakeId, $firstLine );
158
159            $this->contributors[$contributorName]->addAnalysis($macroseismicScale);
160            $firstLine = false;
161        }
162
163        return count($this->contributors);
164    }
165
166    /**
167     * Check if curl_close is still supported
168     * @return bool true is supported, false otherwise
169     */
170    private function isCurlCloseSupported():bool{ return PHP_MAJOR_VERSION <= self::curlCloceLatestPhpVersion; }
171}
172
173?>
174

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.

ContributorCollection->__construct
28    public function __construct(QuakeId $quakeId){
29        $this->quakeId = $quakeId;
30    }
ContributorCollection->curlErrorInfo
33    public function curlErrorInfo(){ return $this->curlErrInfo; }
ContributorCollection->curlErrorNumber
32    public function curlErrorNumber(){ return $this->curlErrNum; }
ContributorCollection->fetch
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        if ( $this->isCurlCloseSupported() )
108            curl_close($curlSession);
109
110        if(CURLE_OK != $this->curlErrNum){
110        if(CURLE_OK != $this->curlErrNum){
117        $rows = preg_split("/\n/", trim($downloadedData));
118
119        if( count($rows) < self::minValidResponseLines ){ //header+data
120            error_log(sprintf("[%s] Invalid contributors response, see below\n'%s'", __METHOD__, $downloadedData));
121            return -2;
124        return $this->findContributors($downloadedData);
125    }
ContributorCollection->findBestContributorByAnalysisType
64    public function findBestContributorByAnalysisType(array $analysisNames):?Contributor {
65        if ( empty($analysisNames) )
66            return null;
68        $bestContributor = null;
69        foreach($analysisNames as $name){
69        foreach($analysisNames as $name){
70            foreach($this->contributors as $contributor){
70            foreach($this->contributors as $contributor){
72                if( $contributor->analisysExists($name) && $contributor->isPreferred() )
72                if( $contributor->analisysExists($name) && $contributor->isPreferred() )
72                if( $contributor->analisysExists($name) && $contributor->isPreferred() )
73                    return $contributor;
76                if( $contributor->analisysExists($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;
70            foreach($this->contributors as $contributor){
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;
69        foreach($analysisNames as $name){
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    }
ContributorCollection->findContributors
135    private function findContributors($downloadedData):int{
136        $originaldataArray = preg_split("/\n/", $downloadedData);
137
138        $dataArray = array_filter($originaldataArray, array($this, 'keepOnlyRowsWithMdpSet'));
139        if(0 == count($dataArray)){
140            error_log(sprintf("[%s] No contributor lines with mdpset data\n'%s'", __METHOD__, $downloadedData));
141            return 0;
145        $firstLine = true;
146        foreach($dataArray as $data){
146        foreach($dataArray as $data){
147            list($eventId, $mdpsetId, $originTime, $region, $mdpCount, $maxIntensity, $macroseismicScale) = str_getcsv($data, '|', "\"", "\\");
148            if( ! isset($macroseismicScale) ){
149                error_log(sprintf("[%s] No macroseismic scale found at index[6]\n'%s'", __METHOD__, $data));
150                continue;
153            preg_match('@.*mdpset/(.*)/\d*@', $mdpsetId, $matchArray);
154            $contributorName = $matchArray[1];
155
156            if( ! array_key_exists($contributorName, $this->contributors) )
157                $this->contributors[ $contributorName ] = new Contributor( new ContributorData($contributorName, $mdpsetId), $this->quakeId, $firstLine );
158
159            $this->contributors[$contributorName]->addAnalysis($macroseismicScale);
146        foreach($dataArray as $data){
147            list($eventId, $mdpsetId, $originTime, $region, $mdpCount, $maxIntensity, $macroseismicScale) = str_getcsv($data, '|', "\"", "\\");
148            if( ! isset($macroseismicScale) ){
149                error_log(sprintf("[%s] No macroseismic scale found at index[6]\n'%s'", __METHOD__, $data));
150                continue;
151            }
152
153            preg_match('@.*mdpset/(.*)/\d*@', $mdpsetId, $matchArray);
154            $contributorName = $matchArray[1];
155
156            if( ! array_key_exists($contributorName, $this->contributors) )
157                $this->contributors[ $contributorName ] = new Contributor( new ContributorData($contributorName, $mdpsetId), $this->quakeId, $firstLine );
158
159            $this->contributors[$contributorName]->addAnalysis($macroseismicScale);
146        foreach($dataArray as $data){
147            list($eventId, $mdpsetId, $originTime, $region, $mdpCount, $maxIntensity, $macroseismicScale) = str_getcsv($data, '|', "\"", "\\");
148            if( ! isset($macroseismicScale) ){
149                error_log(sprintf("[%s] No macroseismic scale found at index[6]\n'%s'", __METHOD__, $data));
150                continue;
151            }
152
153            preg_match('@.*mdpset/(.*)/\d*@', $mdpsetId, $matchArray);
154            $contributorName = $matchArray[1];
155
156            if( ! array_key_exists($contributorName, $this->contributors) )
157                $this->contributors[ $contributorName ] = new Contributor( new ContributorData($contributorName, $mdpsetId), $this->quakeId, $firstLine );
158
159            $this->contributors[$contributorName]->addAnalysis($macroseismicScale);
160            $firstLine = false;
161        }
162
163        return count($this->contributors);
164    }
ContributorCollection->getIterator
55    public function getIterator():Traversable{ return new ArrayIterator($this->contributors); }
ContributorCollection->isCurlCloseSupported
170    private function isCurlCloseSupported():bool{ return PHP_MAJOR_VERSION <= self::curlCloceLatestPhpVersion; }
ContributorCollection->keepOnlyRowsWithMdpSet
130    private function keepOnlyRowsWithMdpSet($row){ return preg_match('@.*mdpset/(.*)/\d*@', $row); }
ContributorCollection->setPreferred
40    public function setPreferred(ContributorData $contributor):bool{ 
41        $found = false;
42        foreach($this->contributors as $elem){
42        foreach($this->contributors as $elem){
43            $elem->setPreferred( $elem->details()->name() == $contributor->name() );
44            if( ! $found )
42        foreach($this->contributors as $elem){
43            $elem->setPreferred( $elem->details()->name() == $contributor->name() );
44            if( ! $found )
45                $found = ($elem->details()->name() == $contributor->name());
42        foreach($this->contributors as $elem){
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    }