Completed
Pull Request — development (#673)
by Nick
12:54 queued 04:44
created

FieldNoteService::importFromFile()   C

Complexity

Conditions 9
Paths 15

Size

Total Lines 78
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 52
nc 15
nop 3
dl 0
loc 78
rs 5.7191
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Oc\FieldNotes;
4
5
use Oc\FieldNotes\Entity\FieldNote;
0 ignored issues
show
introduced by
Use classes must be in alphabetical order.
Loading history...
6
use Oc\FieldNotes\Exception\WrongDateFormatException;
7
use Oc\FieldNotes\Exception\WrongFileFormatException;
8
use Oc\GeoCache\Entity\Geocache;
9
use Oc\GeoCache\Entity\GeocacheLog;
10
use Oc\User\Entity\User;
11
use Oc\Util\Error\ErrorTrait;
12
use Oc\Util\ArrayUtil;
13
use Oc\Util\DateUtil;
14
use DateTime;
15
use DateTimeZone;
16
use Doctrine\ORM\EntityManagerInterface;
17
use Symfony\Component\Translation\TranslatorInterface;
18
19
class FieldNoteService implements FieldNoteServiceInterface
20
{
21
    use ErrorTrait;
22
23
    /**
24
     * @var EntityManagerInterface
0 ignored issues
show
introduced by
EntityManagerInterface => \Doctrine\ORM\EntityManagerInterface
Loading history...
25
     */
26
    protected $entityManager;
27
28
    /**
29
     * @var TranslatorInterface
0 ignored issues
show
introduced by
TranslatorInterface => \Symfony\Component\Translation\TranslatorInterface
Loading history...
30
     */
31
    protected $translator;
32
33
    /**
34
     * FieldNoteService constructor.
35
     *
36
     * @param EntityManagerInterface $entityManager
0 ignored issues
show
introduced by
EntityManagerInterface => \Doctrine\ORM\EntityManagerInterface
Loading history...
37
     * @param TranslatorInterface $translator
0 ignored issues
show
introduced by
TranslatorInterface => \Symfony\Component\Translation\TranslatorInterface
Loading history...
38
     */
39
    public function __construct(EntityManagerInterface $entityManager, TranslatorInterface $translator)
40
    {
41
        $this->entityManager = $entityManager;
42
        $this->translator = $translator;
43
    }
44
45
    /**
46
     * @param string $fileName
47
     * @param int $userId
48
     * @param null|DateTime $ignoreBeforeDate
0 ignored issues
show
introduced by
DateTime => \DateTime
Loading history...
49
     *
50
     * @return bool
51
     * @throws WrongDateFormatException
0 ignored issues
show
introduced by
WrongDateFormatException => \Oc\FieldNotes\Exception\WrongDateFormatException
Loading history...
52
     * @throws WrongFileFormatException
0 ignored issues
show
introduced by
WrongFileFormatException => \Oc\FieldNotes\Exception\WrongFileFormatException
Loading history...
53
     */
54
    public function importFromFile($fileName, $userId, DateTime $ignoreBeforeDate = null)
55
    {
56
        $content = file_get_contents($fileName);
57
        $content = str_replace("\xFF\xFE", '', $content); // remove UTF16(LE) BOM
58
        $content = mb_convert_encoding($content, 'UTF-8', 'UCS-2LE');
59
        // unify line feeds
60
        $content = str_replace("\r\n", "\n", $content);
61
        $rows = ArrayUtil::explodeTrim("\"\n", $content);
62
        $notFoundGeocacheCodes = [];
63
        foreach ($rows as $row) {
64
            $data = str_getcsv($row, ',', '"', '""');
65
            if (count($data) !== 4) {
66
                throw new WrongFileFormatException(
67
                    $this->translator->trans('field_notes.error.wrong_file_format')
68
                );
69
            }
70
71
            $date = $this->getDate($data[1]);
72
73
            if ($ignoreBeforeDate !== null && $date < $ignoreBeforeDate) {
74
                continue;
75
            }
76
77
            if (!array_key_exists($data[2], self::LOG_TYPE)) {
78
                $this->addError(
79
                    /** @Desc("Log type ""%type%"" is not implemented.") */
80
                    $this->translator->trans('field_notes.error.log_type_not_implemented', ['%type%' => $data[2]])
81
                );
82
                continue;
83
            }
84
            $type = self::LOG_TYPE[$data[2]];
85
86
            if (0 === stripos($data[0], 'GC')) {
87
                $query = $this->entityManager->createQueryBuilder()
88
                    ->select('g')
89
                    ->from(Geocache::class, 'g')
90
                    ->where("IFELSE(g.wpGcMaintained = '', g.wpGc, g.wpGcMaintained) = :code")
91
                    ->setParameter('code', $data[0])
92
                    ->getQuery();
93
                $geocache = $query->getOneOrNullResult();
94
            } else {
95
                $geocache = $this->entityManager->getRepository(Geocache::class)->findOneBy(['wpOc' => $data[0]]);
96
            }
97
            if (!$geocache) {
98
                $notFoundGeocacheCodes[] = $data[0];
99
                $this->addError(
100
                    /** @Desc("Geocache ""%code%"" not found.") */
101
                    $this->translator->transChoice(
102
                        'field_notes.error.geocache_not_found',
103
                        count($notFoundGeocacheCodes),
104
                        [
105
                            '%code%' => ArrayUtil::humanImplode(
106
                                $notFoundGeocacheCodes,
107
                                $this->translator->trans('array_util.human_lang_implode.and')
108
                            ),
109
                        ]
110
                    ),
111
                    'geocache-not-found'
112
                );
113
                continue;
114
            }
115
116
            $fieldNote = new FieldNote();
117
            $fieldNote->setUser($this->entityManager->getReference(User::class, $userId));
118
            $fieldNote->setGeocache($geocache);
119
            $fieldNote->setDate($date);
120
            $fieldNote->setType($type);
121
            $fieldNote->setText($data[3]);
122
            $this->entityManager->persist($fieldNote);
123
        }
124
        $this->entityManager->flush();
125
126
        if ($this->hasErrors()) {
127
            return false;
128
        }
129
130
        return true;
131
    }
132
133
    /**
134
     * @param int $userId
135
     *
136
     * @return DateTime|null
0 ignored issues
show
introduced by
DateTime => \DateTime
Loading history...
137
     */
138
    public function getLatestFieldNoteOrLogDate($userId)
139
    {
140
        $maxFieldNote = $this->getMaxDateFromEntityByUserId(FieldNote::class, $userId);
141
        $maxLog = $this->getMaxDateFromEntityByUserId(GeocacheLog::class, $userId);
142
143
        return max($maxFieldNote, $maxLog);
144
    }
145
146
    /**
147
     * @param string $entityName
148
     * @param int $userId
149
     * @return DateTime|null
0 ignored issues
show
introduced by
DateTime => \DateTime
Loading history...
150
     */
151
    protected function getMaxDateFromEntityByUserId($entityName, $userId)
152
    {
153
        $max = null;
154
        $query = $this->entityManager->createQueryBuilder();
155
        $query
156
            ->select('MAX(e.date) AS max_date')
157
            ->from($entityName, 'e')
158
            ->where('e.user = :user_id')
159
            ->setParameter('user_id', $userId)
160
            ->setMaxResults(1);
161
        $result = $query->getQuery()->getResult();
162
        if ($result && isset($result[0]['max_date'])) {
163
            $max = DateUtil::dateTimeFromMySqlFormat($result[0]['max_date']);
164
        }
165
166
        return $max;
167
    }
168
169
    /**
170
     * @param string $dateString
171
     * @throws WrongDateFormatException
0 ignored issues
show
introduced by
WrongDateFormatException => \Oc\FieldNotes\Exception\WrongDateFormatException
Loading history...
172
     * @return DateTime
0 ignored issues
show
introduced by
DateTime => \DateTime
Loading history...
173
     */
174
    protected function getDate($dateString)
175
    {
176
        $format = null;
177
        if (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}Z/', $dateString)) {
178
            $format = self::FIELD_NOTE_DATETIME_FORMAT_SHORT;
179
        } elseif (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z/', $dateString)) {
180
            $format = self::FIELD_NOTE_DATETIME_FORMAT;
181
        }
182
183
        if ($format === null) {
184
            throw new WrongDateFormatException(
185
                $this->translator->trans('field_notes.error.wrong_date_format')
186
            );
187
        }
188
189
        $date = DateTime::createFromFormat(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression \DateTime::createFromFor... \DateTimeZone('UTC')); of type DateTime|false adds false to the return on line 196 which is incompatible with the return type documented by Oc\FieldNotes\FieldNoteService::getDate of type DateTime. It seems like you forgot to handle an error condition.
Loading history...
190
            $format,
191
            $dateString,
192
            new DateTimeZone('UTC')
193
        );
194
        $date->setTimezone(new DateTimeZone(date_default_timezone_get()));
195
196
        return $date;
197
    }
198
}
199