Passed
Push — master ( 13a60b...ea0cdf )
by Dispositif
02:35
created

WikidataAdapter::sparqlRequest()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 16
nc 4
nop 1
dl 0
loc 32
rs 8.4444
c 2
b 0
f 0
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]);
31
        } else {
32
            $this->client = $client;
33
        }
34
    }
35
36
    public function findArticleByISBN13(string $isbn): ?array
37
    {
38
        // strip ISBN formating
39
        $isbn = preg_replace('#[^0-9X]#', '', $isbn);
40
        if(strlen($isbn) !== 13) {
41
            throw new \DomainException('ISBN-13 format error');
42
        }
43
44
        $sparql = sprintf(
45
            'select ?work ?workLabel ?article ?edition ?isbn
46
WHERE {
47
    ?work wdt:P31 wd:Q47461344 ; # instance of written work
48
        wdt:P747 ?edition . # has edition (P747)
49
    ?edition wdt:P212 $isbn . # ISBN-13 (P212)
50
    FILTER(REGEX(REPLACE(?isbn,"-",""), "%s", "i")). # strip ISBN formating
51
    ?article schema:about ?work ;
52
    		schema:isPartOf <https://fr.wikipedia.org/> # frwiki sitelink
53
    SERVICE wikibase:label {
54
        bd:serviceParam wikibase:language "fr" .
55
   }
56
}',
57
            $isbn
58
        );
59
60
        return $this->sparqlRequest($sparql);
61
    }
62
63
    /**
64
     * Get WD item, sitelink, VIAF from search by ISNI (author)
65
     *
66
     * @param string $isni
67
     *
68
     * @return null
69
     * @throws Exception
70
     */
71
    public function searchByISNI(string $isni): ?array
72
    {
73
        if (!$this->ISNIvalide($isni)) {
74
            new Exception('Invalid format for ISNI');
75
        }
76
77
        $sparql = sprintf(
78
            'SELECT distinct ?item ?itemLabel ?article ?isni ?viaf WHERE {
79
  ?item wdt:P213 "%s" .
80
  ?item wdt:P213 ?isni.
81
  ?item wdt:P214 ?viaf.
82
  ?article schema:about ?item ;
83
		schema:isPartOf <https://fr.wikipedia.org/>
84
  SERVICE wikibase:label {
85
    bd:serviceParam wikibase:language "fr" .
86
   }
87
}',
88
            $isni
89
        );
90
91
        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...
92
    }
93
94
    /**
95
     * @param string $sparql
96
     *
97
     * @return array|null
98
     * @throws Exception
99
     */
100
    private function sparqlRequest(string $sparql): ?array
101
    {
102
        $url = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql?'.http_build_query(
103
                [
104
                    'format' => 'json',
105
                    'query' => urlencode($sparql),
106
                ]
107
            );
108
109
        $response = $this->client->get($url);
110
        // todo : catch + return null ?
111
        if (200 !== $response->getStatusCode()) {
112
            throw new Exception('response error '.$response->getStatusCode());
113
        }
114
        $json = $response->getBody()->getContents();
115
116
        if (empty($json)) {
117
            return null;
118
        }
119
        $json = Normalizer::normalize($json);
120
121
        $array = json_decode($json, true) ?? null;
122
123
        // return first result only
124
        if ($array && isset($array['results']) && isset($array['results'])
125
            && isset($array['results']['bindings'])
126
            && count($array['results']['bindings']) === 1
127
        ) {
128
            return $array['results']['bindings'][0];
129
        }
130
131
        return null;
132
    }
133
134
    /**
135
     * todo move
136
     *
137
     * @param string $isni
138
     *
139
     * @return bool
140
     */
141
    private function ISNIvalide(string $isni): bool
142
    {
143
        return (!preg_match('#^0000(000[0-4])([0-9]{4})([0-9]{3}[0-9X])$#', $isni)) ? false : true;
144
    }
145
}
146