Passed
Push — master ( d0e7a6...44374d )
by Dispositif
02:28
created

WikidataAdapter   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 64
c 5
b 0
f 0
dl 0
loc 140
rs 10
wmc 20

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A getDataByInfos() 0 14 4
A ISNIvalide() 0 3 2
A findArticleByISBN13() 0 25 2
B sparqlRequest() 0 34 8
A searchByISNI() 0 21 2
1
<?php
2
/**
3
 * This file is part of dispositif/wikibot application
4
 * 2019 © Philippe M. <[email protected]>
5
 * For the full copyright and MIT license information, please view the LICENSE file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Infrastructure;
11
12
use Exception;
13
use GuzzleHttp\Client;
14
use Normalizer;
15
16
/**
17
 * dirty scratch WikiData read requests
18
 * Class WikidataAdapter
19
 *
20
 * @package App\Infrastructure
21
 */
22
class WikidataAdapter
23
{
24
    private $client;
25
26
    public function __construct(?Client $client = null)
27
    {
28
        if (null === $client) {
29
            // lazy dependency factory :)
30
            $this->client = new Client(['timeout' => 5, 'headers' => ['User-Agent' => getenv('USER_AGENT')]]);
31
        } else {
32
            $this->client = $client;
33
        }
34
    }
35
36
    public function getDataByInfos(?array $infos)
37
    {
38
        $res = [];
39
        if (isset($infos['ISNIAuteur1'])) {
40
            $res = $this->searchByISNI($infos['ISNIAuteur1']);
41
        }
42
        if (isset($infos['isbn'])) {
43
            if(!empty($res)) {
44
                sleep(2);
45
            }
46
            $res = array_merge($res, $this->findArticleByISBN13($infos['isbn']));
0 ignored issues
show
Bug introduced by
It seems like $res can also be of type null; however, parameter $array1 of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

46
            $res = array_merge(/** @scrutinizer ignore-type */ $res, $this->findArticleByISBN13($infos['isbn']));
Loading history...
47
        }
48
49
        return $res;
50
    }
51
52
    public function findArticleByISBN13(string $isbn): ?array
53
    {
54
        // strip ISBN formating
55
        $isbn = preg_replace('#[^0-9X]#', '', $isbn);
56
        if (strlen($isbn) !== 13) {
57
            throw new \DomainException('ISBN-13 format error');
58
        }
59
60
        $sparql = sprintf(
61
            'select ?work ?workLabel ?articleBook ?edition ?isbn
62
WHERE {
63
    ?work wdt:P31 wd:Q47461344 ; # instance of written work
64
        wdt:P747 ?edition . # has edition (P747)
65
    ?edition wdt:P212 $isbn . # ISBN-13 (P212)
66
    FILTER(REGEX(REPLACE(?isbn,"-",""), "%s", "i")). # strip ISBN formating
67
    ?articleBook schema:about ?work ;
68
    		schema:isPartOf <https://fr.wikipedia.org/> # frwiki sitelink
69
    SERVICE wikibase:label {
70
        bd:serviceParam wikibase:language "fr" .
71
   }
72
}',
73
            $isbn
74
        );
75
76
        return $this->sparqlRequest($sparql);
77
    }
78
79
    /**
80
     * Get WD item, sitelink, VIAF from search by ISNI (author)
81
     *
82
     * @param string $isni
83
     *
84
     * @return null
85
     * @throws Exception
86
     */
87
    public function searchByISNI(string $isni): ?array
88
    {
89
        if (!$this->ISNIvalide($isni)) {
90
            new Exception('Invalid format for ISNI');
91
        }
92
93
        $sparql = sprintf(
94
            'SELECT distinct ?item ?itemLabel ?articleAuthor ?isni ?viaf WHERE {
95
  ?item wdt:P213 "%s" .
96
  ?item wdt:P213 ?isni.
97
  ?item wdt:P214 ?viaf.
98
  ?articleAuthor schema:about ?item ;
99
		schema:isPartOf <https://fr.wikipedia.org/>
100
  SERVICE wikibase:label {
101
    bd:serviceParam wikibase:language "fr" .
102
   }
103
}',
104
            $isni
105
        );
106
107
        return $this->sparqlRequest($sparql);
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this->sparqlRequest($sparql) also could return the type array which is incompatible with the documented return type null.
Loading history...
108
    }
109
110
    /**
111
     * @param string $sparql
112
     *
113
     * @return array|null
114
     * @throws Exception
115
     */
116
    private function sparqlRequest(string $sparql): ?array
117
    {
118
        $url = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql?'.http_build_query(
119
                [
120
                    'format' => 'json',
121
                    'query' => $sparql, // rawurlencode()
122
                ]
123
            );
124
125
126
        // todo : catch + return null ?
127
        $response = $this->client->get($url);
128
129
        if (200 !== $response->getStatusCode()) {
130
            throw new Exception('response error '.$response->getStatusCode().' '.$response->getReasonPhrase());
131
        }
132
        $json = $response->getBody()->getContents();
133
134
        if (empty($json)) {
135
            return null;
136
        }
137
        $json = Normalizer::normalize($json);
138
139
        $array = json_decode($json, true) ?? null;
140
141
        // return first result only
142
        if ($array && isset($array['results']) && isset($array['results'])
143
            && isset($array['results']['bindings'])
144
            && count($array['results']['bindings']) === 1
145
        ) {
146
            return $array['results']['bindings'][0];
147
        }
148
149
        return null;
150
    }
151
152
    /**
153
     * todo move
154
     *
155
     * @param string $isni
156
     *
157
     * @return bool
158
     */
159
    private function ISNIvalide(string $isni): bool
160
    {
161
        return (!preg_match('#^0000(000[0-4])([0-9]{4})([0-9]{3}[0-9X])$#', $isni)) ? false : true;
162
    }
163
}
164