1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* For licensing terms, see /license.txt */ |
4
|
|
|
|
5
|
|
|
use Chamilo\CoreBundle\Entity\Asset; |
6
|
|
|
use Chamilo\CoreBundle\Entity\CourseCategory as CourseCategoryEntity; |
7
|
|
|
use Chamilo\CoreBundle\Framework\Container; |
8
|
|
|
use Chamilo\CoreBundle\Component\Utils\ActionIcon; |
9
|
|
|
use Chamilo\CoreBundle\Component\Utils\ObjectIcon; |
10
|
|
|
|
11
|
|
|
class CourseCategory |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Get category details from a simple category code. |
15
|
|
|
* |
16
|
|
|
* @param string|null $categoryCode The literal category code |
17
|
|
|
* |
18
|
|
|
* @return array |
19
|
|
|
*/ |
20
|
|
|
public static function getCategory(string $categoryCode = null): array |
21
|
|
|
{ |
22
|
|
|
if (!empty($categoryCode)) { |
23
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
24
|
|
|
$categoryCode = Database::escape_string($categoryCode); |
25
|
|
|
$sql = "SELECT * FROM $table WHERE code ='$categoryCode'"; |
26
|
|
|
$result = Database::query($sql); |
27
|
|
|
|
28
|
|
|
if (Database::num_rows($result)) { |
29
|
|
|
$category = Database::fetch_assoc($result); |
30
|
|
|
if ($category) { |
31
|
|
|
// Get access url id |
32
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
33
|
|
|
$sql = "SELECT * FROM $table WHERE course_category_id = ".$category['id']; |
34
|
|
|
$result = Database::query($sql); |
35
|
|
|
$result = Database::fetch_array($result); |
36
|
|
|
if ($result) { |
37
|
|
|
$category['access_url_id'] = $result['access_url_id']; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
return $category; |
|
|
|
|
41
|
|
|
} |
42
|
|
|
} |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
return []; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Returns the category fields from the database from an int ID. |
50
|
|
|
* |
51
|
|
|
* @param int $categoryId The category ID |
52
|
|
|
* |
53
|
|
|
* @return array |
54
|
|
|
*/ |
55
|
|
|
public static function getCategoryById($categoryId) |
56
|
|
|
{ |
57
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
58
|
|
|
$categoryId = (int) $categoryId; |
59
|
|
|
$sql = "SELECT * FROM $table WHERE id = $categoryId"; |
60
|
|
|
$result = Database::query($sql); |
61
|
|
|
if (Database::num_rows($result)) { |
62
|
|
|
$category = Database::fetch_assoc($result); |
63
|
|
|
if ($category) { |
64
|
|
|
// Get access url id |
65
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
66
|
|
|
$sql = "SELECT * FROM $table WHERE course_category_id = ".$category['id']; |
67
|
|
|
$result = Database::query($sql); |
68
|
|
|
$result = Database::fetch_array($result); |
69
|
|
|
if ($result) { |
70
|
|
|
$category['access_url_id'] = $result['access_url_id']; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
return $category; |
|
|
|
|
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
return []; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Returns a flat list of all course categories in this URL. If the |
82
|
|
|
* allow_base_course_category option is true, then also show the |
83
|
|
|
* course categories of the base URL. |
84
|
|
|
* |
85
|
|
|
* @return array [id, name, code, parent_id, tree_pos, children_count, number_courses] |
86
|
|
|
*/ |
87
|
|
|
public static function getAllCategories() |
88
|
|
|
{ |
89
|
|
|
$tbl_category = Database::get_main_table(TABLE_MAIN_CATEGORY); |
90
|
|
|
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
91
|
|
|
|
92
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
93
|
|
|
$conditions = " INNER JOIN $table a ON (t1.id = a.course_category_id)"; |
94
|
|
|
$whereCondition = " AND a.access_url_id = ".api_get_current_access_url_id(); |
95
|
|
|
$allowBaseCategories = ('true' === api_get_setting('course.allow_base_course_category')); |
96
|
|
|
if ($allowBaseCategories) { |
97
|
|
|
$whereCondition = " AND (a.access_url_id = ".api_get_current_access_url_id()." OR a.access_url_id = 1) "; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
$sql = "SELECT |
101
|
|
|
t1.id, |
102
|
|
|
t1.title, |
103
|
|
|
t1.code, |
104
|
|
|
t1.parent_id, |
105
|
|
|
t1.tree_pos, |
106
|
|
|
t1.children_count, |
107
|
|
|
COUNT(DISTINCT t3.code) AS number_courses |
108
|
|
|
FROM $tbl_category t1 |
109
|
|
|
$conditions |
110
|
|
|
LEFT JOIN $tbl_course t3 |
111
|
|
|
ON t3.category_id=t1.id |
112
|
|
|
WHERE 1=1 |
113
|
|
|
$whereCondition |
114
|
|
|
GROUP BY |
115
|
|
|
t1.title, |
116
|
|
|
t1.code, |
117
|
|
|
t1.parent_id, |
118
|
|
|
t1.tree_pos, |
119
|
|
|
t1.children_count |
120
|
|
|
ORDER BY t1.parent_id, t1.tree_pos"; |
121
|
|
|
|
122
|
|
|
$result = Database::query($sql); |
123
|
|
|
|
124
|
|
|
return Database::store_result($result, 'ASSOC'); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @param string $code |
129
|
|
|
* @param string $name |
130
|
|
|
* @param string $canHaveCourses |
131
|
|
|
* @param int|null $parentId |
132
|
|
|
*/ |
133
|
|
|
public static function add($code, $name, $canHaveCourses, $description = '', $parentId = null): ?CourseCategoryEntity |
134
|
|
|
{ |
135
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
136
|
|
|
$code = trim($code); |
137
|
|
|
$name = trim($name); |
138
|
|
|
$parentId = (int) $parentId; |
139
|
|
|
|
140
|
|
|
$code = CourseManager::generate_course_code($code); |
141
|
|
|
$sql = "SELECT 1 FROM $table |
142
|
|
|
WHERE code = '".Database::escape_string($code)."'"; |
143
|
|
|
$result = Database::query($sql); |
144
|
|
|
if (Database::num_rows($result)) { |
145
|
|
|
return null; |
146
|
|
|
} |
147
|
|
|
$result = Database::query("SELECT MAX(tree_pos) AS maxTreePos FROM $table"); |
148
|
|
|
$row = Database::fetch_array($result); |
149
|
|
|
$tree_pos = $row['maxTreePos'] + 1; |
150
|
|
|
$parentId = empty($parentId) ? null : $parentId; |
151
|
|
|
|
152
|
|
|
$repo = Container::getCourseCategoryRepository(); |
153
|
|
|
$category = new CourseCategoryEntity(); |
154
|
|
|
$category |
155
|
|
|
->setTitle($name) |
156
|
|
|
->setCode($code) |
157
|
|
|
->setDescription($description) |
158
|
|
|
->setTreePos($tree_pos) |
159
|
|
|
->setAuthCourseChild($canHaveCourses) |
160
|
|
|
->setAuthCatChild('TRUE'); |
161
|
|
|
|
162
|
|
|
if (!empty($parentId)) { |
163
|
|
|
$category->setParent($repo->find($parentId)); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
$repo->save($category); |
167
|
|
|
|
168
|
|
|
$categoryId = $category->getId(); |
169
|
|
|
if ($categoryId) { |
170
|
|
|
self::updateParentCategoryChildrenCount($parentId, 1); |
171
|
|
|
UrlManager::addCourseCategoryListToUrl( |
172
|
|
|
[$categoryId], |
173
|
|
|
[api_get_current_access_url_id()] |
174
|
|
|
); |
175
|
|
|
|
176
|
|
|
return $category; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
return null; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Recursive function that updates the count of children in the parent. |
184
|
|
|
* |
185
|
|
|
* @param string $categoryId Category ID |
186
|
|
|
* @param int $delta The number to add or delete (1 to add one, -1 to remove one) |
187
|
|
|
*/ |
188
|
|
|
public static function updateParentCategoryChildrenCount($categoryId, $delta = 1) |
189
|
|
|
{ |
190
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
191
|
|
|
$categoryId = Database::escape_string($categoryId); |
192
|
|
|
$delta = (int) $delta; |
193
|
|
|
// First get to the highest level possible in the tree |
194
|
|
|
$result = Database::query("SELECT parent_id FROM $table WHERE id = '$categoryId'"); |
195
|
|
|
$row = Database::fetch_array($result); |
196
|
|
|
if (false !== $row && !empty($row['parent_id'])) { |
197
|
|
|
// if a parent was found, enter there to see if he's got one more parent |
198
|
|
|
self::updateParentCategoryChildrenCount($row['parent_id'], $delta); |
199
|
|
|
} |
200
|
|
|
// Now we're at the top, get back down to update each child |
201
|
|
|
$sql = "UPDATE $table SET children_count = (children_count - ".abs($delta).") WHERE id = '$categoryId'"; |
202
|
|
|
if ($delta >= 0) { |
203
|
|
|
$sql = "UPDATE $table SET children_count = (children_count + $delta) WHERE id = '$categoryId'"; |
204
|
|
|
} |
205
|
|
|
Database::query($sql); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
public static function edit($categoryId, $name, $canHaveCourses, $code, $description): ?CourseCategoryEntity |
209
|
|
|
{ |
210
|
|
|
$repo = Container::getCourseCategoryRepository(); |
211
|
|
|
$category = $repo->find($categoryId); |
212
|
|
|
if (null === $category) { |
213
|
|
|
return null; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$name = trim($name); |
217
|
|
|
$category |
218
|
|
|
->setCode($name) |
219
|
|
|
->setTitle($name) |
220
|
|
|
->setDescription($description) |
221
|
|
|
->setAuthCourseChild($canHaveCourses) |
222
|
|
|
; |
223
|
|
|
|
224
|
|
|
$repo->save($category); |
225
|
|
|
|
226
|
|
|
// Updating children |
227
|
|
|
/*$sql = "UPDATE $tbl_category SET parent_id = '$code' |
228
|
|
|
WHERE parent_id = '$old_code'"; |
229
|
|
|
Database::query($sql);*/ |
230
|
|
|
|
231
|
|
|
return $category; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Move a node up on display. |
236
|
|
|
* |
237
|
|
|
* @param string $code |
238
|
|
|
* @param int $tree_pos |
239
|
|
|
* @param string $parent_id |
240
|
|
|
* |
241
|
|
|
* @return bool |
242
|
|
|
*/ |
243
|
|
|
public static function moveNodeUp($categoryId, $treePos, $parentId): bool |
244
|
|
|
{ |
245
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
246
|
|
|
$categoryId = (int) $categoryId; |
247
|
|
|
$treePos = (int) $treePos; |
248
|
|
|
|
249
|
|
|
$parentIdCondition = "parent_id IS NULL"; |
250
|
|
|
if (!empty($parentId)) { |
251
|
|
|
$parentIdCondition = "parent_id = '".Database::escape_string($parentId)."'"; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
self::reorganizeTreePos($parentId); |
255
|
|
|
|
256
|
|
|
$sql = "SELECT id, tree_pos |
257
|
|
|
FROM $table |
258
|
|
|
WHERE $parentIdCondition AND tree_pos < $treePos |
259
|
|
|
ORDER BY tree_pos DESC |
260
|
|
|
LIMIT 1"; |
261
|
|
|
|
262
|
|
|
$result = Database::query($sql); |
263
|
|
|
$previousCategory = Database::fetch_array($result); |
264
|
|
|
|
265
|
|
|
if (!$previousCategory) { |
266
|
|
|
return false; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
Database::query("UPDATE $table SET tree_pos = {$previousCategory['tree_pos']} WHERE id = $categoryId"); |
270
|
|
|
Database::query("UPDATE $table SET tree_pos = $treePos WHERE id = {$previousCategory['id']}"); |
271
|
|
|
|
272
|
|
|
return true; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
public static function reorganizeTreePos($parentId): void |
276
|
|
|
{ |
277
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
278
|
|
|
|
279
|
|
|
$parentIdCondition = "parent_id IS NULL"; |
280
|
|
|
if (!empty($parentId)) { |
281
|
|
|
$parentIdCondition = "parent_id = '".Database::escape_string($parentId)."'"; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
$sql = "SELECT id FROM $table WHERE $parentIdCondition ORDER BY tree_pos"; |
285
|
|
|
$result = Database::query($sql); |
286
|
|
|
|
287
|
|
|
$newTreePos = 1; |
288
|
|
|
while ($row = Database::fetch_array($result)) { |
289
|
|
|
Database::query("UPDATE $table SET tree_pos = $newTreePos WHERE id = {$row['id']}"); |
290
|
|
|
$newTreePos++; |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* @param string $categoryCode |
296
|
|
|
* |
297
|
|
|
* @return array |
298
|
|
|
*/ |
299
|
|
|
public static function getChildren($categoryCode) |
300
|
|
|
{ |
301
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
302
|
|
|
$categoryCode = Database::escape_string($categoryCode); |
303
|
|
|
$sql = "SELECT code, id FROM $table |
304
|
|
|
WHERE parent_id = '$categoryCode'"; |
305
|
|
|
$result = Database::query($sql); |
306
|
|
|
$children = []; |
307
|
|
|
while ($row = Database::fetch_assoc($result)) { |
308
|
|
|
$children[] = $row; |
309
|
|
|
$subChildren = self::getChildren($row['code']); |
310
|
|
|
$children = array_merge($children, $subChildren); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
return $children; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* @param string $categoryCode |
318
|
|
|
* |
319
|
|
|
* @return string|null |
320
|
|
|
*/ |
321
|
|
|
public static function getParentsToString($categoryCode) |
322
|
|
|
{ |
323
|
|
|
$parents = self::getParents($categoryCode); |
324
|
|
|
|
325
|
|
|
if (!empty($parents)) { |
326
|
|
|
$parents = array_reverse($parents); |
327
|
|
|
$categories = []; |
328
|
|
|
foreach ($parents as $category) { |
329
|
|
|
$categories[] = $category['code']; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
return implode(' > ', $categories).' > '; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
return null; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* @param string $categoryCode |
340
|
|
|
* |
341
|
|
|
* @return array |
342
|
|
|
*/ |
343
|
|
|
public static function getParents($categoryCode) |
344
|
|
|
{ |
345
|
|
|
if (empty($categoryCode)) { |
346
|
|
|
return []; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
350
|
|
|
$categoryCode = Database::escape_string($categoryCode); |
351
|
|
|
$sql = "SELECT code, parent_id |
352
|
|
|
FROM $table |
353
|
|
|
WHERE code = '$categoryCode'"; |
354
|
|
|
|
355
|
|
|
$result = Database::query($sql); |
356
|
|
|
$children = []; |
357
|
|
|
while ($row = Database::fetch_assoc($result)) { |
358
|
|
|
$parent = self::getCategory($row['parent_id']); |
359
|
|
|
$children[] = $row; |
360
|
|
|
$subChildren = self::getParents($parent ? $parent['code'] : null); |
361
|
|
|
$children = array_merge($children, $subChildren); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
return $children; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
public static function listCategories(array $categorySource = []): string |
368
|
|
|
{ |
369
|
|
|
$categories = self::getCategories($categorySource ? $categorySource['id'] : null); |
370
|
|
|
$categoryCode = $categorySource ? Security::remove_XSS($categorySource['code']) : ''; |
371
|
|
|
|
372
|
|
|
if (count($categories) > 0) { |
373
|
|
|
$table = new HTML_Table(['class' => 'data_table']); |
374
|
|
|
$column = 0; |
375
|
|
|
$row = 0; |
376
|
|
|
$headers = [ |
377
|
|
|
get_lang('Category'), |
378
|
|
|
get_lang('Sub-categories'), |
379
|
|
|
get_lang('Courses'), |
380
|
|
|
get_lang('Detail'), |
381
|
|
|
]; |
382
|
|
|
foreach ($headers as $header) { |
383
|
|
|
$table->setHeaderContents($row, $column, $header); |
384
|
|
|
$column++; |
385
|
|
|
} |
386
|
|
|
$row++; |
387
|
|
|
$mainUrl = api_get_path(WEB_CODE_PATH).'admin/course_category.php?category='.$categoryCode; |
|
|
|
|
388
|
|
|
|
389
|
|
|
$editIcon = Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Edit')); |
390
|
|
|
$exportIcon = Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('ExportAsCSV')); |
391
|
|
|
$deleteIcon = Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')); |
392
|
|
|
$moveIcon = Display::getMdiIcon(ActionIcon::UP, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Up in same level')); |
393
|
|
|
|
394
|
|
|
$urlId = api_get_current_access_url_id(); |
395
|
|
|
foreach ($categories as $category) { |
396
|
|
|
$categoryId = $category->getId(); |
397
|
|
|
$code = $category->getCode(); |
398
|
|
|
$editUrl = $mainUrl.'&id='.$categoryId.'&action=edit'; |
399
|
|
|
$moveUrl = $mainUrl.'&id='.$categoryId.'&action=moveUp&tree_pos='.$category->getTreePos(); |
400
|
|
|
$deleteUrl = $mainUrl.'&id='.$categoryId.'&action=delete'; |
401
|
|
|
$exportUrl = $mainUrl.'&id='.$categoryId.'&action=export'; |
402
|
|
|
|
403
|
|
|
$actions = []; |
404
|
|
|
|
405
|
|
|
$inUrl = $category->getUrls()->filter( |
406
|
|
|
function ($entry) use ($urlId) { |
407
|
|
|
return $entry->getUrl()->getId() === $urlId; |
408
|
|
|
} |
409
|
|
|
); |
410
|
|
|
|
411
|
|
|
if ($inUrl->count() > 0) { |
412
|
|
|
$actions[] = Display::url($editIcon, $editUrl); |
413
|
|
|
$actions[] = Display::url($moveIcon, $moveUrl); |
414
|
|
|
$actions[] = Display::url($exportIcon, $exportUrl); |
415
|
|
|
$actions[] = Display::url( |
416
|
|
|
$deleteIcon, |
417
|
|
|
$deleteUrl, |
418
|
|
|
[ |
419
|
|
|
'onclick' => 'javascript: if (!confirm(\''.addslashes( |
420
|
|
|
api_htmlentities(sprintf(get_lang('Please confirm your choice')), ENT_QUOTES) |
421
|
|
|
).'\')) return false;', |
422
|
|
|
] |
423
|
|
|
); |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
$url = api_get_path(WEB_CODE_PATH).'admin/course_category.php?id='.$categoryId; |
427
|
|
|
$title = Display::url( |
428
|
|
|
Display::getMdiIcon( |
429
|
|
|
ObjectIcon::FOLDER, |
430
|
|
|
'ch-tool-icon', |
431
|
|
|
null, |
432
|
|
|
ICON_SIZE_SMALL, |
433
|
|
|
get_lang('Open this category') |
434
|
|
|
).' '.$category->getTitle().' ('.$code.')', |
435
|
|
|
$url |
436
|
|
|
); |
437
|
|
|
|
438
|
|
|
$countCourses = $category->getCourses()->count(); |
439
|
|
|
$content = [ |
440
|
|
|
$title, |
441
|
|
|
$category->getChildrenCount(), |
442
|
|
|
$countCourses, |
443
|
|
|
implode('', $actions), |
444
|
|
|
]; |
445
|
|
|
$column = 0; |
446
|
|
|
foreach ($content as $value) { |
447
|
|
|
$table->setCellContents($row, $column, $value); |
448
|
|
|
$column++; |
449
|
|
|
} |
450
|
|
|
$row++; |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
return $table->toHtml(); |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
return Display::return_message(get_lang('There are no categories here'), 'warning'); |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* @param int|null $category Optional. Parent category ID. |
461
|
|
|
* |
462
|
|
|
* @return CourseCategoryEntity[] |
463
|
|
|
*/ |
464
|
|
|
public static function getCategories($category = null) |
465
|
|
|
{ |
466
|
|
|
$repo = Container::getCourseCategoryRepository(); |
467
|
|
|
$category = (int) $category; |
468
|
|
|
$allowBaseCourseCategory = ('true' === api_get_setting('course.allow_base_course_category')); |
469
|
|
|
|
470
|
|
|
return $repo->findAllInAccessUrl( |
471
|
|
|
api_get_current_access_url_id(), |
472
|
|
|
$allowBaseCourseCategory, |
473
|
|
|
$category |
474
|
|
|
); |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* @return array |
479
|
|
|
*/ |
480
|
|
|
public static function getCategoriesToDisplayInHomePage() |
481
|
|
|
{ |
482
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
483
|
|
|
$sql = "SELECT title FROM $table |
484
|
|
|
WHERE parent_id IS NULL |
485
|
|
|
ORDER BY tree_pos"; |
486
|
|
|
|
487
|
|
|
return Database::store_result(Database::query($sql)); |
488
|
|
|
} |
489
|
|
|
|
490
|
|
|
/** |
491
|
|
|
* @param string $categoryCode |
492
|
|
|
* |
493
|
|
|
* @return array |
494
|
|
|
*/ |
495
|
|
|
public static function getCategoriesCanBeAddedInCourse($categoryCode) |
496
|
|
|
{ |
497
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
498
|
|
|
$conditions = " INNER JOIN $table a ON (c.id = a.course_category_id)"; |
499
|
|
|
$whereCondition = ' AND a.access_url_id = '.api_get_current_access_url_id(); |
500
|
|
|
|
501
|
|
|
$tbl_category = Database::get_main_table(TABLE_MAIN_CATEGORY); |
502
|
|
|
$sql = "SELECT c.id, c.code, c.title |
503
|
|
|
FROM $tbl_category c |
504
|
|
|
$conditions |
505
|
|
|
WHERE (auth_course_child = 'TRUE' OR code = '".Database::escape_string($categoryCode)."') |
506
|
|
|
$whereCondition |
507
|
|
|
ORDER BY tree_pos"; |
508
|
|
|
$res = Database::query($sql); |
509
|
|
|
|
510
|
|
|
$categoryToAvoid = ''; |
511
|
|
|
if (!api_is_platform_admin()) { |
512
|
|
|
$categoryToAvoid = api_get_setting('course.course_category_code_to_use_as_model'); |
513
|
|
|
} |
514
|
|
|
$categories[''] = '-'; |
|
|
|
|
515
|
|
|
while ($cat = Database::fetch_array($res)) { |
516
|
|
|
$categoryCode = $cat['code']; |
517
|
|
|
if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) { |
518
|
|
|
continue; |
519
|
|
|
} |
520
|
|
|
$categories[$cat['id']] = '('.$cat['code'].') '.$cat['title']; |
521
|
|
|
ksort($categories); |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
return $categories; |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
/** |
528
|
|
|
* @param string $category_code |
529
|
|
|
* @param string $keyword |
530
|
|
|
* |
531
|
|
|
* @paran bool $avoidCourses |
532
|
|
|
* @paran array $conditions |
533
|
|
|
* |
534
|
|
|
* @return int |
535
|
|
|
*/ |
536
|
|
|
public static function countCoursesInCategory( |
537
|
|
|
$category_code = '', |
538
|
|
|
$keyword = '', |
539
|
|
|
$avoidCourses = true, |
540
|
|
|
$conditions = [] |
541
|
|
|
) { |
542
|
|
|
return self::getCoursesInCategory($category_code, $keyword, $avoidCourses, $conditions, true); |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
/** |
546
|
|
|
* @return \Chamilo\CoreBundle\Entity\Course[] |
547
|
|
|
*/ |
548
|
|
|
public static function getCoursesInCategory( |
549
|
|
|
$categoryId, |
550
|
|
|
$keyword = '', |
551
|
|
|
$avoidCourses = true, |
552
|
|
|
$conditions = [], |
553
|
|
|
$getCount = false |
554
|
|
|
) { |
555
|
|
|
$repo = Container::getCourseCategoryRepository(); |
556
|
|
|
/** @var CourseCategoryEntity $category */ |
557
|
|
|
$category = $repo->find($categoryId); |
558
|
|
|
|
559
|
|
|
// @todo add filters |
560
|
|
|
|
561
|
|
|
return $category->getCourses(); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* @param array $list |
566
|
|
|
* |
567
|
|
|
* @return array |
568
|
|
|
*/ |
569
|
|
|
public static function getCourseCategoryNotInList($list) |
570
|
|
|
{ |
571
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
572
|
|
|
|
573
|
|
|
if (empty($list)) { |
574
|
|
|
$sql = "SELECT * FROM $table |
575
|
|
|
WHERE (parent_id IS NULL) "; |
576
|
|
|
$result = Database::query($sql); |
577
|
|
|
|
578
|
|
|
return Database::store_result($result, 'ASSOC'); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
$list = array_map('intval', $list); |
582
|
|
|
$listToString = implode("','", $list); |
583
|
|
|
|
584
|
|
|
$sql = "SELECT * FROM $table |
585
|
|
|
WHERE id NOT IN ('$listToString') AND (parent_id IS NULL) "; |
586
|
|
|
$result = Database::query($sql); |
587
|
|
|
|
588
|
|
|
return Database::store_result($result, 'ASSOC'); |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* @param string $keyword |
593
|
|
|
* |
594
|
|
|
* @return array|null |
595
|
|
|
*/ |
596
|
|
|
public static function searchCategoryByKeyword($keyword) |
597
|
|
|
{ |
598
|
|
|
if (empty($keyword)) { |
599
|
|
|
return null; |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
$tableCategory = Database::get_main_table(TABLE_MAIN_CATEGORY); |
603
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
604
|
|
|
$conditions = " INNER JOIN $table a ON (c.id = a.course_category_id)"; |
605
|
|
|
$whereCondition = " AND a.access_url_id = ".api_get_current_access_url_id(); |
606
|
|
|
|
607
|
|
|
$allowBaseCategories = ('true' === api_get_setting('course.allow_base_course_category')); |
608
|
|
|
if ($allowBaseCategories) { |
609
|
|
|
$whereCondition = " AND (a.access_url_id = ".api_get_current_access_url_id()." OR a.access_url_id = 1) "; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
$keyword = Database::escape_string($keyword); |
613
|
|
|
|
614
|
|
|
$sql = "SELECT c.*, c.title as text |
615
|
|
|
FROM $tableCategory c $conditions |
616
|
|
|
WHERE |
617
|
|
|
( |
618
|
|
|
c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' |
619
|
|
|
) AND auth_course_child = 'TRUE' |
620
|
|
|
$whereCondition "; |
621
|
|
|
$result = Database::query($sql); |
622
|
|
|
|
623
|
|
|
return Database::store_result($result, 'ASSOC'); |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
/** |
627
|
|
|
* Get Pagination HTML div. |
628
|
|
|
* |
629
|
|
|
* @param $pageCurrent |
630
|
|
|
* @param $pageLength |
631
|
|
|
* @param $pageTotal |
632
|
|
|
* |
633
|
|
|
* @return string |
634
|
|
|
*/ |
635
|
|
|
public static function getCatalogPagination($pageCurrent, $pageLength, $pageTotal) |
636
|
|
|
{ |
637
|
|
|
// Start empty html |
638
|
|
|
$pageDiv = ''; |
639
|
|
|
$html = ''; |
640
|
|
|
$pageBottom = max(1, $pageCurrent - 3); |
641
|
|
|
$pageTop = min($pageTotal, $pageCurrent + 3); |
642
|
|
|
|
643
|
|
|
if ($pageBottom > 1) { |
644
|
|
|
$pageDiv .= self::getPageNumberItem(1, $pageLength); |
645
|
|
|
if ($pageBottom > 2) { |
646
|
|
|
$pageDiv .= self::getPageNumberItem( |
647
|
|
|
$pageBottom - 1, |
648
|
|
|
$pageLength, |
649
|
|
|
null, |
650
|
|
|
'...' |
651
|
|
|
); |
652
|
|
|
} |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
// For each page add its page button to html |
656
|
|
|
for ($i = $pageBottom; $i <= $pageTop; $i++) { |
657
|
|
|
if ($i === $pageCurrent) { |
658
|
|
|
$pageItemAttributes = ['class' => 'page-item active']; |
659
|
|
|
} else { |
660
|
|
|
$pageItemAttributes = ['class' => 'page-item']; |
661
|
|
|
} |
662
|
|
|
$pageDiv .= self::getPageNumberItem( |
663
|
|
|
$i, |
664
|
|
|
$pageLength, |
665
|
|
|
$pageItemAttributes |
666
|
|
|
); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
// Check if current page is the last page |
670
|
|
|
if ($pageTop < $pageTotal) { |
671
|
|
|
if ($pageTop < ($pageTotal - 1)) { |
672
|
|
|
$pageDiv .= self::getPageNumberItem( |
673
|
|
|
$pageTop + 1, |
674
|
|
|
$pageLength, |
675
|
|
|
null, |
676
|
|
|
'...' |
677
|
|
|
); |
678
|
|
|
} |
679
|
|
|
$pageDiv .= self::getPageNumberItem($pageTotal, $pageLength); |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
// Complete pagination html |
683
|
|
|
$pageDiv = Display::tag('ul', $pageDiv, ['class' => 'pagination']); |
684
|
|
|
$html .= '<nav>'.$pageDiv.'</nav>'; |
685
|
|
|
|
686
|
|
|
return $html; |
687
|
|
|
} |
688
|
|
|
|
689
|
|
|
/** |
690
|
|
|
* Get li HTML of page number. |
691
|
|
|
* |
692
|
|
|
* @param $pageNumber |
693
|
|
|
* @param $pageLength |
694
|
|
|
* @param array $liAttributes |
695
|
|
|
* @param string $content |
696
|
|
|
* |
697
|
|
|
* @return string |
698
|
|
|
*/ |
699
|
|
|
public static function getPageNumberItem( |
700
|
|
|
$pageNumber, |
701
|
|
|
$pageLength, |
702
|
|
|
$liAttributes = [], |
703
|
|
|
$content = '' |
704
|
|
|
) { |
705
|
|
|
// Get page URL |
706
|
|
|
$url = self::getCourseCategoryUrl( |
707
|
|
|
$pageNumber, |
708
|
|
|
$pageLength |
709
|
|
|
); |
710
|
|
|
|
711
|
|
|
// If is current page ('active' class) clear URL |
712
|
|
|
if (isset($liAttributes) && is_array($liAttributes) && isset($liAttributes['class'])) { |
713
|
|
|
if (false !== strpos('active', $liAttributes['class'])) { |
714
|
|
|
$url = ''; |
715
|
|
|
} |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
$content = !empty($content) ? $content : $pageNumber; |
719
|
|
|
|
720
|
|
|
return Display::tag( |
721
|
|
|
'li', |
722
|
|
|
Display::url( |
723
|
|
|
$content, |
724
|
|
|
$url, |
725
|
|
|
['class' => 'page-link'] |
726
|
|
|
), |
727
|
|
|
$liAttributes |
728
|
|
|
); |
729
|
|
|
} |
730
|
|
|
|
731
|
|
|
/** |
732
|
|
|
* Return URL to course catalog. |
733
|
|
|
* |
734
|
|
|
* @param int $pageCurrent |
735
|
|
|
* @param int $pageLength |
736
|
|
|
* @param string $categoryCode |
737
|
|
|
* @param int $hiddenLinks |
738
|
|
|
* @param string $action |
739
|
|
|
* |
740
|
|
|
* @return string |
741
|
|
|
*/ |
742
|
|
|
public static function getCourseCategoryUrl( |
743
|
|
|
$pageCurrent, |
744
|
|
|
$pageLength, |
745
|
|
|
$categoryCode = null, |
746
|
|
|
$hiddenLinks = null, |
747
|
|
|
$action = null |
748
|
|
|
) { |
749
|
|
|
$requestAction = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : null; |
750
|
|
|
$action = isset($action) ? Security::remove_XSS($action) : $requestAction; |
751
|
|
|
$searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : null; |
752
|
|
|
|
753
|
|
|
if ('subscribe_user_with_password' === $action) { |
754
|
|
|
$action = 'subscribe'; |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
$categoryCodeRequest = isset($_REQUEST['category_code']) ? Security::remove_XSS( |
758
|
|
|
$_REQUEST['category_code'] |
759
|
|
|
) : null; |
760
|
|
|
$categoryCode = isset($categoryCode) ? Security::remove_XSS($categoryCode) : $categoryCodeRequest; |
761
|
|
|
$hiddenLinksRequest = isset($_REQUEST['hidden_links']) ? Security::remove_XSS($_REQUEST['hidden_links']) : null; |
762
|
|
|
$hiddenLinks = isset($hiddenLinks) ? Security::remove_XSS($hiddenLinksRequest) : $categoryCodeRequest; |
763
|
|
|
|
764
|
|
|
// Start URL with params |
765
|
|
|
$pageUrl = api_get_self(). |
766
|
|
|
'?action='.$action. |
|
|
|
|
767
|
|
|
'&category_code='.$categoryCode. |
|
|
|
|
768
|
|
|
'&hidden_links='.$hiddenLinks. |
|
|
|
|
769
|
|
|
'&pageCurrent='.$pageCurrent. |
770
|
|
|
'&pageLength='.$pageLength; |
771
|
|
|
|
772
|
|
|
switch ($action) { |
773
|
|
|
case 'subscribe': |
774
|
|
|
// for search |
775
|
|
|
$pageUrl .= |
776
|
|
|
'&search_term='.$searchTerm. |
|
|
|
|
777
|
|
|
'&search_course=1'. |
778
|
|
|
'&sec_token='.Security::getTokenFromSession(); |
779
|
|
|
break; |
780
|
|
|
case 'display_courses': |
781
|
|
|
default: |
782
|
|
|
break; |
783
|
|
|
} |
784
|
|
|
|
785
|
|
|
return $pageUrl; |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
/** |
789
|
|
|
* Return the name tool by action. |
790
|
|
|
* |
791
|
|
|
* @param string $action |
792
|
|
|
* |
793
|
|
|
* @return string |
794
|
|
|
*/ |
795
|
|
|
public static function getCourseCatalogNameTools($action) |
796
|
|
|
{ |
797
|
|
|
$nameTools = get_lang('My courses'); |
798
|
|
|
if (empty($action)) { |
799
|
|
|
return $nameTools; //should never happen |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
switch ($action) { |
803
|
|
|
case 'subscribe': |
804
|
|
|
case 'subscribe_user_with_password': |
805
|
|
|
case 'display_random_courses': |
806
|
|
|
case 'display_courses': |
807
|
|
|
$nameTools = get_lang('Courses catalog'); |
808
|
|
|
break; |
809
|
|
|
case 'display_sessions': |
810
|
|
|
$nameTools = get_lang('Course sessions'); |
811
|
|
|
break; |
812
|
|
|
default: |
813
|
|
|
// Nothing to do |
814
|
|
|
break; |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
return $nameTools; |
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
/** |
821
|
|
|
* Save image for a course category. |
822
|
|
|
* |
823
|
|
|
* @param array $fileData File data from $_FILES |
824
|
|
|
*/ |
825
|
|
|
public static function saveImage(CourseCategoryEntity $category, $fileData, $crop = '') |
826
|
|
|
{ |
827
|
|
|
if (isset($fileData['tmp_name']) && !empty($fileData['tmp_name'])) { |
828
|
|
|
$repo = Container::getCourseCategoryRepository(); |
829
|
|
|
$repo->deleteAsset($category); |
830
|
|
|
|
831
|
|
|
$assetRepo = Container::getAssetRepository(); |
832
|
|
|
$asset = (new Asset()) |
833
|
|
|
->setCategory(Asset::COURSE_CATEGORY) |
834
|
|
|
->setTitle($fileData['name']) |
835
|
|
|
->setCrop($crop) |
836
|
|
|
; |
837
|
|
|
$asset = $assetRepo->createFromRequest($asset, $fileData); |
838
|
|
|
|
839
|
|
|
$category->setAsset($asset); |
840
|
|
|
$repo->save($category); |
841
|
|
|
} |
842
|
|
|
} |
843
|
|
|
} |
844
|
|
|
|