Completed
Push — master ( 64470f...3a69fd )
by Florian
02:24
created

RecordsManager::search()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 0
cts 8
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Laposte\DatanovaBundle\Manager;
4
5
use Laposte\DatanovaBundle\Model\Download;
6
use Laposte\DatanovaBundle\Model\Search;
7
use Laposte\DatanovaBundle\Client\ClientInterface;
8
use Laposte\DatanovaBundle\Service\Downloader;
9
use Laposte\DatanovaBundle\Service\Finder;
10
use Laposte\DatanovaBundle\Parser\ParserInterface;
11
use Psr\Log\LoggerInterface;
12
13
class RecordsManager
14
{
15
    /**
16
     * @var ClientInterface
17
     */
18
    private $client;
19
20
    /**
21
     * @var Downloader
22
     */
23
    private $downloader;
24
25
    /**
26
     * @var Finder
27
     */
28
    private $finder;
29
30
    /**
31
     * @var ParserInterface[]
32
     */
33
    private $parsers;
34
35
    /** @var LoggerInterface */
36
    private $logger;
37
38
    /**
39
     * @param ClientInterface $client
40
     * @param Downloader $downloader
41
     * @param Finder $finder
42
     */
43
    public function __construct(ClientInterface $client, Downloader $downloader, Finder $finder)
44
    {
45
        $this->parsers = array();
46
        $this->client = $client;
47
        $this->downloader = $downloader;
48
        $this->finder = $finder;
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function setLogger(LoggerInterface $logger)
55
    {
56
        $this->logger = $logger;
57
    }
58
59
    /**
60
     * @param ParserInterface $parser
61
     */
62
    public function addParser(ParserInterface $parser)
63
    {
64
        $this->parsers[] = $parser;
65
    }
66
67
    /**
68
     * @param Search $search
69
     *
70
     * @return array|false
71
     */
72
    public function search(Search $search)
73
    {
74
        //look locally (parser)
75
        $data = $this->searchLocally($search);
76
        //query remote api
77
        if (false === $data) {
78
            $data = $this->searchDistant($search);
79
        }
80
81
        return $data;
82
    }
83
84
    /**
85
     * Look locally (parsers)
86
     *
87
     * @param Search $search
88
     *
89
     * @return array|false
90
     */
91
    private function searchLocally(Search $search)
92
    {
93
        $this->log('debug', sprintf('Search locally for %s dataset', $search->getDataset()), $search->getParameters());
94
        $result = false;
95
        foreach ($this->parsers as $parser) {
96
            $parsed = $parser->parse($search->getDataset());
97
            if ($parsed) {
98
                $result = $this->searchInArrayData($parsed, $search);
99
                $this->sortLocalData($result, $search);
100
                $this->log('debug', sprintf('Local dataset %s found', $search->getDataset()), $search->getParameters());
101
                break;
102
            }
103
        }
104
105
        return $result;
106
    }
107
108
    /**
109
     * @param array $parsed
110
     * @param Search $search
111
     *
112
     * @return array
113
     */
114
    private function sortLocalData(array $parsed, Search $search)
115
    {
116
        $sortKey = $search->getSort();
117
        if (!empty($sortKey)) {
118
            $sorter = function ($key) {
119
                return function ($elt1, $elt2) use ($key) {
120
                    return strnatcmp($elt1[$key], $elt2[$key]);
121
                };
122
            };
123
124
            usort($parsed, $sorter($sortKey));
125
        }
126
127
        return $parsed;
128
    }
129
130
    /**
131
     * @param array $parsed
132
     * @param Search $search
133
     *
134
     * @return array
135
     */
136
    private function searchInArrayData(array $parsed, Search $search)
137
    {
138
        $data = array();
139
        $query = $search->getFilterValue();
140
        $columnSearch = $search->getFilterColumn();
141
        foreach ($parsed as $index => $line) {
142
            if ($search->getStart() > $index) {
143
                continue;
144
            }
145
            if (empty($query)) {
146
                $data[] = $line;
147
            } else {
148
                if (!empty($columnSearch)) {
149
                    if ($query == $line[$columnSearch]) {
150
                        $data[] = $line;
151
                    }
152
                } else {
153
                    foreach ($line as $value) {
154
                        if (false !== strpos($value, $query)) {
155
                            $data[] = $line;
156
                            break;
157
                        }
158
                    }
159
                }
160
            }
161
            if ($search->getRows() == count($data)) {
162
                break;
163
            }
164
        }
165
166
        return $data;
167
    }
168
169
    /**
170
     * @param string $level
171
     * @param string $message
172
     * @param array $context
173
     */
174
    private function log($level, $message, $context = array())
175
    {
176
        if ($this->logger) {
177
            $this->logger->log($level, $message, $context);
178
        }
179
    }
180
181
    /**
182
     * Look locally (parsers)
183
     *
184
     * @param Search $search
185
     *
186
     * @return array|false
187
     */
188
    private function searchDistant(Search $search)
189
    {
190
        $data = array();
191
        $result = $this->client->get('search', $search->getParameters());
192
        if ($result) {
193
            $result = json_decode($result, true);
194
            foreach ($result['records'] as $record) {
195
                $data[] = $record['fields'];
196
            }
197
        }
198
199
        return $data;
200
    }
201
202
    /**
203
     * @param Download $download
204
     * @param bool $forceUpdate
205
     *
206
     * @return false|string
207
     */
208
    public function download(Download $download, $forceUpdate = false)
209
    {
210
        return $this->downloader->download(
211
            $download->getDataset(),
212
            $download->getFormat(),
213
            $download->getFilter(),
214
            $forceUpdate
215
        );
216
    }
217
218
    /**
219
     * @param Download $download
220
     *
221
     * @return null|string
222
     */
223
    public function getLocalDatasetContent(Download $download)
224
    {
225
        $content = null;
226
        $filepath = $this->finder->findDataset(
227
            $download->getDataset(),
228
            $download->getFormat(),
229
            $download->getFilter()
230
        );
231
        if (false !== $filepath) {
232
            $content = $this->finder->getContent($filepath);
233
        }
234
235
        return $content;
236
    }
237
}
238