Fetcher::fetchResources()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 13
c 0
b 0
f 0
rs 9.9666
cc 1
nc 1
nop 0
1
<?php
2
3
namespace PubPeerFoundation\PublicationDataExtractor;
4
5
use Generator;
6
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
7
use GuzzleHttp\Promise\EachPromise;
8
use Psr\Http\Message\ResponseInterface;
9
use PubPeerFoundation\PublicationDataExtractor\Identifiers\Identifier;
10
use PubPeerFoundation\PublicationDataExtractor\Resources\Resource;
11
use Tightenco\Collect\Support\Arr;
12
13
class Fetcher
14
{
15
    /**
16
     * @var Identifier
17
     */
18
    protected $identifier;
19
20
    /**
21
     * @var \GuzzleHttp\Client
22
     */
23
    protected $client;
24
25
    /**
26
     * @var array
27
     */
28
    protected $apiData = [];
29
30
    /**
31
     * @var array
32
     */
33
    protected $resources = [];
34
35
    /**
36
     * @var array
37
     */
38
    protected $resourcesToFetch = [];
39
40
    /**
41
     * @var array
42
     */
43
    protected $errors = [];
44
45
    /**
46
     * The Output object.
47
     *
48
     * @var Output
49
     */
50
    protected $output;
51
52
    /**
53
     * ApiDataFetcher constructor.
54
     *
55
     * @param  Identifier  $identifier
56
     */
57
    public function __construct(Identifier $identifier)
58
    {
59
        $this->identifier = $identifier;
60
        $this->resourcesToFetch = $identifier->getRelatedResources();
61
        $this->output = new Output();
62
        $this->client = GuzzleFactory::make(['timeout' => 2], 100, null, 0);
63
    }
64
65
    /**
66
     * Fetch Data and return Output.
67
     *
68
     * @return Output
69
     */
70
    public function fetch(): Output
71
    {
72
        $this->fetchResources();
73
74
        $this->fetchComplementaryResources();
75
76
        $this->output->resetLists();
77
78
        return $this->output;
79
    }
80
81
    /**
82
     * Fetch resources.
83
     */
84
    protected function fetchResources(): void
85
    {
86
        (new EachPromise($this->getPromises(), [
87
            'concurrency' => 5,
88
            'fulfilled' => function (ResponseInterface $response, $index) {
89
                $this->apiData[] = $this->getResourceAtIndex($index)
90
                    ->getDataFrom((string) $response->getBody());
91
            },
92
            'rejected' => function (\Exception $exception, $index) {
93
                $resourceName = get_class_name($this->getResourceAtIndex($index));
94
                $this->errors[$resourceName] = $exception->getCode();
95
            },
96
        ]))->promise()->wait();
97
    }
98
99
    /**
100
     * Get list of API calls promises.
101
     *
102
     * @return Generator
103
     */
104
    protected function getPromises(): Generator
105
    {
106
        foreach ($this->resourcesToFetch as $resourceClass) {
107
            $resource = $this->instantiateResource($resourceClass);
108
109
            $promise = $this->client->requestAsync(
110
                'GET',
111
                $resource->getApiUrl(),
112
                $resource->getRequestOptions()
113
            );
114
115
            yield $promise;
116
        }
117
    }
118
119
    /**
120
     * Get errors as array.
121
     *
122
     * @return array
123
     */
124
    public function getErrors(): array
125
    {
126
        return $this->errors;
127
    }
128
129
    /**
130
     * Get resource instance from resources array.
131
     *
132
     * @param  int  $index
133
     * @return resource
134
     */
135
    protected function getResourceAtIndex(int $index): Resource
136
    {
137
        return $this->resources[$index];
138
    }
139
140
    /**
141
     * Create and store an instance of the Resource class.
142
     *
143
     * @param  string  $resourceClass
144
     * @return resource
145
     */
146
    protected function instantiateResource($resourceClass): Resource
147
    {
148
        return $this->resources[] = new $resourceClass($this->identifier, $this->output);
149
    }
150
151
    /**
152
     * Fetch again with new related Identifiers.
153
     */
154
    protected function fetchComplementaryResources()
155
    {
156
        $flatIdentifiers = Arr::flatten(Arr::pluck($this->apiData, 'identifiers'));
157
158
        foreach ($this->identifier->getComplementaryResources() as $key => $value) {
159
            if (false !== $valueKey = array_search($key, $flatIdentifiers)) {
160
                try {
161
                    $this->identifier = (new IdentifierResolver($flatIdentifiers[$valueKey - 1]))->handle();
162
163
                    $this->resourcesToFetch = [$value];
164
                    $this->resources = [];
165
166
                    $this->fetchResources();
167
                } catch (Exceptions\UnknownIdentifierException $e) {
168
                    continue;
169
                }
170
            }
171
        }
172
    }
173
}
174