Completed
Push — master ( c72125...a4a431 )
by Florian
02:26
created

RecordsManager::matchToSearch()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 0
cts 17
cp 0
rs 8.8571
cc 6
eloc 11
nc 5
nop 3
crap 42
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
        $column = $search->getFilterColumn();
141
        foreach ($parsed as $index => $line) {
142
            if ($search->getStart() > $index) {
143
                continue;
144
            }
145
            if (empty($query) || $this->matchToSearch($query, $column, $line)) {
146
                $data[] = $line;
147
            }
148
            if ($search->getRows() == count($data)) {
149
                break;
150
            }
151
        }
152
153
        return $data;
154
    }
155
156
    /**
157
     * @param string $query
158
     * @param string $column
159
     * @param array $line
160
     * @return bool
161
     */
162
    private function matchToSearch($query, $column, $line)
163
    {
164
        $match = false;
165
        if (!empty($column)) {
166
            if (array_key_exists($column, $line) && $query == $line[$column]) {
167
                $match = true;
168
            }
169
        } else {
170
            foreach ($line as $value) {
171
                if (false !== strpos($value, $query)) {
172
                    $match = true;
173
                    break;
174
                }
175
            }
176
        }
177
178
        return $match;
179
    }
180
181
    /**
182
     * @param string $level
183
     * @param string $message
184
     * @param array $context
185
     */
186
    private function log($level, $message, $context = array())
187
    {
188
        if ($this->logger) {
189
            $this->logger->log($level, $message, $context);
190
        }
191
    }
192
193
    /**
194
     * Look locally (parsers)
195
     *
196
     * @param Search $search
197
     *
198
     * @return array|false
199
     */
200
    private function searchDistant(Search $search)
201
    {
202
        $data = array();
203
        $result = $this->client->get('search', $search->getParameters());
204
        if ($result) {
205
            $result = json_decode($result, true);
206
            foreach ($result['records'] as $record) {
207
                $data[] = $record['fields'];
208
            }
209
        }
210
211
        return $data;
212
    }
213
214
    /**
215
     * @param Download $download
216
     * @param bool $forceUpdate
217
     *
218
     * @return false|string
219
     */
220
    public function download(Download $download, $forceUpdate = false)
221
    {
222
        return $this->downloader->download(
223
            $download->getDataset(),
224
            $download->getFormat(),
225
            $download->getFilter(),
226
            $forceUpdate
227
        );
228
    }
229
230
    /**
231
     * @param Download $download
232
     *
233
     * @return null|string
234
     */
235
    public function getLocalDatasetContent(Download $download)
236
    {
237
        $content = null;
238
        $filepath = $this->finder->findDataset(
239
            $download->getDataset(),
240
            $download->getFormat(),
241
            $download->getFilter()
242
        );
243
        if (false !== $filepath) {
244
            $content = $this->finder->getContent($filepath);
245
        }
246
247
        return $content;
248
    }
249
}
250