Passed
Pull Request — development (#390)
by Mirko
09:05
created

FieldNoteService::getDate()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 6
nop 1
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
1
<?php
2
3
namespace AppBundle\Service;
4
5
use AppBundle\Entity\FieldNote;
6
use AppBundle\Exception\WrongDateFormatException;
7
use AppBundle\Exception\WrongFileFormatException;
8
use AppBundle\Service\Interfaces\FieldNoteServiceInterface;
9
use AppBundle\Service\Traits\ErrorTrait;
10
use AppBundle\Util\ArrayUtil;
11
use AppBundle\Util\DateUtil;
12
use DateTime;
13
use DateTimeZone;
14
use Doctrine\ORM\EntityManagerInterface;
15
use Symfony\Component\Translation\TranslatorInterface;
16
17
class FieldNoteService implements FieldNoteServiceInterface
18
{
19
    use ErrorTrait;
20
21
    /**
22
     * @var \Doctrine\ORM\EntityManagerInterface
23
     */
24
    protected $entityManager;
25
26
    /**
27
     * @var \Symfony\Component\Translation\TranslatorInterface
28
     */
29
    protected $translator;
30
31
    /**
32
     * FieldNoteService constructor.
33
     *
34
     * @param \Doctrine\ORM\EntityManagerInterface $entityManager
35
     * @param \Symfony\Component\Translation\TranslatorInterface $translator
36
     */
37
    public function __construct(EntityManagerInterface $entityManager, TranslatorInterface $translator)
38
    {
39
        $this->entityManager = $entityManager;
40
        $this->translator = $translator;
41
    }
42
43
    /**
44
     * @param string $fileName
45
     * @param int $userId
46
     * @param null|\DateTime $ignoreBeforeDate
47
     *
48
     * @return bool
49
     * @throws \AppBundle\Exception\WrongDateFormatException
50
     * @throws \AppBundle\Exception\WrongFileFormatException
51
     */
52
    public function importFromFile($fileName, $userId, DateTime $ignoreBeforeDate = null)
53
    {
54
        $content = file_get_contents($fileName);
55
        $content = str_replace('\xFF\xFE', '', $content); // remove UTF16(LE) BOM
56
        $content = mb_convert_encoding($content, 'UTF-8', 'UCS-2LE');
57
        $rows = ArrayUtil::trimExplode("\n", $content);
58
        foreach ($rows as $row) {
59
            $data = str_getcsv($row, ',', '"', '""');
60
            if (count($data) !== 4) {
61
                throw new WrongFileFormatException(
62
                    $this->translator->trans('field_notes.error.wrong_file_format')
63
                );
64
            }
65
66
            $date = $this->getDate($data[1]);
67
68
            if ($ignoreBeforeDate !== null && $date < $ignoreBeforeDate) {
69
                continue;
70
            }
71
72
            if (!array_key_exists($data[2], self::LOG_TYPE)) {
73
                $this->addError(
74
                    /** @Desc("Log type ""%type%"" is not implemented.") */
75
                    $this->translator->trans('field_notes.error.log_type_not_implemented', ['%type%' => $data[2]])
76
                );
77
                continue;
78
            }
79
            $type = self::LOG_TYPE[$data[2]];
80
81
            if (strtoupper(substr($data[0], 0, 2)) == 'GC') {
82
                $query = $this->entityManager->createQueryBuilder()
83
                    ->select('g')
84
                    ->from('AppBundle:Geocache', 'g')
85
                    ->where("IFELSE(g.wpGcMaintained = '', g.wpGc, g.wpGcMaintained) = :code")
86
                    ->setParameter('code', $data[0])
87
                    ->getQuery();
88
                $geocache = $query->getOneOrNullResult();
89
            } else {
90
                $geocache = $this->entityManager->getRepository('AppBundle:Geocache')->findOneBy(['wpOc' => $data[0]]);
91
            }
92
            if (!$geocache) {
93
                $this->addError(
94
                    /** @Desc("Geocache ""%code%"" not found.") */
95
                    $this->translator->trans('field_notes.error.geocache_not_found', ['%code%' => $data[0]])
96
                );
97
                continue;
98
            }
99
100
            $fieldNote = new FieldNote();
101
            $fieldNote->setUser($this->entityManager->getReference('AppBundle:User', $userId));
102
            $fieldNote->setGeocache($geocache);
103
            $fieldNote->setDate($date);
104
            $fieldNote->setType($type);
105
            $fieldNote->setText($data[3]);
106
            $this->entityManager->persist($fieldNote);
107
        }
108
        $this->entityManager->flush();
109
110
        if ($this->hasErrors()) {
111
            return false;
112
        }
113
114
        return true;
115
    }
116
117
    /**
118
     * @param int $userId
119
     *
120
     * @return \DateTime|null
121
     */
122
    public function getLatestFieldNoteOrLogDate($userId)
123
    {
124
        $maxFieldNote = $this->getMaxDateFromEntityByUserId('AppBundle:FieldNote', $userId);
125
        $maxLog = $this->getMaxDateFromEntityByUserId('AppBundle:GeocacheLog', $userId);
126
127
        return max($maxFieldNote, $maxLog);
128
    }
129
130
    /**
131
     * @param string $entityName
132
     * @param int $userId
133
     *
134
     * @return \DateTime|null
135
     */
136
    protected function getMaxDateFromEntityByUserId($entityName, $userId)
137
    {
138
        $max = null;
139
        $query = $this->entityManager->createQueryBuilder();
140
        $query
141
            ->select('MAX(e.date) AS max_date')
142
            ->from($entityName, 'e')
143
            ->where('e.user = :user_id')
144
                ->setParameter('user_id', $userId)
145
            ->setMaxResults(1);
146
        $result = $query->getQuery()->getResult();
147
        if ($result && isset($result[0]['max_date'])) {
148
            $max = DateUtil::dateTimeFromMySqlFormat($result[0]['max_date']);
149
        }
150
151
        return $max;
152
    }
153
154
    /**
155
     * @param string $dateString
156
     *
157
     * @throws \AppBundle\Exception\WrongDateFormatException
158
     * @return \DateTime
159
     */
160
    protected function getDate($dateString)
161
    {
162
        $format = null;
163
        if (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}Z/', $dateString)) {
164
            $format = self::FIELD_NOTE_DATETIME_FORMAT_SHORT;
165
        } elseif (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z/', $dateString)) {
166
            $format = self::FIELD_NOTE_DATETIME_FORMAT;
167
        }
168
169
        if ($format === null) {
170
            throw new WrongDateFormatException(
171
                $this->translator->trans('field_notes.error.wrong_date_format')
172
            );
173
        }
174
175
        $date = DateTime::createFromFormat(
176
            $format,
177
            $dateString,
178
            new DateTimeZone('UTC')
179
        );
180
181
        return $date;
182
    }
183
}
184