Completed
Push — master ( dbcf6b...d53ab6 )
by Peter
44:13 queued 37:37
created

ImportRepository   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 297
Duplicated Lines 8.42 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 48.33%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 7
dl 25
loc 297
ccs 58
cts 120
cp 0.4833
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A startImport() 0 5 1
A startImportPart() 0 6 1
A finishImportPart() 0 9 2
A findScheduledByFeed() 0 10 1
A findOneLatestStarted() 0 11 1
A findOneLatestStartedByFeed() 13 13 1
A findCompletedByFeed() 12 12 1
A findByNumberOfParts() 0 9 1
A findStartedButUnfinished() 0 10 1
A save() 0 8 2
A savePart() 0 8 2
A createPart() 0 31 5
A finishImport() 0 27 3
A importHasUnfinishedParts() 0 14 4
A addResult() 0 21 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace TreeHouse\IoBundle\Entity;
4
5
use Doctrine\ORM\EntityRepository;
6
use TreeHouse\IoBundle\Exception\UnfinishedImportException;
7
use TreeHouse\IoBundle\Import\ImportResult;
8
9
class ImportRepository extends EntityRepository
10
{
11
    /**
12
     * Find scheduled imports by feed.
13
     *
14
     * @param Feed $feed
15
     *
16
     * @return Import[]
17
     */
18
    public function findScheduledByFeed(Feed $feed)
19
    {
20
        $builder = $this->createQueryBuilder('i')
21
            ->where('i.feed = :feed')
22
            ->andWhere('i.datetimeStarted IS NULL')
23
            ->setParameter('feed', $feed)
24
        ;
25
26
        return $builder->getQuery()->getResult();
27
    }
28
29
    /**
30
     * Find latest started import.
31
     *
32
     * @return Import
33
     */
34
    public function findOneLatestStarted()
35
    {
36
        $builder = $this->createQueryBuilder('i')
37
            ->andWhere('i.datetimeStarted IS NOT NULL')
38
            ->andWhere('SIZE(i.parts) > 0')
39
            ->orderBy('i.datetimeStarted', 'DESC')
40
            ->setMaxResults(1)
41
        ;
42
43
        return $builder->getQuery()->getOneOrNullResult();
44
    }
45
46
    /**
47
     * Find latest started import by feed.
48
     *
49
     * @param Feed $feed
50
     *
51
     * @return Import
52
     */
53 View Code Duplication
    public function findOneLatestStartedByFeed(Feed $feed)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
54
    {
55
        $builder = $this->createQueryBuilder('i')
56
            ->where('i.feed = :feed')
57
            ->andWhere('i.datetimeStarted IS NOT NULL')
58
            ->andWhere('SIZE(i.parts) > 0')
59
            ->orderBy('i.datetimeStarted', 'DESC')
60
            ->setMaxResults(1)
61
            ->setParameter('feed', $feed)
62
        ;
63
64
        return $builder->getQuery()->getOneOrNullResult();
65
    }
66
67
    /**
68
     * Find imports by feed, ordered by descending start date.
69
     *
70
     * @param Feed $feed
71
     *
72
     * @return Import[]
73
     */
74 View Code Duplication
    public function findCompletedByFeed(Feed $feed)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
75
    {
76
        $builder = $this->createQueryBuilder('i')
77
            ->where('i.feed = :feed')
78
            ->andWhere('i.datetimeStarted IS NOT NULL')
79
            ->andWhere('i.datetimeEnded IS NOT NULL')
80
            ->orderBy('i.datetimeStarted', 'DESC')
81
            ->setParameter('feed', $feed)
82
        ;
83
84
        return $builder->getQuery()->getResult();
85
    }
86
87
    /**
88
     * Find imports by number of parts.
89
     *
90
     * @param int    $number   The number of parts
91
     * @param string $operator The operator to use. Possible values are `=`, `<`, `>`, `<=`, and `>=`
92
     *
93
     * @return Import[]
94
     */
95
    public function findByNumberOfParts($number, $operator = '=')
96
    {
97
        $builder = $this->createQueryBuilder('i')
98
            ->andWhere(sprintf('SIZE(i.parts) %s :parts', $operator))
99
            ->setParameter('parts', $number)
100
        ;
101
102
        return $builder->getQuery()->getResult();
103
    }
104
105
    /**
106
     * Find imports that have started but not yet finished.
107
     *
108
     * @return Import[]
109
     */
110
    public function findStartedButUnfinished()
111
    {
112
        $builder = $this->createQueryBuilder('i')
113
            ->andWhere('i.datetimeStarted IS NOT NULL')
114
            ->andWhere('i.datetimeEnded IS NULL')
115
            ->orderBy('i.datetimeStarted', 'DESC')
116
        ;
117
118
        return $builder->getQuery()->getResult();
119
    }
120
121
    /**
122
     * @param Import $import
123
     * @param bool   $autoFlush
124
     */
125 4
    public function save(Import $import, $autoFlush = true)
126
    {
127 4
        $this->getEntityManager()->persist($import);
128
129 4
        if ($autoFlush) {
130 4
            $this->getEntityManager()->flush($import);
131
        }
132 4
    }
133
134
    /**
135
     * @param ImportPart $part
136
     * @param bool       $autoFlush
137
     */
138 4
    public function savePart(ImportPart $part, $autoFlush = true)
139
    {
140 4
        $this->getEntityManager()->persist($part);
141
142 4
        if ($autoFlush) {
143 4
            $this->getEntityManager()->flush($part);
144
        }
145 4
    }
146
147
    /**
148
     * @param Import    $import
149
     * @param array     $transport
150
     * @param \DateTime $scheduleDate
151
     * @param int       $position
152
     *
153
     * @return ImportPart
154
     */
155
    public function createPart(Import $import, array $transport, \DateTime $scheduleDate = null, $position = null)
156
    {
157
        if (is_null($scheduleDate)) {
158
            $scheduleDate = new \DateTime();
159
        }
160
161
        if (is_null($position)) {
162
            $position = 0;
163
164
            /** @var ImportPart $part */
165
            foreach ($import->getParts() as $part) {
166
                if ($part->getPosition() > $position) {
167
                    $position = $part->getPosition();
168
                }
169
            }
170
171
            ++$position;
172
        }
173
174
        $part = new ImportPart();
175
        $part->setPosition($position);
176
        $part->setTransportConfig($transport);
177
        $part->setDatetimeScheduled($scheduleDate);
178
        $part->setImport($import);
179
        $import->addPart($part);
180
181
        $this->getEntityManager()->persist($part);
182
        $this->getEntityManager()->flush($part);
183
184
        return $part;
185
    }
186
187
    /**
188
     * @param Import $import
189
     */
190 4
    public function startImport(Import $import)
191
    {
192 4
        $import->setDatetimeStarted(new \DateTime());
193 4
        $this->save($import);
194 4
    }
195
196
    /**
197
     * @param Import $import
198
     *
199
     * @throws \RuntimeException
200
     * @throws UnfinishedImportException
201
     *
202
     * @return bool
203
     */
204 4
    public function finishImport(Import $import)
205
    {
206 4
        if (!$import->isStarted()) {
207
            throw new \RuntimeException('Import has not yet started');
208
        }
209
210 4
        if ($this->importHasUnfinishedParts($import)) {
211
            throw UnfinishedImportException::create($import);
212
        }
213
214
        // set number of errored parts
215
        $erroredParts = $import
216 4
            ->getParts()
217 4
            ->filter(function (ImportPart $part) {
218 4
                return $part->getError();
219 4
            })
220 4
            ->count()
221
        ;
222
223 4
        $import->setErroredParts($erroredParts);
224
225
        // set end-date/time
226 4
        $import->setDatetimeEnded(new \DateTime());
227
228
        // flush the end result, and finish the log
229 4
        $this->save($import);
230 4
    }
231
232
    /**
233
     * @param ImportPart $part
234
     */
235 4
    public function startImportPart(ImportPart $part)
236
    {
237 4
        $part->setError(null);
238 4
        $part->setDatetimeStarted(new \DateTime());
239 4
        $this->savePart($part);
240 4
    }
241
242
    /**
243
     * @param ImportPart $part
244
     */
245 4
    public function finishImportPart(ImportPart $part)
246
    {
247 4
        if (!$part->isStarted()) {
248
            throw new \RuntimeException('Import part has not yet started');
249
        }
250
251 4
        $part->setDatetimeEnded(new \DateTime());
252 4
        $this->savePart($part);
253 4
    }
254
255
    /**
256
     * Checks if the import has any parts that are unfinished.
257
     *
258
     * @param Import $import  The import
259
     * @param bool   $refresh Whether to refresh the checked parts first. This
260
     *                        is useful when time has passed since the import
261
     *                        start, and you want to avoid race conditions
262
     *
263
     * @return bool
264
     */
265 4
    public function importHasUnfinishedParts(Import $import, $refresh = true)
266
    {
267 4
        foreach ($import->getParts() as $part) {
268 4
            if ($refresh === true) {
269 4
                $this->getEntityManager()->refresh($part);
270
            }
271
272 4
            if (!$part->isFinished()) {
273 4
                return true;
274
            }
275
        }
276
277 4
        return false;
278
    }
279
280
    /**
281
     * @param Import       $import
282
     * @param ImportResult $result
283
     */
284 4
    public function addResult(Import $import, ImportResult $result)
285
    {
286
        $query = $this
287 4
            ->createQueryBuilder('i')
288 4
            ->update()
289 4
            ->set('i.success', 'i.success + :success')
290 4
            ->set('i.failed', 'i.failed + :failed')
291 4
            ->set('i.skipped', 'i.skipped + :skipped')
292 4
            ->where('i.id = :id')
293 4
            ->getQuery()
294
        ;
295
296 4
        $query->execute([
297 4
            'id' => $import->getId(),
298 4
            'success' => $result->getSuccess(),
299 4
            'failed' => $result->getFailed(),
300 4
            'skipped' => $result->getSkipped(),
301
        ]);
302
303 4
        $this->getEntityManager()->refresh($import);
304 4
    }
305
}
306