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