Skip to content

Commit 3f4c2fc

Browse files
Merge pull request #7129 from christianbeeznest/fixes-updates191
Course: Fix course tool drag-and-drop ordering persistence
2 parents 2d478ee + b4a8725 commit 3f4c2fc

File tree

3 files changed

+130
-26
lines changed

3 files changed

+130
-26
lines changed

assets/vue/services/courseService.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ export default {
7373
* @returns {Promise<Object>}
7474
*/
7575
updateToolOrder: async (tool, newIndex, courseId, sessionId = 0) => {
76-
const { data } = await api.post(`/course/${courseId}/home.json?sid=${sessionId}`, {
76+
const payload = {
77+
toolId: tool.iid,
7778
index: newIndex,
78-
toolItem: tool,
79-
})
79+
}
80+
81+
const { data } = await api.post(`/course/${courseId}/home.json?sid=${sessionId}`, payload)
8082

8183
return data
8284
},

assets/vue/views/course/CourseHome.vue

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,18 +444,14 @@ watch(isSorting, (isSortingEnabled) => {
444444
})
445445
446446
async function updateDisplayOrder(htmlItem, newIndex) {
447-
const tool = htmlItem.dataset.tool
448-
let toolItem = null
449-
450-
if (typeof tools.value !== "undefined" && Array.isArray(tools.value)) {
451-
const toolList = tools.value
452-
toolItem = toolList.find((element) => element.title === tool)
453-
} else {
454-
console.error("Error: tools.value is undefined")
447+
const toolTitle = htmlItem.dataset.tool
448+
const toolItem = tools.value.find((element) => element.title === toolTitle)
449+
450+
if (!toolItem || !toolItem.iid) {
451+
console.error("[CourseHome] Tool item or iid missing", toolItem)
455452
return
456453
}
457454
458-
console.log(toolItem, newIndex)
459455
460456
// Send the updated values to the server
461457
await courseService.updateToolOrder(toolItem, newIndex, course.value.id, session.value?.id)

src/CoreBundle/Controller/CourseController.php

Lines changed: 120 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,27 @@ public function indexJson(
156156
EntityManagerInterface $em,
157157
AssetRepository $assetRepository
158158
): Response {
159-
$requestData = json_decode($request->getContent(), true);
160-
// Sort behaviour
161-
if (!empty($requestData) && isset($requestData['toolItem'])) {
162-
$index = $requestData['index'];
163-
$toolItem = $requestData['toolItem'];
164-
$toolId = (int) $toolItem['iid'];
165-
166-
/** @var CTool $cTool */
167-
$cTool = $em->find(CTool::class, $toolId);
168-
169-
if ($cTool) {
170-
$cTool->setPosition($index + 1);
171-
$em->persist($cTool);
172-
$em->flush();
159+
// Handle drag & drop sort for course tools
160+
if ($request->isMethod('POST')) {
161+
$requestData = json_decode($request->getContent() ?: '', true) ?? [];
162+
163+
if (isset($requestData['toolId'], $requestData['index'])) {
164+
$course = $this->getCourse();
165+
if (null === $course) {
166+
return $this->json(
167+
['success' => false, 'message' => 'Course not found.'],
168+
Response::HTTP_BAD_REQUEST
169+
);
170+
}
171+
172+
$sessionId = $this->getSessionId();
173+
$toolId = (int) $requestData['toolId'];
174+
$newIndex = (int) $requestData['index'];
175+
176+
$result = $this->reorderCourseTools($em, $course, $sessionId, $toolId, $newIndex);
177+
$statusCode = $result['success'] ? Response::HTTP_OK : Response::HTTP_BAD_REQUEST;
178+
179+
return $this->json($result, $statusCode);
173180
}
174181
}
175182

@@ -1317,4 +1324,103 @@ private function isUserEnrolledInAnySession(User $user, EntityManagerInterface $
13171324

13181325
return $enrollmentCount > 0;
13191326
}
1327+
1328+
/**
1329+
* Reorders all course tools for a given course / session after drag & drop.
1330+
*
1331+
* @return array<string, mixed>
1332+
*/
1333+
private function reorderCourseTools(
1334+
EntityManagerInterface $em,
1335+
Course $course,
1336+
int $sessionId,
1337+
int $toolId,
1338+
int $newIndex
1339+
): array {
1340+
if ($toolId <= 0) {
1341+
return [
1342+
'success' => false,
1343+
'message' => 'Invalid tool id.',
1344+
];
1345+
}
1346+
1347+
/** @var CToolRepository $toolRepo */
1348+
$toolRepo = $em->getRepository(CTool::class);
1349+
1350+
// Load all tools for this course + (optional) session ordered by current position
1351+
$qb = $toolRepo->createQueryBuilder('t')
1352+
->andWhere('t.course = :course')
1353+
->setParameter('course', $course)
1354+
->orderBy('t.position', 'ASC')
1355+
->addOrderBy('t.iid', 'ASC');
1356+
1357+
if ($sessionId > 0) {
1358+
$qb
1359+
->andWhere('IDENTITY(t.session) = :sessionId')
1360+
->setParameter('sessionId', $sessionId);
1361+
} else {
1362+
$qb->andWhere('t.session IS NULL');
1363+
}
1364+
1365+
/** @var CTool[] $tools */
1366+
$tools = $qb->getQuery()->getResult();
1367+
1368+
if (0 === \count($tools)) {
1369+
return [
1370+
'success' => false,
1371+
'message' => 'No tools found for course / session.',
1372+
];
1373+
}
1374+
1375+
// Build an array of IDs to manipulate positions easily
1376+
$ids = array_map(static fn (CTool $tool): int => $tool->getIid() ?? 0, $tools);
1377+
1378+
$currentIndex = array_search($toolId, $ids, true);
1379+
if (false === $currentIndex) {
1380+
return [
1381+
'success' => false,
1382+
'message' => 'Tool not found in current course / session.',
1383+
];
1384+
}
1385+
1386+
// Clamp the new index into a valid range
1387+
$newIndex = max(0, min($newIndex, \count($tools) - 1));
1388+
1389+
if ($newIndex === $currentIndex) {
1390+
return [
1391+
'success' => true,
1392+
'unchanged' => true,
1393+
'from' => $currentIndex,
1394+
'to' => $newIndex,
1395+
'total' => \count($tools),
1396+
];
1397+
}
1398+
1399+
// Move the ID in the array (remove at old index, insert at new index)
1400+
$idToMove = $ids[$currentIndex];
1401+
array_splice($ids, $currentIndex, 1);
1402+
array_splice($ids, $newIndex, 0, [$idToMove]);
1403+
1404+
// Rewrite all positions in DB using a simple DQL UPDATE per tool
1405+
// Positions will be 0-based: 0,1,2,...
1406+
foreach ($ids as $pos => $id) {
1407+
$em->createQueryBuilder()
1408+
->update(CTool::class, 't')
1409+
->set('t.position', ':pos')
1410+
->where('t.iid = :iid')
1411+
->setParameter('pos', $pos)
1412+
->setParameter('iid', $id)
1413+
->getQuery()
1414+
->execute();
1415+
}
1416+
1417+
return [
1418+
'success' => true,
1419+
'from' => $currentIndex,
1420+
'to' => $newIndex,
1421+
'total' => \count($tools),
1422+
'courseId' => $course->getId(),
1423+
'sessionId' => $sessionId,
1424+
];
1425+
}
13201426
}

0 commit comments

Comments
 (0)