181181 // Skills: Category::generateUserCertificate() already assigns skills
182182 // to the user for this course/session/category when enabled.
183183 // Here we just render the user's skills panel.
184- $ badgeBlock = generateBadgePanel ($ userId , $ courseId , $ sessionId );
184+ $ badgeBlock = generateBadgePanel ($ userId , $ courseId , $ sessionId, ( int ) $ gbCat -> getId () );
185185 }
186186
187187 // Replace ((certificate)) and ((skill)) tokens in the final-item document.
193193$ tpl ->display_blank_template ();
194194
195195/**
196- * Generates/ensures the certificate via Doctrine repositories and returns minimal link data .
196+ * Returns the user's skills panel HTML for the current final-item category only (empty if none) .
197197 */
198- function safeGenerateCertificateForCategory ( GradebookCategory $ category , int $ userId ): array
198+ function generateBadgePanel ( int $ userId , int $ courseId , int $ sessionId = 0 , int $ gradebookCategoryId = 0 ): string
199199{
200- $ course = $ category ->getCourse ();
201- $ session = $ category ->getSession ();
202- $ courseId = $ course ? $ course ->getId () : 0 ;
203- $ sessId = $ session ? $ session ->getId () : 0 ;
204- $ catId = (int ) $ category ->getId ();
205-
206- // Build certificate content & score.
207- $ gb = GradebookUtils::get_user_certificate_content ($ userId , $ courseId , $ sessId );
208- $ html = (is_array ($ gb ) && isset ($ gb ['content ' ])) ? $ gb ['content ' ] : '' ;
209- $ score = isset ($ gb ['score ' ]) ? (float ) $ gb ['score ' ] : 100.0 ;
210-
211- $ certRepo = Container::getGradeBookCertificateRepository ();
212-
213- $ htmlUrl = '' ;
214- $ pdfUrl = '' ;
215- $ cert = null ;
216-
217- try {
218- // Store/refresh as Resource (controlled access; not shown in "My personal files").
219- $ cert = $ certRepo ->upsertCertificateResource ($ catId , $ userId , $ score , $ html );
220-
221- // (Optional) keep metadata (created_at/score). Filename is not required anymore.
222- $ certRepo ->registerUserInfoAboutCertificate ($ catId , $ userId , $ score );
223-
224- // Build URLs from the Resource layer.
225- $ htmlUrl = $ certRepo ->getResourceFileUrl ($ cert );
226- } catch (\Throwable $ e ) {
227- error_log ('[LP_FINAL] register cert error: ' .$ e ->getMessage ());
200+ $ gradebookCategoryId = (int ) $ gradebookCategoryId ;
201+ if ($ gradebookCategoryId <= 0 ) {
202+ return '' ;
228203 }
229204
230- return [
231- 'path_certificate ' => $ cert ? (string ) ($ cert ->getPathCertificate () ?? '' ) : '' ,
232- 'html_url ' => $ htmlUrl ,
233- 'pdf_url ' => $ pdfUrl ,
234- ];
235- }
236-
237- /**
238- * Builds the certificate download/view HTML block (if available).
239- */
240- function buildCertificateBlock (array $ cert ): string
241- {
242- $ htmlUrl = $ cert ['html_url ' ] ?? '' ;
243- $ pdfUrl = $ cert ['pdf_url ' ] ?? '' ;
244- if (!$ htmlUrl && !$ pdfUrl ) {
205+ $ allowedSkillIds = getSkillIdsForGradebookCategory ($ gradebookCategoryId );
206+ if (empty ($ allowedSkillIds )) {
245207 return '' ;
246208 }
247209
248- $ downloadBtn = $ pdfUrl
249- ? Display::toolbarButton (get_lang ('Download certificate in PDF ' ), $ pdfUrl , 'file-pdf-box ' )
250- : '' ;
251-
252- $ viewBtn = $ htmlUrl
253- ? Display::url (get_lang ('View certificate ' ), $ htmlUrl , ['class ' => 'btn btn-default ' ])
254- : '' ;
255-
256- return "
257- <div class='panel panel-default'>
258- <div class='panel-body'>
259- <h3 class='text-center'> " .get_lang ('You can now download your certificate by clicking here ' )."</h3>
260- <div class='text-center'> {$ downloadBtn } {$ viewBtn }</div>
261- </div>
262- </div>
263- " ;
264- }
265-
266- /**
267- * Returns the user's skills panel HTML (empty if none).
268- */
269- function generateBadgePanel (int $ userId , int $ courseId , int $ sessionId = 0 ): string
270- {
271210 $ em = Database::getManager ();
272211 $ skillRelUser = new SkillRelUserModel ();
273212 $ userSkills = $ skillRelUser ->getUserSkills ($ userId , $ courseId , $ sessionId );
@@ -279,7 +218,16 @@ function generateBadgePanel(int $userId, int $courseId, int $sessionId = 0): str
279218 $ items = '' ;
280219
281220 foreach ($ userSkills as $ row ) {
282- $ skill = $ em ->find (Skill::class, (int ) $ row ['skill_id ' ]);
221+ $ rowSkillId = (int ) ($ row ['skill_id ' ] ?? 0 );
222+ if ($ rowSkillId <= 0 ) {
223+ continue ;
224+ }
225+
226+ if (!in_array ($ rowSkillId , $ allowedSkillIds , true )) {
227+ continue ;
228+ }
229+
230+ $ skill = $ em ->find (Skill::class, $ rowSkillId );
283231 if (!$ skill ) {
284232 continue ;
285233 }
@@ -383,6 +331,42 @@ class='inline-flex h-10 w-10 items-center justify-center rounded-full ring-1 rin
383331 " ;
384332}
385333
334+ /**
335+ * Returns the skill IDs linked to a gradebook category.
336+ */
337+ function getSkillIdsForGradebookCategory (int $ categoryId ): array
338+ {
339+ if ($ categoryId <= 0 ) {
340+ return [];
341+ }
342+
343+ $ ids = [];
344+
345+ try {
346+ $ gradebook = new Gradebook ();
347+ $ rows = $ gradebook ->getSkillsByGradebook ($ categoryId );
348+
349+ if (is_array ($ rows )) {
350+ foreach ($ rows as $ row ) {
351+ if (is_array ($ row ) && isset ($ row ['id ' ])) {
352+ $ ids [] = (int ) $ row ['id ' ];
353+ } elseif (is_scalar ($ row )) {
354+ $ ids [] = (int ) $ row ;
355+ }
356+ }
357+ } elseif (is_string ($ rows ) && trim ($ rows ) !== '' ) {
358+ $ parts = preg_split ('/\s*,\s*/ ' , trim ($ rows )) ?: [];
359+ foreach ($ parts as $ p ) {
360+ $ ids [] = (int ) $ p ;
361+ }
362+ }
363+ } catch (\Throwable $ e ) {
364+ return [];
365+ }
366+
367+ return array_values (array_unique (array_filter (array_map ('intval ' , $ ids ), static fn (int $ v ) => $ v > 0 )));
368+ }
369+
386370/**
387371 * Render the Learning Path final-item document.
388372 */
0 commit comments