Issues (106)

src/Infrastructure/WikidataAdapter.php (1 issue)

Labels
Severity
1
<?php
2
/*
3
 * This file is part of dispositif/wikibot application (@github)
4
 * 2019-2023 © Philippe M./Irønie  <[email protected]>
5
 * For the full copyright and MIT license information, view the license file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Infrastructure;
11
12
use App\Domain\InfrastructurePorts\WikidataAdapterInterface;
13
use DomainException;
14
use Exception;
15
use GuzzleHttp\Client;
16
use Normalizer;
17
18
/**
19
 * dirty scratch WikiData read requests
20
 * Class WikidataAdapter
21
 *
22
 * @package App\Infrastructure
23
 */
24
class WikidataAdapter implements WikidataAdapterInterface
25
{
26
    private ?Client $client = null;
27 2
28
    public function __construct(?Client $client = null)
29 2
    {
30
        if (!$client instanceof Client) {
31
            // lazy dependency factory :)
32
            $this->client = new Client(['timeout' => 60, 'headers' => ['User-Agent' => getenv('USER_AGENT')]]);
33 2
        } else {
34
            $this->client = $client;
35 2
        }
36
    }
37
38
    public function getDataByInfos(?array $infos)
39
    {
40
        $res = [];
41
        if (isset($infos['ISNIAuteur1'])) {
42
            $res = $this->searchByISNI($infos['ISNIAuteur1']);
43
        }
44
        if (isset($infos['isbn'])) {
45
            if(!empty($res)) {
46
                sleep(2);
47
            }
48
            $res = array_merge($res ?? [], $this->findArticleByISBN13($infos['isbn']));
49
        }
50
51
        return $res ?? [];
52
    }
53 1
54
    public function findArticleByISBN13(string $isbn): ?array
55
    {
56 1
        // strip ISBN formating
57 1
        $isbn = preg_replace('#[^0-9X]#', '', $isbn);
58
        if (strlen($isbn) !== 13) {
59
            throw new DomainException('ISBN-13 format error');
60
        }
61 1
62 1
        $sparql = sprintf(
63
            'select ?work ?workLabel ?articleBook ?edition ?isbn
64
WHERE {
65
    ?work wdt:P31 wd:Q47461344 ; # instance of written work
66
        wdt:P747 ?edition . # has edition (P747)
67
    ?edition wdt:P212 $isbn . # ISBN-13 (P212)
68
    FILTER(REGEX(REPLACE(?isbn,"-",""), "%s", "i")). # strip ISBN formating
69
    ?articleBook schema:about ?work ;
70
    		schema:isPartOf <https://fr.wikipedia.org/> # frwiki sitelink
71
    SERVICE wikibase:label {
72
        bd:serviceParam wikibase:language "fr" .
73
   }
74 1
}',
75
            $isbn
76
        );
77 1
78
        return $this->sparqlRequest($sparql);
79
    }
80
81
    /**
82
     * Get WD item, sitelink, VIAF from search by ISNI (author)
83
     * @throws Exception
84
     */
85
    public function searchByISNI(string $isni): ?array
86
    {
87
        if (!$this->ISNIvalide($isni)) {
88 1
            new Exception('Invalid format for ISNI');
89
        }
90 1
91 1
        $sparql = sprintf(
92
            'SELECT distinct ?item ?itemLabel ?articleAuthor ?isni ?viaf WHERE {
93
  ?item wdt:P213 "%s" .
94 1
  ?item wdt:P213 ?isni.
95 1
  ?item wdt:P214 ?viaf.
96
  ?articleAuthor schema:about ?item ;
97
		schema:isPartOf <https://fr.wikipedia.org/>
98
  SERVICE wikibase:label {
99
    bd:serviceParam wikibase:language "fr" .
100
   }
101
}',
102
            $isni
103
        );
104
105 1
        return $this->sparqlRequest($sparql);
106
    }
107
108 1
    /**
109
     * @throws Exception
110
     */
111
    private function sparqlRequest(string $sparql): ?array
112
    {
113
        $url = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql?'.http_build_query(
114
                [
115
                    'format' => 'json',
116
                    'query' => $sparql, // rawurlencode()
117 2
                ]
118
            );
119 2
120
121 2
        // todo : catch + return null ?
122 2
        $response = $this->client->get($url);
0 ignored issues
show
The method get() does not exist on null. ( Ignorable by Annotation )

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

122
        /** @scrutinizer ignore-call */ 
123
        $response = $this->client->get($url);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
123
124
        if (200 !== $response->getStatusCode()) {
125
            throw new Exception('response error '.$response->getStatusCode().' '.$response->getReasonPhrase());
126
        }
127
        $json = $response->getBody()->getContents();
128 2
129
        if (empty($json)) {
130 2
            return null;
131
        }
132
        $json = Normalizer::normalize($json);
133 2
134
        $array = json_decode($json, true, 512, JSON_THROW_ON_ERROR) ?? null;
135 2
136
        // return first result only
137
        if ($array && isset($array['results']) && isset($array['results'])
138 2
            && isset($array['results']['bindings'])
139
            && (is_countable($array['results']['bindings']) ? count($array['results']['bindings']) : 0) === 1
140 2
        ) {
141
            return $array['results']['bindings'][0];
142
        }
143 2
144 2
        return null;
145 2
    }
146
147 2
    /**
148
     * todo move
149
     *
150
     *
151
     */
152
    private function ISNIvalide(string $isni): bool
153
    {
154
        return (bool) preg_match('#^0000(000[0-4])(\d{4})(\d{3}[0-9X])$#', $isni);
155
    }
156
}
157