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\Entity\User; |
8
|
|
|
use Chamilo\CoreBundle\Framework\Container; |
9
|
|
|
use Doctrine\Common\Collections\Criteria; |
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) |
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_array($result, 'ASSOC'); |
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_array($result, 'ASSOC'); |
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 = api_get_configuration_value('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.name, |
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.name, |
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
|
|
|
->setName($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 && 0 != $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 delete($categoryId): bool |
209
|
|
|
{ |
210
|
|
|
$repo = Container::getCourseCategoryRepository(); |
211
|
|
|
$category = $repo->find($categoryId); |
212
|
|
|
if (null === $category) { |
213
|
|
|
return false; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$repo->delete($category); |
217
|
|
|
|
218
|
|
|
return true; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
public static function edit($categoryId, $name, $canHaveCourses, $code, $description): CourseCategoryEntity |
222
|
|
|
{ |
223
|
|
|
$name = trim(Database::escape_string($name)); |
224
|
|
|
$canHaveCourses = Database::escape_string($canHaveCourses); |
225
|
|
|
|
226
|
|
|
$repo = Container::getCourseCategoryRepository(); |
227
|
|
|
$category = $repo->find($categoryId); |
228
|
|
|
|
229
|
|
|
$category |
230
|
|
|
->setCode($name) |
231
|
|
|
->setName($name) |
232
|
|
|
->setDescription($description) |
233
|
|
|
->setAuthCourseChild($canHaveCourses) |
234
|
|
|
; |
235
|
|
|
|
236
|
|
|
$repo->save($category); |
237
|
|
|
|
238
|
|
|
// Updating children |
239
|
|
|
/*$sql = "UPDATE $tbl_category SET parent_id = '$code' |
240
|
|
|
WHERE parent_id = '$old_code'"; |
241
|
|
|
Database::query($sql);*/ |
242
|
|
|
|
243
|
|
|
return $category; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Move a node up on display. |
248
|
|
|
* |
249
|
|
|
* @param string $code |
250
|
|
|
* @param int $tree_pos |
251
|
|
|
* @param string $parent_id |
252
|
|
|
* |
253
|
|
|
* @return bool |
254
|
|
|
*/ |
255
|
|
|
public static function moveNodeUp($code, $tree_pos, $parent_id) |
256
|
|
|
{ |
257
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
258
|
|
|
$code = Database::escape_string($code); |
259
|
|
|
$tree_pos = (int) $tree_pos; |
260
|
|
|
$parent_id = Database::escape_string($parent_id); |
261
|
|
|
|
262
|
|
|
$parentIdCondition = " AND (parent_id IS NULL OR parent_id = '' )"; |
263
|
|
|
if (!empty($parent_id)) { |
264
|
|
|
$parentIdCondition = " AND parent_id = '$parent_id' "; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
$sql = "SELECT code,tree_pos |
268
|
|
|
FROM $table |
269
|
|
|
WHERE |
270
|
|
|
tree_pos < $tree_pos |
271
|
|
|
$parentIdCondition |
272
|
|
|
ORDER BY tree_pos DESC |
273
|
|
|
LIMIT 0,1"; |
274
|
|
|
|
275
|
|
|
$result = Database::query($sql); |
276
|
|
|
if (!$row = Database::fetch_array($result)) { |
277
|
|
|
$sql = "SELECT code, tree_pos |
278
|
|
|
FROM $table |
279
|
|
|
WHERE |
280
|
|
|
tree_pos > $tree_pos |
281
|
|
|
$parentIdCondition |
282
|
|
|
ORDER BY tree_pos DESC |
283
|
|
|
LIMIT 0,1"; |
284
|
|
|
$result2 = Database::query($sql); |
285
|
|
|
if (!$row = Database::fetch_array($result2)) { |
286
|
|
|
return false; |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
$sql = "UPDATE $table |
291
|
|
|
SET tree_pos ='".$row['tree_pos']."' |
292
|
|
|
WHERE code='$code'"; |
293
|
|
|
Database::query($sql); |
294
|
|
|
|
295
|
|
|
$sql = "UPDATE $table |
296
|
|
|
SET tree_pos = '$tree_pos' |
297
|
|
|
WHERE code= '".$row['code']."'"; |
298
|
|
|
Database::query($sql); |
299
|
|
|
|
300
|
|
|
return true; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* @param string $categoryCode |
305
|
|
|
* |
306
|
|
|
* @return array |
307
|
|
|
*/ |
308
|
|
|
public static function getChildren($categoryCode) |
309
|
|
|
{ |
310
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
311
|
|
|
$categoryCode = Database::escape_string($categoryCode); |
312
|
|
|
$sql = "SELECT code, id FROM $table |
313
|
|
|
WHERE parent_id = '$categoryCode'"; |
314
|
|
|
$result = Database::query($sql); |
315
|
|
|
$children = []; |
316
|
|
|
while ($row = Database::fetch_array($result, 'ASSOC')) { |
317
|
|
|
$children[] = $row; |
318
|
|
|
$subChildren = self::getChildren($row['code']); |
319
|
|
|
$children = array_merge($children, $subChildren); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
return $children; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* @param string $categoryCode |
327
|
|
|
* |
328
|
|
|
* @return string|null |
329
|
|
|
*/ |
330
|
|
|
public static function getParentsToString($categoryCode) |
331
|
|
|
{ |
332
|
|
|
$parents = self::getParents($categoryCode); |
333
|
|
|
|
334
|
|
|
if (!empty($parents)) { |
335
|
|
|
$parents = array_reverse($parents); |
336
|
|
|
$categories = []; |
337
|
|
|
foreach ($parents as $category) { |
338
|
|
|
$categories[] = $category['code']; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
return implode(' > ', $categories).' > '; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
return null; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* @param string $categoryCode |
349
|
|
|
* |
350
|
|
|
* @return array |
351
|
|
|
*/ |
352
|
|
|
public static function getParents($categoryCode) |
353
|
|
|
{ |
354
|
|
|
if (empty($categoryCode)) { |
355
|
|
|
return []; |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
359
|
|
|
$categoryCode = Database::escape_string($categoryCode); |
360
|
|
|
$sql = "SELECT code, parent_id |
361
|
|
|
FROM $table |
362
|
|
|
WHERE code = '$categoryCode'"; |
363
|
|
|
|
364
|
|
|
$result = Database::query($sql); |
365
|
|
|
$children = []; |
366
|
|
|
while ($row = Database::fetch_array($result, 'ASSOC')) { |
367
|
|
|
$parent = self::getCategory($row['parent_id']); |
368
|
|
|
$children[] = $row; |
369
|
|
|
$subChildren = self::getParents($parent ? $parent['code'] : null); |
370
|
|
|
$children = array_merge($children, $subChildren); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
return $children; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
public static function listCategories(array $categorySource = []): string |
377
|
|
|
{ |
378
|
|
|
$categories = self::getCategories($categorySource ? $categorySource['id'] : null); |
379
|
|
|
$categoryCode = $categorySource ? Security::remove_XSS($categorySource['code']) : ''; |
380
|
|
|
|
381
|
|
|
if (count($categories) > 0) { |
382
|
|
|
$table = new HTML_Table(['class' => 'data_table']); |
383
|
|
|
$column = 0; |
384
|
|
|
$row = 0; |
385
|
|
|
$headers = [ |
386
|
|
|
get_lang('Category'), |
387
|
|
|
get_lang('Sub-categories'), |
388
|
|
|
get_lang('Courses'), |
389
|
|
|
get_lang('Detail'), |
390
|
|
|
]; |
391
|
|
|
foreach ($headers as $header) { |
392
|
|
|
$table->setHeaderContents($row, $column, $header); |
393
|
|
|
$column++; |
394
|
|
|
} |
395
|
|
|
$row++; |
396
|
|
|
$mainUrl = api_get_path(WEB_CODE_PATH).'admin/course_category.php?category='.$categoryCode; |
|
|
|
|
397
|
|
|
|
398
|
|
|
$editIcon = Display::return_icon( |
399
|
|
|
'edit.png', |
400
|
|
|
get_lang('Edit'), |
401
|
|
|
null, |
402
|
|
|
ICON_SIZE_SMALL |
403
|
|
|
); |
404
|
|
|
$exportIcon = Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), ''); |
405
|
|
|
$deleteIcon = Display::return_icon( |
406
|
|
|
'delete.png', |
407
|
|
|
get_lang('Delete'), |
408
|
|
|
null, |
409
|
|
|
ICON_SIZE_SMALL |
410
|
|
|
); |
411
|
|
|
$moveIcon = Display::return_icon( |
412
|
|
|
'up.png', |
413
|
|
|
get_lang('Up in same level'), |
414
|
|
|
null, |
415
|
|
|
ICON_SIZE_SMALL |
416
|
|
|
); |
417
|
|
|
|
418
|
|
|
$urlId = api_get_current_access_url_id(); |
419
|
|
|
foreach ($categories as $category) { |
420
|
|
|
$categoryId = $category->getId(); |
421
|
|
|
$code = $category->getCode(); |
422
|
|
|
$editUrl = $mainUrl.'&id='.$categoryId.'&action=edit'; |
423
|
|
|
$moveUrl = $mainUrl.'&id='.$categoryId.'&action=moveUp&tree_pos='.$category->getTreePos(); |
424
|
|
|
$deleteUrl = $mainUrl.'&id='.$categoryId.'&action=delete'; |
425
|
|
|
$exportUrl = $mainUrl.'&id='.$categoryId.'&action=export'; |
426
|
|
|
|
427
|
|
|
$actions = []; |
428
|
|
|
$criteria = Criteria::create(); |
429
|
|
|
$criteria->where(Criteria::expr()->eq('status', User::STUDENT)); |
430
|
|
|
|
431
|
|
|
$inUrl = $category->getUrls()->filter( |
432
|
|
|
function ($entry) use ($urlId) { |
433
|
|
|
return $entry->getUrl()->getId() === $urlId; |
434
|
|
|
} |
435
|
|
|
); |
436
|
|
|
|
437
|
|
|
if ($inUrl->count() > 0) { |
438
|
|
|
$actions[] = Display::url($editIcon, $editUrl); |
439
|
|
|
$actions[] = Display::url($moveIcon, $moveUrl); |
440
|
|
|
$actions[] = Display::url($exportIcon, $exportUrl); |
441
|
|
|
$actions[] = Display::url( |
442
|
|
|
$deleteIcon, |
443
|
|
|
$deleteUrl, |
444
|
|
|
[ |
445
|
|
|
'onclick' |
446
|
|
|
=> |
447
|
|
|
'javascript: if (!confirm(\''.addslashes( |
448
|
|
|
api_htmlentities(sprintf(get_lang('Please confirm your choice')), ENT_QUOTES) |
449
|
|
|
).'\')) return false;', |
450
|
|
|
] |
451
|
|
|
); |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
$url = api_get_path(WEB_CODE_PATH).'admin/course_category.php?id='.$categoryId; |
455
|
|
|
$title = Display::url( |
456
|
|
|
Display::return_icon( |
457
|
|
|
'folder_document.gif', |
458
|
|
|
get_lang('Open this category'), |
459
|
|
|
null, |
460
|
|
|
ICON_SIZE_SMALL |
461
|
|
|
).' '.$category->getName().' ('.$code.')', |
462
|
|
|
$url |
463
|
|
|
); |
464
|
|
|
|
465
|
|
|
$countCourses = $category->getCourses()->count(); |
466
|
|
|
$content = [ |
467
|
|
|
$title, |
468
|
|
|
$category->getChildrenCount(), |
469
|
|
|
$countCourses, |
470
|
|
|
implode('', $actions), |
471
|
|
|
]; |
472
|
|
|
$column = 0; |
473
|
|
|
foreach ($content as $value) { |
474
|
|
|
$table->setCellContents($row, $column, $value); |
475
|
|
|
$column++; |
476
|
|
|
} |
477
|
|
|
$row++; |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
return $table->toHtml(); |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
return Display::return_message(get_lang('There are no categories here'), 'warning'); |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* @param int|null $category Optional. Parent category ID. |
488
|
|
|
* |
489
|
|
|
* @return CourseCategoryEntity[] |
490
|
|
|
*/ |
491
|
|
|
public static function getCategories($category = null) |
492
|
|
|
{ |
493
|
|
|
$repo = Container::getCourseCategoryRepository(); |
494
|
|
|
$category = (int) $category; |
495
|
|
|
|
496
|
|
|
return $repo->findAllInAccessUrl( |
497
|
|
|
api_get_current_access_url_id(), |
498
|
|
|
api_get_configuration_value('allow_base_course_category'), |
499
|
|
|
$category |
500
|
|
|
); |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* @return array |
505
|
|
|
*/ |
506
|
|
|
public static function getCategoriesToDisplayInHomePage() |
507
|
|
|
{ |
508
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
509
|
|
|
$sql = "SELECT name FROM $table |
510
|
|
|
WHERE parent_id IS NULL |
511
|
|
|
ORDER BY tree_pos"; |
512
|
|
|
|
513
|
|
|
return Database::store_result(Database::query($sql)); |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
/** |
517
|
|
|
* @param string $categoryCode |
518
|
|
|
* |
519
|
|
|
* @return array |
520
|
|
|
*/ |
521
|
|
|
public static function getCategoriesCanBeAddedInCourse($categoryCode) |
522
|
|
|
{ |
523
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
524
|
|
|
$conditions = " INNER JOIN $table a ON (c.id = a.course_category_id)"; |
525
|
|
|
$whereCondition = ' AND a.access_url_id = '.api_get_current_access_url_id(); |
526
|
|
|
|
527
|
|
|
$tbl_category = Database::get_main_table(TABLE_MAIN_CATEGORY); |
528
|
|
|
$sql = "SELECT c.id, c.code, name |
529
|
|
|
FROM $tbl_category c |
530
|
|
|
$conditions |
531
|
|
|
WHERE (auth_course_child = 'TRUE' OR code = '".Database::escape_string($categoryCode)."') |
532
|
|
|
$whereCondition |
533
|
|
|
ORDER BY tree_pos"; |
534
|
|
|
$res = Database::query($sql); |
535
|
|
|
|
536
|
|
|
$categoryToAvoid = ''; |
537
|
|
|
if (!api_is_platform_admin()) { |
538
|
|
|
$categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model'); |
539
|
|
|
} |
540
|
|
|
$categories[''] = '-'; |
|
|
|
|
541
|
|
|
while ($cat = Database::fetch_array($res)) { |
542
|
|
|
$categoryCode = $cat['code']; |
543
|
|
|
if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) { |
544
|
|
|
continue; |
545
|
|
|
} |
546
|
|
|
$categories[$cat['id']] = '('.$cat['code'].') '.$cat['name']; |
547
|
|
|
ksort($categories); |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
return $categories; |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
/** |
554
|
|
|
* @param string $category_code |
555
|
|
|
* @param string $keyword |
556
|
|
|
* |
557
|
|
|
* @paran bool $avoidCourses |
558
|
|
|
* @paran array $conditions |
559
|
|
|
* |
560
|
|
|
* @return int |
561
|
|
|
*/ |
562
|
|
|
public static function countCoursesInCategory( |
563
|
|
|
$category_code = '', |
564
|
|
|
$keyword = '', |
565
|
|
|
$avoidCourses = true, |
566
|
|
|
$conditions = [] |
567
|
|
|
) { |
568
|
|
|
return self::getCoursesInCategory($category_code, $keyword, $avoidCourses, $conditions, true); |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* @return \Chamilo\CoreBundle\Entity\Course[] |
573
|
|
|
*/ |
574
|
|
|
public static function getCoursesInCategory( |
575
|
|
|
$categoryId, |
576
|
|
|
$keyword = '', |
577
|
|
|
$avoidCourses = true, |
578
|
|
|
$conditions = [], |
579
|
|
|
$getCount = false |
580
|
|
|
) { |
581
|
|
|
$repo = Container::getCourseCategoryRepository(); |
582
|
|
|
/** @var CourseCategoryEntity $category */ |
583
|
|
|
$category = $repo->find($categoryId); |
584
|
|
|
|
585
|
|
|
// @todo add filters |
586
|
|
|
|
587
|
|
|
return $category->getCourses(); |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
/** |
591
|
|
|
* @param array $list |
592
|
|
|
* |
593
|
|
|
* @return array |
594
|
|
|
*/ |
595
|
|
|
public static function getCourseCategoryNotInList($list) |
596
|
|
|
{ |
597
|
|
|
$table = Database::get_main_table(TABLE_MAIN_CATEGORY); |
598
|
|
|
|
599
|
|
|
if (empty($list)) { |
600
|
|
|
$sql = "SELECT * FROM $table |
601
|
|
|
WHERE (parent_id IS NULL) "; |
602
|
|
|
$result = Database::query($sql); |
603
|
|
|
|
604
|
|
|
return Database::store_result($result, 'ASSOC'); |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
$list = array_map('intval', $list); |
608
|
|
|
$listToString = implode("','", $list); |
609
|
|
|
|
610
|
|
|
$sql = "SELECT * FROM $table |
611
|
|
|
WHERE id NOT IN ('$listToString') AND (parent_id IS NULL) "; |
612
|
|
|
$result = Database::query($sql); |
613
|
|
|
|
614
|
|
|
return Database::store_result($result, 'ASSOC'); |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
/** |
618
|
|
|
* @param string $keyword |
619
|
|
|
* |
620
|
|
|
* @return array|null |
621
|
|
|
*/ |
622
|
|
|
public static function searchCategoryByKeyword($keyword) |
623
|
|
|
{ |
624
|
|
|
if (empty($keyword)) { |
625
|
|
|
return null; |
626
|
|
|
} |
627
|
|
|
|
628
|
|
|
$tableCategory = Database::get_main_table(TABLE_MAIN_CATEGORY); |
629
|
|
|
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY); |
630
|
|
|
$conditions = " INNER JOIN $table a ON (c.id = a.course_category_id)"; |
631
|
|
|
$whereCondition = " AND a.access_url_id = ".api_get_current_access_url_id(); |
632
|
|
|
|
633
|
|
|
$allowBaseCategories = api_get_configuration_value('allow_base_course_category'); |
634
|
|
|
if ($allowBaseCategories) { |
635
|
|
|
$whereCondition = " AND (a.access_url_id = ".api_get_current_access_url_id()." OR a.access_url_id = 1) "; |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
$keyword = Database::escape_string($keyword); |
639
|
|
|
|
640
|
|
|
$sql = "SELECT c.*, c.name as text |
641
|
|
|
FROM $tableCategory c $conditions |
642
|
|
|
WHERE |
643
|
|
|
( |
644
|
|
|
c.code LIKE '%$keyword%' OR name LIKE '%$keyword%' |
645
|
|
|
) AND auth_course_child = 'TRUE' |
646
|
|
|
$whereCondition "; |
647
|
|
|
$result = Database::query($sql); |
648
|
|
|
|
649
|
|
|
return Database::store_result($result, 'ASSOC'); |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
/** |
653
|
|
|
* Get Pagination HTML div. |
654
|
|
|
* |
655
|
|
|
* @param $pageCurrent |
656
|
|
|
* @param $pageLength |
657
|
|
|
* @param $pageTotal |
658
|
|
|
* |
659
|
|
|
* @return string |
660
|
|
|
*/ |
661
|
|
|
public static function getCatalogPagination($pageCurrent, $pageLength, $pageTotal) |
662
|
|
|
{ |
663
|
|
|
// Start empty html |
664
|
|
|
$pageDiv = ''; |
665
|
|
|
$html = ''; |
666
|
|
|
$pageBottom = max(1, $pageCurrent - 3); |
667
|
|
|
$pageTop = min($pageTotal, $pageCurrent + 3); |
668
|
|
|
|
669
|
|
|
if ($pageBottom > 1) { |
670
|
|
|
$pageDiv .= self::getPageNumberItem(1, $pageLength); |
671
|
|
|
if ($pageBottom > 2) { |
672
|
|
|
$pageDiv .= self::getPageNumberItem( |
673
|
|
|
$pageBottom - 1, |
674
|
|
|
$pageLength, |
675
|
|
|
null, |
676
|
|
|
'...' |
677
|
|
|
); |
678
|
|
|
} |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
// For each page add its page button to html |
682
|
|
|
for ($i = $pageBottom; $i <= $pageTop; $i++) { |
683
|
|
|
if ($i === $pageCurrent) { |
684
|
|
|
$pageItemAttributes = ['class' => 'page-item active']; |
685
|
|
|
} else { |
686
|
|
|
$pageItemAttributes = ['class' => 'page-item']; |
687
|
|
|
} |
688
|
|
|
$pageDiv .= self::getPageNumberItem( |
689
|
|
|
$i, |
690
|
|
|
$pageLength, |
691
|
|
|
$pageItemAttributes |
692
|
|
|
); |
693
|
|
|
} |
694
|
|
|
|
695
|
|
|
// Check if current page is the last page |
696
|
|
|
if ($pageTop < $pageTotal) { |
697
|
|
|
if ($pageTop < ($pageTotal - 1)) { |
698
|
|
|
$pageDiv .= self::getPageNumberItem( |
699
|
|
|
$pageTop + 1, |
700
|
|
|
$pageLength, |
701
|
|
|
null, |
702
|
|
|
'...' |
703
|
|
|
); |
704
|
|
|
} |
705
|
|
|
$pageDiv .= self::getPageNumberItem($pageTotal, $pageLength); |
706
|
|
|
} |
707
|
|
|
|
708
|
|
|
// Complete pagination html |
709
|
|
|
$pageDiv = Display::tag('ul', $pageDiv, ['class' => 'pagination']); |
710
|
|
|
$html .= '<nav>'.$pageDiv.'</nav>'; |
711
|
|
|
|
712
|
|
|
return $html; |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
/** |
716
|
|
|
* Get li HTML of page number. |
717
|
|
|
* |
718
|
|
|
* @param $pageNumber |
719
|
|
|
* @param $pageLength |
720
|
|
|
* @param array $liAttributes |
721
|
|
|
* @param string $content |
722
|
|
|
* |
723
|
|
|
* @return string |
724
|
|
|
*/ |
725
|
|
|
public static function getPageNumberItem( |
726
|
|
|
$pageNumber, |
727
|
|
|
$pageLength, |
728
|
|
|
$liAttributes = [], |
729
|
|
|
$content = '' |
730
|
|
|
) { |
731
|
|
|
// Get page URL |
732
|
|
|
$url = self::getCourseCategoryUrl( |
733
|
|
|
$pageNumber, |
734
|
|
|
$pageLength |
735
|
|
|
); |
736
|
|
|
|
737
|
|
|
// If is current page ('active' class) clear URL |
738
|
|
|
if (isset($liAttributes) && is_array($liAttributes) && isset($liAttributes['class'])) { |
739
|
|
|
if (false !== strpos('active', $liAttributes['class'])) { |
740
|
|
|
$url = ''; |
741
|
|
|
} |
742
|
|
|
} |
743
|
|
|
|
744
|
|
|
$content = !empty($content) ? $content : $pageNumber; |
745
|
|
|
|
746
|
|
|
return Display::tag( |
747
|
|
|
'li', |
748
|
|
|
Display::url( |
749
|
|
|
$content, |
750
|
|
|
$url, |
751
|
|
|
['class' => 'page-link'] |
752
|
|
|
), |
753
|
|
|
$liAttributes |
754
|
|
|
); |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
/** |
758
|
|
|
* Return URL to course catalog. |
759
|
|
|
* |
760
|
|
|
* @param int $pageCurrent |
761
|
|
|
* @param int $pageLength |
762
|
|
|
* @param string $categoryCode |
763
|
|
|
* @param int $hiddenLinks |
764
|
|
|
* @param string $action |
765
|
|
|
* |
766
|
|
|
* @return string |
767
|
|
|
*/ |
768
|
|
|
public static function getCourseCategoryUrl( |
769
|
|
|
$pageCurrent, |
770
|
|
|
$pageLength, |
771
|
|
|
$categoryCode = null, |
772
|
|
|
$hiddenLinks = null, |
773
|
|
|
$action = null |
774
|
|
|
) { |
775
|
|
|
$requestAction = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : null; |
776
|
|
|
$action = isset($action) ? Security::remove_XSS($action) : $requestAction; |
777
|
|
|
$searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : null; |
778
|
|
|
|
779
|
|
|
if ('subscribe_user_with_password' === $action) { |
780
|
|
|
$action = 'subscribe'; |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
$categoryCodeRequest = isset($_REQUEST['category_code']) ? Security::remove_XSS( |
784
|
|
|
$_REQUEST['category_code'] |
785
|
|
|
) : null; |
786
|
|
|
$categoryCode = isset($categoryCode) ? Security::remove_XSS($categoryCode) : $categoryCodeRequest; |
787
|
|
|
$hiddenLinksRequest = isset($_REQUEST['hidden_links']) ? Security::remove_XSS($_REQUEST['hidden_links']) : null; |
788
|
|
|
$hiddenLinks = isset($hiddenLinks) ? Security::remove_XSS($hiddenLinksRequest) : $categoryCodeRequest; |
789
|
|
|
|
790
|
|
|
// Start URL with params |
791
|
|
|
$pageUrl = api_get_self(). |
792
|
|
|
'?action='.$action. |
|
|
|
|
793
|
|
|
'&category_code='.$categoryCode. |
|
|
|
|
794
|
|
|
'&hidden_links='.$hiddenLinks. |
|
|
|
|
795
|
|
|
'&pageCurrent='.$pageCurrent. |
796
|
|
|
'&pageLength='.$pageLength; |
797
|
|
|
|
798
|
|
|
switch ($action) { |
799
|
|
|
case 'subscribe': |
800
|
|
|
// for search |
801
|
|
|
$pageUrl .= |
802
|
|
|
'&search_term='.$searchTerm. |
|
|
|
|
803
|
|
|
'&search_course=1'. |
804
|
|
|
'&sec_token='.Security::getTokenFromSession(); |
805
|
|
|
break; |
806
|
|
|
case 'display_courses': |
807
|
|
|
default: |
808
|
|
|
break; |
809
|
|
|
} |
810
|
|
|
|
811
|
|
|
return $pageUrl; |
812
|
|
|
} |
813
|
|
|
|
814
|
|
|
/** |
815
|
|
|
* Return the name tool by action. |
816
|
|
|
* |
817
|
|
|
* @param string $action |
818
|
|
|
* |
819
|
|
|
* @return string |
820
|
|
|
*/ |
821
|
|
|
public static function getCourseCatalogNameTools($action) |
822
|
|
|
{ |
823
|
|
|
$nameTools = get_lang('My courses'); |
824
|
|
|
if (empty($action)) { |
825
|
|
|
return $nameTools; //should never happen |
826
|
|
|
} |
827
|
|
|
|
828
|
|
|
switch ($action) { |
829
|
|
|
case 'subscribe': |
830
|
|
|
case 'subscribe_user_with_password': |
831
|
|
|
case 'display_random_courses': |
832
|
|
|
case 'display_courses': |
833
|
|
|
$nameTools = get_lang('Courses catalog'); |
834
|
|
|
break; |
835
|
|
|
case 'display_sessions': |
836
|
|
|
$nameTools = get_lang('Course sessions'); |
837
|
|
|
break; |
838
|
|
|
default: |
839
|
|
|
// Nothing to do |
840
|
|
|
break; |
841
|
|
|
} |
842
|
|
|
|
843
|
|
|
return $nameTools; |
844
|
|
|
} |
845
|
|
|
|
846
|
|
|
public static function deleteImage(CourseCategoryEntity $category) |
847
|
|
|
{ |
848
|
|
|
$assetId = $category->getImage(); |
849
|
|
|
if (empty($assetId)) { |
850
|
|
|
return false; |
851
|
|
|
} |
852
|
|
|
|
853
|
|
|
$assetRepo = Container::getAssetRepository(); |
854
|
|
|
/** @var Asset $asset */ |
855
|
|
|
$asset = $assetRepo->find($assetId); |
856
|
|
|
if (null !== $asset) { |
857
|
|
|
$category->setImage(''); |
858
|
|
|
$assetRepo->delete($asset); |
859
|
|
|
$repo = Container::getCourseCategoryRepository(); |
860
|
|
|
$repo->save($category); |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
return true; |
864
|
|
|
} |
865
|
|
|
|
866
|
|
|
/** |
867
|
|
|
* Save image for a course category. |
868
|
|
|
* |
869
|
|
|
* @param array $fileData File data from $_FILES |
870
|
|
|
*/ |
871
|
|
|
public static function saveImage(CourseCategoryEntity $category, $fileData, $crop = '') |
872
|
|
|
{ |
873
|
|
|
if (isset($fileData['tmp_name']) && !empty($fileData['tmp_name'])) { |
874
|
|
|
self::deleteImage($category); |
875
|
|
|
|
876
|
|
|
$repo = Container::getAssetRepository(); |
877
|
|
|
$asset = new Asset(); |
878
|
|
|
$asset |
879
|
|
|
->setCategory(Asset::COURSE_CATEGORY) |
880
|
|
|
->setTitle($fileData['name']) |
881
|
|
|
->setCrop($crop) |
882
|
|
|
; |
883
|
|
|
$asset = $repo->createFromRequest($asset, $fileData); |
884
|
|
|
|
885
|
|
|
$category->setImage($asset->getId()); |
886
|
|
|
$repo = Container::getCourseCategoryRepository(); |
887
|
|
|
$repo->save($category); |
888
|
|
|
} |
889
|
|
|
} |
890
|
|
|
} |
891
|
|
|
|