Passed
Pull Request — master (#7139)
by
unknown
11:28
created

findLinkForResourceInContext()   B

Complexity

Conditions 7
Paths 33

Size

Total Lines 64
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 39
c 0
b 0
f 0
nc 33
nop 6
dl 0
loc 64
rs 8.3626

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Chamilo\CoreBundle\Entity\AbstractResource;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\ResourceLink;
12
use Chamilo\CoreBundle\Entity\ResourceNode;
13
use Chamilo\CoreBundle\Entity\ResourceType;
14
use Chamilo\CoreBundle\Entity\Session;
15
use Chamilo\CoreBundle\Entity\Tool;
16
use Chamilo\CoreBundle\Entity\User;
17
use Chamilo\CoreBundle\Entity\Usergroup;
18
use Chamilo\CourseBundle\Entity\CGroup;
19
use Doctrine\ORM\EntityManagerInterface;
20
use Gedmo\Sortable\Entity\Repository\SortableRepository;
21
22
/**
23
 * @template-extends SortableRepository<ResourceLink>
24
 */
25
class ResourceLinkRepository extends SortableRepository
26
{
27
    private array $toolList = [
28
        'course_description' => '/main/course_description/index.php',
29
        'document' => '/resources/document/%resource_node_id%/',
30
        'learnpath' => '/main/lp/lp_controller.php',
31
        'link' => '/resources/links/%resource_node_id%/',
32
        'quiz' => '/main/exercise/exercise.php',
33
        'announcement' => '/main/announcements/announcements.php',
34
        'glossary' => '/resources/glossary/%resource_node_id%/',
35
        'attendance' => '/main/attendance/index.php',
36
        'course_progress' => '/main/course_progress/index.php',
37
        'agenda' => '/resources/ccalendarevent',
38
        'forum' => '/main/forum/index.php',
39
        'student_publication' => '/resources/assignment/%resource_node_id%',
40
        'survey' => '/main/survey/survey_list.php',
41
        'notebook' => '/main/notebook/index.php',
42
    ];
43
44
    public function __construct(EntityManagerInterface $em)
45
    {
46
        parent::__construct($em, $em->getClassMetadata(ResourceLink::class));
47
    }
48
49
    public function remove(ResourceLink $resourceLink): void
50
    {
51
        $em = $this->getEntityManager();
52
53
        // To move the resource link at the end to reorder the list
54
        $resourceLink->setDisplayOrder(-1);
55
56
        $em->flush();
57
        // soft delete handled by Gedmo\SoftDeleteable
58
        $em->remove($resourceLink);
59
        $em->flush();
60
    }
61
62
    public function removeByResourceInContext(
63
        AbstractResource $resource,
64
        Course $course,
65
        ?Session $session = null,
66
        ?CGroup $group = null,
67
        ?Usergroup $usergroup = null,
68
        ?User $user = null,
69
    ): void {
70
        $link = $resource->getResourceNode()->getResourceLinkByContext($course, $session, $group, $usergroup, $user);
71
72
        if ($link) {
73
            $this->remove($link);
74
        }
75
    }
76
77
    /**
78
     * Retrieves the list of available tools filtered by a predefined tool list.
79
     *
80
     * @return array the list of tools with their IDs and titles
81
     */
82
    public function getAvailableTools(): array
83
    {
84
        $queryBuilder = $this->_em->createQueryBuilder();
85
        $queryBuilder
86
            ->select('DISTINCT t.id, t.title')
87
            ->from(ResourceLink::class, 'rl')
88
            ->innerJoin(ResourceType::class, 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
89
            ->innerJoin(Tool::class, 't', 'WITH', 't.id = rt.tool')
90
            ->where('rl.course IS NOT NULL')
91
            ->andWhere('t.title IN (:toolList)')
92
            ->setParameter('toolList', array_keys($this->toolList))
93
        ;
94
95
        $result = $queryBuilder->getQuery()->getArrayResult();
96
97
        $tools = [];
98
        foreach ($result as $row) {
99
            $tools[$row['id']] = ucfirst(str_replace('_', ' ', $row['title']));
100
        }
101
102
        return $tools;
103
    }
104
105
    /**
106
     * Retrieves a usage report of tools with dynamic links.
107
     *
108
     * @return array the tool usage data including counts, last update timestamps, and dynamic links
109
     */
110
    public function getToolUsageReportByTools(array $toolIds): array
111
    {
112
        $queryBuilder = $this->_em->createQueryBuilder();
113
114
        $queryBuilder
115
            ->select(
116
                'COUNT(rl.id) AS resource_count',
117
                'IDENTITY(rl.course) AS course_id',
118
                'IDENTITY(rl.session) AS session_id',
119
                'IDENTITY(c.resourceNode) AS course_resource_node_id',
120
                't.title AS tool_name',
121
                'c.title AS course_name',
122
                's.title AS session_name',
123
                'MAX(rl.updatedAt) AS last_updated'
124
            )
125
            ->from(ResourceLink::class, 'rl')
126
            ->innerJoin(ResourceType::class, 'rt', 'WITH', 'rt.id = rl.resourceTypeGroup')
127
            ->innerJoin(Tool::class, 't', 'WITH', 't.id = rt.tool')
128
            ->innerJoin(Course::class, 'c', 'WITH', 'c.id = rl.course')
129
            ->leftJoin(Session::class, 's', 'WITH', 's.id = rl.session')
130
            ->where($queryBuilder->expr()->in('t.id', ':toolIds'))
131
            ->groupBy('rl.course, rl.session, t.title')
132
            ->orderBy('t.title', 'ASC')
133
            ->addOrderBy('c.title', 'ASC')
134
            ->addOrderBy('s.title', 'ASC')
135
            ->setParameter('toolIds', $toolIds)
136
        ;
137
138
        $result = $queryBuilder->getQuery()->getArrayResult();
139
140
        return array_map(function ($row) {
141
            $toolName = $row['tool_name'];
142
            $baseLink = $this->toolList[$toolName] ?? null;
143
            $link = '-';
144
            if ($baseLink) {
145
                $link = str_replace(
146
                    ['%resource_node_id%'],
147
                    [$row['course_resource_node_id']],
148
                    $baseLink
149
                );
150
151
                $queryParams = [
152
                    'cid' => $row['course_id'],
153
                ];
154
155
                if (!empty($row['session_id'])) {
156
                    $queryParams['sid'] = $row['session_id'];
157
                }
158
159
                $link .= '?'.http_build_query($queryParams);
160
            }
161
162
            return [
163
                'tool_name' => $toolName,
164
                'session_id' => $row['session_id'],
165
                'session_name' => $row['session_name'] ?: '-',
166
                'course_id' => $row['course_id'],
167
                'course_name' => $row['course_name'],
168
                'resource_count' => (int) $row['resource_count'],
169
                'last_updated' => $row['last_updated'] ?: '-',
170
                'link' => $link,
171
            ];
172
        }, $result);
173
    }
174
175
    /**
176
     * Find the parent link (folder link) for a given parent node in a specific context.
177
     *
178
     * This is used when creating new document links so that the link hierarchy
179
     * is context-aware (course/session/group/usergroup/user).
180
     */
181
    public function findParentLinkForContext(
182
        ResourceNode $parentNode,
183
        ?Course $course,
184
        ?Session $session,
185
        ?CGroup $group,
186
        ?Usergroup $usergroup,
187
        ?User $user
188
    ): ?ResourceLink {
189
        $qb = $this->createQueryBuilder('rl')
190
            ->andWhere('rl.resourceNode = :parentNode')
191
            ->setParameter('parentNode', $parentNode)
192
            ->andWhere('rl.deletedAt IS NULL')
193
            ->setMaxResults(1);
194
195
        // Match course context
196
        if (null !== $course) {
197
            $qb
198
                ->andWhere('rl.course = :course')
199
                ->setParameter('course', $course);
200
        } else {
201
            $qb->andWhere('rl.course IS NULL');
202
        }
203
204
        // Match session context
205
        if (null !== $session) {
206
            $qb
207
                ->andWhere('rl.session = :session')
208
                ->setParameter('session', $session);
209
        } else {
210
            $qb->andWhere('rl.session IS NULL');
211
        }
212
213
        // Match group context
214
        if (null !== $group) {
215
            $qb
216
                ->andWhere('rl.group = :group')
217
                ->setParameter('group', $group);
218
        } else {
219
            $qb->andWhere('rl.group IS NULL');
220
        }
221
222
        if (null !== $usergroup) {
223
            $qb
224
                ->andWhere('rl.userGroup = :usergroup')
225
                ->setParameter('usergroup', $usergroup);
226
        } else {
227
            $qb->andWhere('rl.userGroup IS NULL');
228
        }
229
230
        // Match user context
231
        if (null !== $user) {
232
            $qb
233
                ->andWhere('rl.user = :user')
234
                ->setParameter('user', $user);
235
        } else {
236
            $qb->andWhere('rl.user IS NULL');
237
        }
238
239
        return $qb->getQuery()->getOneOrNullResult();
240
    }
241
242
    /**
243
     * Find the link of a resource in a given context.
244
     *
245
     * This is mostly used by document move operations to update the link parent
246
     * only in the current context.
247
     */
248
    public function findLinkForResourceInContext(
249
        AbstractResource $resource,
250
        ?Course $course,
251
        ?Session $session,
252
        ?CGroup $group,
253
        ?Usergroup $usergroup,
254
        ?User $user
255
    ): ?ResourceLink {
256
        $resourceNode = $resource->getResourceNode();
257
        if (null === $resourceNode) {
258
            return null;
259
        }
260
261
        $qb = $this->createQueryBuilder('rl')
262
            ->andWhere('rl.resourceNode = :resourceNode')
263
            ->setParameter('resourceNode', $resourceNode)
264
            ->andWhere('rl.deletedAt IS NULL')
265
            ->setMaxResults(1);
266
267
        // Match course context
268
        if (null !== $course) {
269
            $qb
270
                ->andWhere('rl.course = :course')
271
                ->setParameter('course', $course);
272
        } else {
273
            $qb->andWhere('rl.course IS NULL');
274
        }
275
276
        // Match session context
277
        if (null !== $session) {
278
            $qb
279
                ->andWhere('rl.session = :session')
280
                ->setParameter('session', $session);
281
        } else {
282
            $qb->andWhere('rl.session IS NULL');
283
        }
284
285
        // Match group context
286
        if (null !== $group) {
287
            $qb
288
                ->andWhere('rl.group = :group')
289
                ->setParameter('group', $group);
290
        } else {
291
            $qb->andWhere('rl.group IS NULL');
292
        }
293
294
        if (null !== $usergroup) {
295
            $qb
296
                ->andWhere('rl.userGroup = :usergroup')
297
                ->setParameter('usergroup', $usergroup);
298
        } else {
299
            $qb->andWhere('rl.userGroup IS NULL');
300
        }
301
302
        // Match user context
303
        if (null !== $user) {
304
            $qb
305
                ->andWhere('rl.user = :user')
306
                ->setParameter('user', $user);
307
        } else {
308
            $qb->andWhere('rl.user IS NULL');
309
        }
310
311
        return $qb->getQuery()->getOneOrNullResult();
312
    }
313
}
314