Total Complexity | 65 |
Total Lines | 376 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like SectionExport often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SectionExport, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class SectionExport |
||
28 | { |
||
29 | /** |
||
30 | * @var object |
||
31 | */ |
||
32 | private $course; |
||
33 | |||
34 | /** |
||
35 | * @param object $course the course object to be exported |
||
36 | */ |
||
37 | public function __construct(object $course) |
||
38 | { |
||
39 | $this->course = $course; |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * Export a section and its activities to the specified directory. |
||
44 | */ |
||
45 | public function exportSection(int $sectionId, string $exportDir): void |
||
46 | { |
||
47 | $sectionDir = $exportDir."/sections/section_{$sectionId}"; |
||
48 | if (!is_dir($sectionDir)) { |
||
49 | mkdir($sectionDir, api_get_permissions_for_new_directories(), true); |
||
50 | } |
||
51 | |||
52 | if ($sectionId > 0) { |
||
53 | $learnpath = $this->getLearnpathById($sectionId); |
||
54 | if (null === $learnpath) { |
||
55 | throw new Exception("Learnpath with ID $sectionId not found."); |
||
56 | } |
||
57 | $sectionData = $this->getSectionData($learnpath); |
||
58 | } else { |
||
59 | $sectionData = [ |
||
60 | 'id' => 0, |
||
61 | 'number' => 0, |
||
62 | 'name' => get_lang('General'), |
||
63 | 'summary' => get_lang('GeneralResourcesCourse'), |
||
64 | 'sequence' => 0, |
||
65 | 'visible' => 1, |
||
66 | 'timemodified' => time(), |
||
67 | 'activities' => $this->getActivitiesForGeneral(), |
||
68 | ]; |
||
69 | } |
||
70 | |||
71 | $this->exportActivities($sectionData['activities'], $exportDir, (int) $sectionData['id']); |
||
72 | $this->createSectionXml($sectionData, $sectionDir); |
||
73 | $this->createInforefXml($sectionData, $sectionDir); |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * Get all general items not linked to any learnpath. |
||
78 | * |
||
79 | * @return array<int,array<string,mixed>> |
||
80 | */ |
||
81 | public function getGeneralItems(): array |
||
82 | { |
||
83 | $generalItems = []; |
||
84 | |||
85 | $resourceTypes = [ |
||
86 | RESOURCE_DOCUMENT => 'source_id', |
||
87 | RESOURCE_QUIZ => 'source_id', |
||
88 | RESOURCE_GLOSSARY => 'glossary_id', |
||
89 | RESOURCE_LINK => 'source_id', |
||
90 | RESOURCE_WORK => 'source_id', |
||
91 | RESOURCE_FORUM => 'source_id', |
||
92 | RESOURCE_SURVEY => 'source_id', |
||
93 | RESOURCE_TOOL_INTRO => 'source_id', |
||
94 | ]; |
||
95 | |||
96 | foreach ($resourceTypes as $resourceType => $idKey) { |
||
97 | if (!empty($this->course->resources[$resourceType])) { |
||
98 | foreach ($this->course->resources[$resourceType] as $id => $resource) { |
||
99 | if (!$this->isItemInLearnpath($resource, (string) $resourceType)) { |
||
100 | $title = RESOURCE_WORK === $resourceType |
||
101 | ? ($resource->params['title'] ?? '') |
||
102 | : ($resource->title ?? $resource->name); |
||
103 | $generalItems[] = [ |
||
104 | 'id' => $resource->{$idKey}, |
||
105 | 'item_type' => $resourceType, |
||
106 | 'path' => $id, |
||
107 | 'title' => $title, |
||
108 | ]; |
||
109 | } |
||
110 | } |
||
111 | } |
||
112 | } |
||
113 | |||
114 | return $generalItems; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Get the activities for the general section. |
||
119 | * |
||
120 | * @return array<int,array<string,mixed>> |
||
121 | */ |
||
122 | public function getActivitiesForGeneral(): array |
||
123 | { |
||
124 | $generalLearnpath = (object) [ |
||
125 | 'items' => $this->getGeneralItems(), |
||
126 | 'source_id' => 0, |
||
127 | ]; |
||
128 | |||
129 | $activities = $this->getActivitiesForSection($generalLearnpath, true); |
||
130 | |||
131 | if (!\in_array('folder', array_column($activities, 'modulename'), true)) { |
||
132 | $activities[] = [ |
||
133 | 'id' => 0, |
||
134 | 'moduleid' => 0, |
||
135 | 'modulename' => 'folder', |
||
136 | 'name' => 'Documents', |
||
137 | 'sectionid' => 0, |
||
138 | ]; |
||
139 | } |
||
140 | |||
141 | return $activities; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Get the learnpath object by its ID. |
||
146 | */ |
||
147 | public function getLearnpathById(int $sectionId): ?object |
||
148 | { |
||
149 | foreach (($this->course->resources[RESOURCE_LEARNPATH] ?? []) as $learnpath) { |
||
150 | if (($learnpath->source_id ?? null) == $sectionId) { |
||
151 | return $learnpath; |
||
152 | } |
||
153 | } |
||
154 | |||
155 | return null; |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Get section data for a learnpath. |
||
160 | * |
||
161 | * @return array<string,mixed> |
||
162 | */ |
||
163 | public function getSectionData(object $learnpath): array |
||
164 | { |
||
165 | return [ |
||
166 | 'id' => $learnpath->source_id, |
||
167 | 'number' => $learnpath->display_order, |
||
168 | 'name' => $learnpath->name, |
||
169 | 'summary' => $learnpath->description, |
||
170 | 'sequence' => $learnpath->source_id, |
||
171 | 'visible' => $learnpath->visibility, |
||
172 | 'timemodified' => strtotime($learnpath->modified_on), |
||
173 | 'activities' => $this->getActivitiesForSection($learnpath), |
||
174 | ]; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Get the activities for a specific section. |
||
179 | * |
||
180 | * @return array<int,array<string,mixed>> |
||
181 | */ |
||
182 | public function getActivitiesForSection(object $learnpath, bool $isGeneral = false): array |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Export the activities of a section. |
||
196 | * |
||
197 | * @param array<int,array<string,mixed>> $activities |
||
198 | */ |
||
199 | private function exportActivities(array $activities, string $exportDir, int $sectionId): void |
||
200 | { |
||
201 | $exportClasses = [ |
||
202 | 'quiz' => QuizExport::class, |
||
203 | 'glossary' => GlossaryExport::class, |
||
204 | 'url' => UrlExport::class, |
||
205 | 'assign' => AssignExport::class, |
||
206 | 'forum' => ForumExport::class, |
||
207 | 'page' => PageExport::class, |
||
208 | 'resource' => ResourceExport::class, |
||
209 | 'folder' => FolderExport::class, |
||
210 | 'feedback' => FeedbackExport::class, |
||
211 | ]; |
||
212 | |||
213 | foreach ($activities as $activity) { |
||
214 | $moduleName = $activity['modulename']; |
||
215 | if (isset($exportClasses[$moduleName])) { |
||
216 | $exportClass = $exportClasses[$moduleName]; |
||
217 | $exporter = new $exportClass($this->course); |
||
218 | $exporter->export((int) $activity['id'], $exportDir, (int) $activity['moduleid'], $sectionId); |
||
219 | } else { |
||
220 | throw new Exception("Export for module '$moduleName' is not supported."); |
||
221 | } |
||
222 | } |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Check if an item is associated with any learnpath. |
||
227 | */ |
||
228 | private function isItemInLearnpath(object $item, string $type): bool |
||
229 | { |
||
230 | foreach (($this->course->resources[RESOURCE_LEARNPATH] ?? []) as $learnpath) { |
||
231 | foreach (($learnpath->items ?? []) as $learnpathItem) { |
||
232 | $lpType = ($learnpathItem['item_type'] ?? '') === 'student_publication' ? 'work' : ($learnpathItem['item_type'] ?? ''); |
||
233 | if ($lpType === $type && (string) ($learnpathItem['path'] ?? '') === (string) ($item->source_id ?? '')) { |
||
234 | return true; |
||
235 | } |
||
236 | } |
||
237 | } |
||
238 | |||
239 | return false; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Add an activity to the activities list. |
||
244 | * |
||
245 | * @param array<string,mixed> $item |
||
246 | * @param array<int,array<string,mixed>> $activities (by ref) |
||
247 | */ |
||
248 | private function addActivityToList(array $item, int $sectionId, array &$activities): void |
||
326 | ]; |
||
327 | } |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Determine the document type based on filetype and path. |
||
332 | */ |
||
333 | private function getDocumentType(string $filetype, string $path): ?string |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * Create the section.xml file. |
||
348 | * |
||
349 | * @param array<string,mixed> $sectionData |
||
350 | */ |
||
351 | private function createSectionXml(array $sectionData, string $destinationDir): void |
||
352 | { |
||
353 | $seen = []; |
||
354 | $cmIds = []; |
||
355 | foreach ($sectionData['activities'] as $a) { |
||
356 | $name = (string) ($a['modulename'] ?? ''); |
||
357 | $mid = isset($a['moduleid']) ? (int) $a['moduleid'] : null; |
||
358 | if ('' === $name || null === $mid || $mid < 0) { |
||
359 | continue; |
||
360 | } |
||
361 | |||
362 | $key = $name.':'.$mid; |
||
363 | if (isset($seen[$key])) { |
||
364 | continue; |
||
365 | } |
||
366 | $seen[$key] = true; |
||
367 | |||
368 | $cmIds[] = (string) $mid; |
||
369 | } |
||
370 | |||
371 | $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL; |
||
372 | $xmlContent .= '<section id="'.$sectionData['id'].'">'.PHP_EOL; |
||
373 | $xmlContent .= ' <number>'.$sectionData['number'].'</number>'.PHP_EOL; |
||
374 | $xmlContent .= ' <name>'.htmlspecialchars((string) $sectionData['name']).'</name>'.PHP_EOL; |
||
375 | $xmlContent .= ' <summary>'.htmlspecialchars((string) $sectionData['summary']).'</summary>'.PHP_EOL; |
||
376 | $xmlContent .= ' <summaryformat>1</summaryformat>'.PHP_EOL; |
||
377 | $xmlContent .= ' <sequence>'.implode(',', $cmIds).'</sequence>'.PHP_EOL; |
||
378 | $xmlContent .= ' <visible>'.$sectionData['visible'].'</visible>'.PHP_EOL; |
||
379 | $xmlContent .= ' <timemodified>'.$sectionData['timemodified'].'</timemodified>'.PHP_EOL; |
||
380 | $xmlContent .= '</section>'.PHP_EOL; |
||
381 | |||
382 | file_put_contents($destinationDir.'/section.xml', $xmlContent); |
||
383 | } |
||
384 | |||
385 | /** |
||
386 | * Create the inforef.xml file for the section. |
||
387 | * |
||
388 | * @param array<string,mixed> $sectionData |
||
389 | */ |
||
390 | private function createInforefXml(array $sectionData, string $destinationDir): void |
||
403 | } |
||
404 | } |
||
405 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.