Lines 97.26% 71 / 73
Methods 60.00% 3 / 5
Classes 0.00% 0 / 1
Covered by tests of size
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 import 97.67% 42 / 43 0.00% 0 / 1 4
 parseCSV 100.00% 4 / 4 100.00% 1 / 1 2
 isCSVFile 100.00% 3 / 3 100.00% 1 / 1 1
 validateCSV 95.45% 21 / 22 0.00% 0 / 1 13
37readonly class Import
38{
39    public function __construct(
40        private Configuration $configuration,
41    ) {
42    }
43
44    /**
45     * Imports a record with the given record data.
46     *
47     * @param array $record Record data
48     * @throws Exception
49     */
50    public function import(array $record): bool
51    {
52        $user = CurrentUser::getCurrentUser($this->configuration);
53        [$currentUser, $currentGroups] = CurrentUser::getCurrentUserGroupId($user);
54
55        $categoryId = Filter::filterVar($record[0], FILTER_VALIDATE_INT);
56        $question = Filter::filterVar($record[1], FILTER_SANITIZE_SPECIAL_CHARS, '');
57        $answer = Filter::filterVar($record[2], FILTER_SANITIZE_SPECIAL_CHARS, '');
58        $keywords = Filter::filterVar($record[3], FILTER_SANITIZE_SPECIAL_CHARS, '');
59        $languageCode = Filter::filterVar($record[4], FILTER_SANITIZE_SPECIAL_CHARS, '');
60        $author = Filter::filterVar($record[5], FILTER_SANITIZE_SPECIAL_CHARS, '');
61        $email = Filter::filterEmail($record[6]);
62        $email = is_string($email) ? $email : '';
63        $isActive = Filter::filterVar($record[7], FILTER_VALIDATE_BOOLEAN);
64        $isSticky = Filter::filterVar($record[8], FILTER_VALIDATE_BOOLEAN);
65
66        $faq = new Faq($this->configuration);
67        $faq->setUser($currentUser);
68        $faq->setGroups($currentGroups);
69
70        $category = new Category($this->configuration, $currentGroups, true);
71        $category->setUser($currentUser);
72        $category->setGroups($currentGroups);
73        $category->setLanguage($languageCode);
74
75        if ($faq->hasTitleAHash($question)) {
76            throw new Exception('It is not allowed, that the question title ' . $question . ' contains a hash.');
77        }
78
79        $categories = [(int) $categoryId];
80        $isActive = !is_null($isActive);
81        $isSticky = !is_null($isSticky);
82
83        $faqEntity = new FaqEntity();
84        $faqEntity
85            ->setLanguage($languageCode)
86            ->setQuestion($question)
87            ->setAnswer($answer)
88            ->setKeywords($keywords)
89            ->setAuthor($author)
90            ->setEmail($email)
91            ->setActive($isActive)
92            ->setSticky($isSticky)
93            ->setComment(false)
94            ->setNotes('');
95
96        $faqEntity = $faq->create($faqEntity);
97
98        $faqId = $faqEntity->getId();
99        if ($faqId === null) {
100            return false;
101        }
102
103        $faqMetaData = new MetaData($this->configuration);
104        $faqMetaData->setFaqId($faqId)->setFaqLanguage($languageCode)->setCategories($categories)->save();
105
106        return true;
107    }
108
109    /**
110     * Returns the data from a csv file.
111     *
112     * @param resource $handle
113     *
114     * @return array<int<0, max>, array> $csvData
115     */
116    public function parseCSV($handle): array
117    {
118        $csvData = [];
119        while (($record = fgetcsv(stream: $handle, separator: ',', enclosure: '"', escape: '')) !== false) {
120            $csvData[] = $record;
121        }
122
123        return $csvData;
124    }
125
126    /**
127     * Returns true if given Symfony FileBag-object is a csv file. Returns false if not.
128     *
129     *
130     */
131    public function isCSVFile(UploadedFile $uploadedFile): bool
132    {
133        $allowedExtensions = ['csv'];
134        $fileExtension = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_EXTENSION);
135
136        return in_array(strtolower($fileExtension), $allowedExtensions, strict: true);
137    }
138
139    /**
140     * Checks if the given csv-Data matches all requirements.
141     *
142     * @param array<array-key, array<array-key, mixed>> $csvData
143     */
144    public function validateCSV(array $csvData): bool
145    {
146        foreach ($csvData as $row) {
147            if (count($row) !== 9) {
148                return false;
149            }
150
151            $requiredColumns = [0, 1, 2, 4, 5, 6, 7, 8];
152            foreach ($requiredColumns as $requiredColumn) {
153                if (!array_key_exists($requiredColumn, $row)) {
154                    return false;
155                }
156
157                $value = $row[$requiredColumn];
158                if (
159                    $value === null
160                    || $value === ''
161                    || $value === '0'
162                    || $value === 0
163                    || $value === false
164                    || $value === []
165                ) {
166                    return false;
167                }
168            }
169
170            $activatedColumn = 7;
171            $importantFAQColumn = 8;
172            $validBooleanValues = ['true', 'false'];
173
174            if (
175                !in_array(strtolower((string) $row[$activatedColumn]), $validBooleanValues, strict: true)
176                || !in_array(strtolower((string) $row[$importantFAQColumn]), $validBooleanValues, strict: true)
177            ) {
178                return false;
179            }
180        }
181
182        return true;
183    }
184}