From bfc3eb21c6bbc70ea6616e0d75aa0e36e4944ddd Mon Sep 17 00:00:00 2001 From: Adam Franco Date: Wed, 9 Oct 2024 17:07:57 -0400 Subject: [PATCH] #47: Migrate courses by id XML action. --- src/Controller/Courses.php | 127 ++++++++++++------ .../Helper/RecentCourses/All.php | 26 ++-- .../Helper/RecentCourses/Department.php | 18 ++- .../Helper/RecentCourses/Instructor.php | 53 ++++---- .../RecentCourses/RecentCoursesAbstract.php | 72 ++++------ .../RecentCourses/RecentCoursesInterface.php | 18 ++- templates/partials/course.xml.twig | 5 + templates/partials/offering_list.xml.twig | 2 + 8 files changed, 181 insertions(+), 140 deletions(-) rename {application/library => src}/Helper/RecentCourses/All.php (63%) rename {application/library => src}/Helper/RecentCourses/Department.php (79%) rename {application/library => src}/Helper/RecentCourses/Instructor.php (74%) rename application/library/Helper/RecentCourses/Abstract.php => src/Helper/RecentCourses/RecentCoursesAbstract.php (81%) rename application/library/Helper/RecentCourses/Interface.php => src/Helper/RecentCourses/RecentCoursesInterface.php (64%) diff --git a/src/Controller/Courses.php b/src/Controller/Courses.php index 3d9a06c0..6e1d8da7 100755 --- a/src/Controller/Courses.php +++ b/src/Controller/Courses.php @@ -6,11 +6,14 @@ namespace App\Controller; +use App\Helper\RecentCourses\Department as DepartmentRecentCourses; +use App\Helper\RecentCourses\RecentCoursesInterface; use App\Service\Osid\IdMap; use App\Service\Osid\Runtime; use App\Service\Osid\TermHelper; use App\Service\Osid\TopicHelper; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -118,7 +121,9 @@ public function view($course, $term = NULL) public function viewxml($course, $term = NULL) { $data = []; - $data['courses'] = [$this->getCourseDataByIdString($course, $term)]; + $courseData = $this->getCourseDataByIdString($course, $term); + $courseData['offerings'] = $this->getCourseOfferingsData($courseData['course'], $courseData['term']); + $data['courses'] = [$courseData]; $data['title'] = $data['courses'][0]['course']->getDisplayName(); $data['feedLink'] = $this->generateUrl('view_course', ['course' => $course], UrlGeneratorInterface::ABSOLUTE_URL); @@ -148,7 +153,11 @@ protected function getCourseDataByIdString($idString, $termIdString = NULL) } protected function getCourseData(\osid_course_Course $course, \osid_course_Term|NULL $term = NULL) { + $data = []; $data['course'] = $course; + // Optional add-on data that can be populated by other methods. + $data['offerings'] = []; + $data['terms'] = []; // Load the topics into our view $data = array_merge($data, $this->getTopics($course->getTopics())); @@ -178,8 +187,11 @@ protected function getCourseData(\osid_course_Course $course, \osid_course_Term| // Term $data['term'] = $term; - // offerings. - $data['offerings'] = []; + return $data; + } + + protected function getCourseOfferingsData(\osid_course_Course $course, \osid_course_Term|NULL $term = NULL) { + $data = []; $offeringLookupSession = $this->osidRuntime->getCourseManager()->getCourseOfferingLookupSession(); $offeringLookupSession->useFederatedCourseCatalogView(); if ($term) { @@ -219,7 +231,7 @@ protected function getCourseData(\osid_course_Course $course, \osid_course_Term| } } - $data['offerings'][] = $offering; + $data[] = $offering; } return $data; @@ -407,75 +419,86 @@ public function topicxmlAction() $topicLookup->useFederatedCourseCatalogView(); $topic = $topicLookup->getTopic($topicId); - $recentCourses = new Helper_RecentCourses_Department($courses); - if ($this->_getParam('cutoff')) { - $recentCourses->setRecentInterval(new DateInterval($this->_getParam('cutoff'))); + $recentCourses = new DepartmentRecentCourses($this->osidIdMap, $courses); + if ($request->get('cutoff')) { + $recentCourses->setRecentInterval(new \DateInterval($request->get('cutoff'))); } $this->outputCourseFeed($recentCourses, htmlentities('Courses in '.$topic->getDisplayName()), $searchUrl); } - /** - * Search for courses. - * - * @return void - * - * @since 6/15/09 - */ - public function byidxmlAction() + #[Route('/courses/byidxml/{catalog}', name: 'list_courses_by_ids')] + public function byidxmlAction(Request $request, $catalog) { - $this->_helper->layout->disableLayout(); - $this->_helper->viewRenderer->setNoRender(); - - if (!$this->_getParam('catalog')) { + if (!$catalog) { header('HTTP/1.1 400 Bad Request'); echo 'A catalog must be specified.'; exit; } try { - $catalogId = $this->osidIdMap->fromString($this->_getParam('catalog')); + $catalogId = $this->osidIdMap->fromString($catalog); $lookupSession = $this->osidRuntime->getCourseManager()->getCourseLookupSessionForCatalog($catalogId); $this->termLookupSession = $this->osidRuntime->getCourseManager()->getTermLookupSessionForCatalog($catalogId); - } catch (osid_InvalidArgumentException $e) { + } catch (\osid_InvalidArgumentException $e) { header('HTTP/1.1 400 Bad Request'); echo 'The catalog id specified was not of the correct format.'; exit; - } catch (osid_NotFoundException $e) { + } catch (\osid_NotFoundException $e) { header('HTTP/1.1 404 Not Found'); echo 'The catalog id specified was not found.'; exit; } - - if (!$this->_getParam('id')) { + $ids = $request->get('id', []); + if (!$ids) { header('HTTP/1.1 400 Bad Request'); echo "'id[]' must be specified."; exit; } $courseIds = []; - if (is_array($this->_getParam('id'))) { - foreach ($this->_getParam('id') as $idString) { + if (is_array($ids)) { + foreach ($ids as $idString) { $courseIds[] = $this->osidIdMap->fromString($idString); } } else { - $courseIds[] = $this->osidIdMap->fromString($this->_getParam('id')); + $courseIds[] = $this->osidIdMap->fromString($ids); } - // Use Comparative view to include any found courses, ignoring missing ids. $lookupSession->useComparativeCourseView(); - $courses = $lookupSession->getCoursesByIds(new phpkit_id_ArrayIdList($courseIds)); + $courses = $lookupSession->getCoursesByIds(new \phpkit_id_ArrayIdList($courseIds)); - $recentCourses = new Helper_RecentCourses_Department($courses); - if ($this->_getParam('cutoff')) { - $recentCourses->setRecentInterval(new DateInterval($this->_getParam('cutoff'))); + $recentCourses = new DepartmentRecentCourses($this->osidIdMap, $courses); + if ($request->get('cutoff')) { + $recentCourses->setRecentInterval(new \DateInterval($request->get('cutoff'))); + } + + // Set the next and previous terms. + $currentTermId = $this->osidTermHelper->getCurrentTermId($this->termLookupSession->getCourseCatalogId()); + $currentTerm = $this->termLookupSession->getTerm($currentTermId); + + $data = [ + 'courses' => [], + ]; + foreach ($recentCourses->getPrimaryCourses() as $course) { + $courseData = $this->getCourseData($course); + $courseData['terms'] = $this->getRecentTermData($currentTerm, $recentCourses, $course); + $courseData['offerings'] = []; + $data['courses'][] = $courseData; } + $data['title'] = 'Courses by Id'; + $data['feedLink'] = $this->generateUrl( + 'list_courses_by_ids', + [ + 'catalog' => $catalog, + 'id' => $request->get('id'), + 'cutoff' => $request->get('cutoff'), + ], + UrlGeneratorInterface::ABSOLUTE_URL + ); - $searchUrl = $this->_helper->pathAsAbsoluteUrl($this->_helper->url('byidxml', 'courses', null, [ - 'catalog' => $this->_getParam('catalog'), - 'id' => $this->_getParam('id'), - 'cuttoff' => $this->_getParam('cutoff'), - ])); - $this->outputCourseFeed($recentCourses, 'Courses by Id', $searchUrl); + $response = new Response($this->renderView('courses/list.xml.twig', $data)); + $response->headers->set('Content-Type', 'text/xml; charset=utf-8'); + return $response; } /** @@ -733,10 +756,36 @@ protected function outputCourseFeed(Helper_RecentCourses_Interface $recentCourse exit; } + protected function getRecentTermData(\osid_course_Term $currentTerm, RecentCoursesInterface $recentCourses, \osid_course_Course $course) { + $now = $this->DateTime_getTimestamp(new \DateTime()); + $currentTermId = $currentTerm->getId(); + $currentEndTime = $this->DateTime_getTimestamp($currentTerm->getEndTime()); + $recentTerms = $recentCourses->getTermsForCourse($course); + $data = []; + if (count($recentTerms)) { + foreach ($recentTerms as $term) { + if ($term->getId()->isEqual($currentTermId)) { + $type = 'current'; + } elseif ($currentEndTime < $this->DateTime_getTimestamp($term->getEndTime())) { + $type = 'future'; + } elseif ($now > $this->DateTime_getTimestamp($term->getStartTime()) && $now < $this->DateTime_getTimestamp($term->getEndTime())) { + $type = 'current'; + } else { + $type = 'past'; + } + $data[] = [ + 'term' => $term, + 'type' => $type, + ]; + } + } + return $data; + } + public function DateTime_getTimestamp($dt) { $dtz_original = $dt->getTimezone(); - $dtz_utc = new DateTimeZone('UTC'); + $dtz_utc = new \DateTimeZone('UTC'); $dt->setTimezone($dtz_utc); $year = (int) $dt->format('Y'); $month = (int) $dt->format('n'); diff --git a/application/library/Helper/RecentCourses/All.php b/src/Helper/RecentCourses/All.php similarity index 63% rename from application/library/Helper/RecentCourses/All.php rename to src/Helper/RecentCourses/All.php index 39b34542..5f3a04dd 100755 --- a/application/library/Helper/RecentCourses/All.php +++ b/src/Helper/RecentCourses/All.php @@ -1,20 +1,20 @@ termsCache = []; - parent::__construct($courses); + parent::__construct($osidIdMap, $courses); } /** @@ -38,12 +38,12 @@ public function __construct(osid_course_CourseList $courses) * * @since 11/16/09 */ - protected function fetchCourseTerms(osid_course_Course $course) + protected function fetchCourseTerms(\osid_course_Course $course) { - $cacheKey = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($course->getId()); + $cacheKey = $this->osidIdMap->toString($course->getId()); if (!isset($this->termsCache[$cacheKey])) { - $termsType = new phpkit_type_URNInetType('urn:inet:middlebury.edu:record:terms'); + $termsType = new \phpkit_type_URNInetType('urn:inet:middlebury.edu:record:terms'); $allTerms = []; if ($course->hasRecordType($termsType)) { $termsRecord = $course->getCourseRecord($termsType); @@ -52,7 +52,7 @@ protected function fetchCourseTerms(osid_course_Course $course) while ($terms->hasNext()) { $allTerms[] = $terms->getNextTerm(); } - } catch (osid_OperationFailedException $e) { + } catch (\osid_OperationFailedException $e) { } } $this->termsCache[$cacheKey] = $allTerms; diff --git a/application/library/Helper/RecentCourses/Department.php b/src/Helper/RecentCourses/Department.php similarity index 79% rename from application/library/Helper/RecentCourses/Department.php rename to src/Helper/RecentCourses/Department.php index 35a94971..3f7aaafa 100755 --- a/application/library/Helper/RecentCourses/Department.php +++ b/src/Helper/RecentCourses/Department.php @@ -1,20 +1,18 @@ hasNext()) { $course = $courses->getNextCourse(); - $courseIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($course->getId()); + $courseIdString = $this->osidIdMap->toString($course->getId()); $groupId = $courseIdString; @@ -50,7 +48,7 @@ protected function groupAlternates(osid_course_CourseList $courses) $term = $this->getMostRecentTermForCourse($course); $dates[] = $this->DateTime_getTimestamp($term->getEndTime()); $names[] = $course->getDisplayName(); - } catch (osid_NotFoundException $e) { + } catch (\osid_NotFoundException $e) { unset($group[$key]); } } diff --git a/application/library/Helper/RecentCourses/Instructor.php b/src/Helper/RecentCourses/Instructor.php similarity index 74% rename from application/library/Helper/RecentCourses/Instructor.php rename to src/Helper/RecentCourses/Instructor.php index f6639a91..62ddebe8 100755 --- a/application/library/Helper/RecentCourses/Instructor.php +++ b/src/Helper/RecentCourses/Instructor.php @@ -1,21 +1,23 @@ recentInterval = new DateInterval('P4Y'); - $this->alternatesType = new phpkit_type_URNInetType('urn:inet:middlebury.edu:record:alternates'); + $this->osidIdMap = $osidIdMap; + $this->recentInterval = new \DateInterval('P4Y'); + $this->alternatesType = new \phpkit_type_URNInetType('urn:inet:middlebury.edu:record:alternates'); $this->groupCourseOfferings($offerings); $this->courseLookupSession = $courseLookupSession; } @@ -39,7 +42,7 @@ public function __construct(osid_course_CourseOfferingSearchResults $offerings, * * @return null */ - public function setRecentInterval(DateInterval $interval) + public function setRecentInterval(\DateInterval $interval) { $this->recentInterval = $interval; } @@ -64,11 +67,11 @@ public function getPrimaryCourses() * * @return array */ - public function getAlternatesForCourse(osid_course_Course $course) + public function getAlternatesForCourse(\osid_course_Course $course) { - $idString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($course->getId()); + $idString = $this->osidIdMap->toString($course->getId()); if (!isset($this->groups[$idString])) { - throw new osid_NotFoundException('The course specified is not one of our primary courses.'); + throw new \osid_NotFoundException('The course specified is not one of our primary courses.'); } if (!isset($this->groups[$idString]['alternate_courses'])) { $this->groups[$idString]['alternate_courses'] = []; @@ -85,11 +88,11 @@ public function getAlternatesForCourse(osid_course_Course $course) * * @return array */ - public function getTermsForCourse(osid_course_Course $course) + public function getTermsForCourse(\osid_course_Course $course) { - $idString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($course->getId()); + $idString = $this->osidIdMap->toString($course->getId()); if (!isset($this->groups[$idString])) { - throw new osid_NotFoundException('The course specified is not one of our primary courses.'); + throw new \osid_NotFoundException('The course specified is not one of our primary courses.'); } ksort($this->groups[$idString]['terms']); @@ -105,14 +108,14 @@ public function getTermsForCourse(osid_course_Course $course) * * @return null */ - protected function groupCourseOfferings(osid_course_CourseOfferingSearchResults $offerings) + protected function groupCourseOfferings(\osid_course_CourseOfferingSearchResults $offerings) { while ($offerings->hasNext()) { $offering = $offerings->getNextCourseOffering(); if ($this->termIsRecent($offering->getTerm())) { $courseId = $offering->getCourseId(); - $courseIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($courseId); - $termIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($offering->getTermId()); + $courseIdString = $this->osidIdMap->toString($courseId); + $termIdString = $this->osidIdMap->toString($offering->getTermId()); $groupAlternateCourseIds = []; $groupTerms = [$termIdString => $offering->getTerm()]; @@ -126,7 +129,7 @@ protected function groupCourseOfferings(osid_course_CourseOfferingSearchResults while ($alternates->hasNext()) { $alternate = $alternates->getNextCourseOffering(); $alternateCourseId = $alternate->getCourseId(); - $alternateCourseIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($alternateCourseId); + $alternateCourseIdString = $this->osidIdMap->toString($alternateCourseId); $groupAlternateCourseIds[$alternateCourseIdString] = $alternateCourseId; // Reset the group key if the primary alternate is later in the search results. if ($alternate->hasRecordType($this->alternatesType)) { @@ -139,7 +142,7 @@ protected function groupCourseOfferings(osid_course_CourseOfferingSearchResults } } - $groupKey = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($groupPrimaryCourseId); + $groupKey = $this->osidIdMap->toString($groupPrimaryCourseId); // Add our group to our result list. if (!isset($this->groups[$groupKey])) { $this->groups[$groupKey] = [ @@ -159,11 +162,11 @@ protected function groupCourseOfferings(osid_course_CourseOfferingSearchResults * * @return bool */ - protected function termIsRecent(osid_course_Term $term) + protected function termIsRecent(\osid_course_Term $term) { // Define a cutoff date after which courses will be included in the feed. // Default is 4 years. - $now = new DateTime(); + $now = new \DateTime(); $cutOff = $this->DateTime_getTimestamp($now->sub($this->recentInterval)); $termEnd = $this->DateTime_getTimestamp($term->getEndTime()); @@ -173,7 +176,7 @@ protected function termIsRecent(osid_course_Term $term) public function DateTime_getTimestamp($dt) { $dtz_original = $dt->getTimezone(); - $dtz_utc = new DateTimeZone('UTC'); + $dtz_utc = new \DateTimeZone('UTC'); $dt->setTimezone($dtz_utc); $year = (int) $dt->format('Y'); $month = (int) $dt->format('n'); diff --git a/application/library/Helper/RecentCourses/Abstract.php b/src/Helper/RecentCourses/RecentCoursesAbstract.php similarity index 81% rename from application/library/Helper/RecentCourses/Abstract.php rename to src/Helper/RecentCourses/RecentCoursesAbstract.php index 59ba4372..e8116438 100755 --- a/application/library/Helper/RecentCourses/Abstract.php +++ b/src/Helper/RecentCourses/RecentCoursesAbstract.php @@ -1,21 +1,23 @@ alternateType = new phpkit_type_URNInetType('urn:inet:middlebury.edu:record:alternates'); + $this->osidIdMap = $osidIdMap; + $this->alternateType = new \phpkit_type_URNInetType('urn:inet:middlebury.edu:record:alternates'); $this->groups = []; $this->terms = []; - $this->recentInterval = new DateInterval('P4Y'); + $this->recentInterval = new \DateInterval('P4Y'); $this->courses = $courses; } @@ -47,7 +47,7 @@ public function __construct(osid_course_CourseList $courses) * * @since 9/19/14 */ - public function setRecentInterval(DateInterval $interval) + public function setRecentInterval(\DateInterval $interval) { $this->recentInterval = $interval; } @@ -56,8 +56,6 @@ public function setRecentInterval(DateInterval $interval) * Answer an array of primary courses. * * @return array - * - * @since 11/16/09 */ public function getPrimaryCourses() { @@ -79,10 +77,8 @@ public function getPrimaryCourses() * Answer an array of alternate courses for a primary course. * * @return array - * - * @since 11/16/09 */ - public function getAlternatesForCourse(osid_course_Course $course) + public function getAlternatesForCourse(\osid_course_Course $course) { $this->initialize(); @@ -99,17 +95,15 @@ public function getAlternatesForCourse(osid_course_Course $course) return $alternates; } } - throw new osid_NotFoundException('No primary matches the id given.'); + throw new \osid_NotFoundException('No primary matches the id given.'); } /** * Answer an array of terms from primary or alternate courses given a primary id. * * @return array - * - * @since 11/16/09 */ - public function getTermsForCourse(osid_course_Course $course) + public function getTermsForCourse(\osid_course_Course $course) { $this->initialize(); @@ -124,10 +118,8 @@ public function getTermsForCourse(osid_course_Course $course) * Answer the terms for a course. These may be all terms or terms taught. * * @return array - * - * @since 11/16/09 */ - abstract protected function fetchCourseTerms(osid_course_Course $course); + abstract protected function fetchCourseTerms(\osid_course_Course $course); /********************************************************* * Internal methods @@ -156,13 +148,13 @@ protected function initialize() * * @since 11/13/09 */ - protected function groupAlternates(osid_course_CourseList $courses) + protected function groupAlternates(\osid_course_CourseList $courses) { while ($courses->hasNext()) { $groupId = false; $course = $courses->getNextCourse(); - $courseIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($course->getId()); + $courseIdString = $this->osidIdMap->toString($course->getId()); // print "\n

Grouping $courseIdString

\n"; // print "\n

Current Groups:

\n"; @@ -223,16 +215,14 @@ protected function groupAlternates(osid_course_CourseList $courses) } /** - * return the id of a group that matches or false. - * - * @since 11/13/09 + * Return the id of a group that matches or false. */ - private function findGroupIdMatchingAlternates(osid_id_IdList $altIds) + private function findGroupIdMatchingAlternates(\osid_id_IdList $altIds) { // print "\n

Alternates:

\n"; while ($altIds->hasNext()) { $altId = $altIds->getNextId(); - $altIdString = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId')->toString($altId); + $altIdString = $this->osidIdMap->toString($altId); // var_dump($altIdString); foreach ($this->groups as $groupId => $group) { @@ -253,10 +243,8 @@ private function findGroupIdMatchingAlternates(osid_id_IdList $altIds) * @param optional $includeAlternates * * @return array - * - * @since 11/16/09 */ - private function getRecentTermsForCourse(osid_course_Course $course, $includeAlternates = false) + private function getRecentTermsForCourse(\osid_course_Course $course, $includeAlternates = false) { $recentTerms = $this->filterRecentTerms($this->fetchCourseTerms($course)); @@ -282,15 +270,13 @@ private function getRecentTermsForCourse(osid_course_Course $course, $includeAlt * Answer the most recent term for a course. * * @return osid_course_Term - * - * @since 11/16/09 */ - protected function getMostRecentTermForCourse(osid_course_Course $course) + protected function getMostRecentTermForCourse(\osid_course_Course $course) { $terms = $this->getRecentTermsForCourse($course); if (!count($terms)) { - throw new osid_NotFoundException('No terms available.'); + throw new \osid_NotFoundException('No terms available.'); } foreach ($terms as $term) { @@ -318,10 +304,10 @@ private function filterRecentTerms(array $allTerms) { // Define a cutoff date after which courses will be included in the feed. // Currently set to 4 years. Would be good to have as a configurable time. - $now = new DateTime(); + $now = new \DateTime(); $cutOff = $this->DateTime_getTimestamp($now->sub($this->recentInterval)); $recentTerms = []; - $osidIdHelper = Zend_Controller_Action_HelperBroker::getStaticHelper('OsidId'); + $osidIdHelper = $this->osidIdMap; foreach ($allTerms as $term) { if ($this->DateTime_getTimestamp($term->getEndTime()) > $cutOff) { $termIdString = $osidIdHelper->toString($term->getId()); @@ -335,7 +321,7 @@ private function filterRecentTerms(array $allTerms) public function DateTime_getTimestamp($dt) { $dtz_original = $dt->getTimezone(); - $dtz_utc = new DateTimeZone('UTC'); + $dtz_utc = new \DateTimeZone('UTC'); $dt->setTimezone($dtz_utc); $year = (int) $dt->format('Y'); $month = (int) $dt->format('n'); diff --git a/application/library/Helper/RecentCourses/Interface.php b/src/Helper/RecentCourses/RecentCoursesInterface.php similarity index 64% rename from application/library/Helper/RecentCourses/Interface.php rename to src/Helper/RecentCourses/RecentCoursesInterface.php index c03a36e8..0adb330b 100644 --- a/application/library/Helper/RecentCourses/Interface.php +++ b/src/Helper/RecentCourses/RecentCoursesInterface.php @@ -1,27 +1,25 @@ {{ alternate.displayname }} {% endfor ~%} +{% endif %} +{%- if terms is not empty %} +{%- for termData in terms %} + {{ termData.term.displayname }} +{% endfor ~%} {% endif %} {{ course.genustype.displayname }} {% for topic in subjectTopics %} diff --git a/templates/partials/offering_list.xml.twig b/templates/partials/offering_list.xml.twig index 3feaeb8f..c560bbd9 100755 --- a/templates/partials/offering_list.xml.twig +++ b/templates/partials/offering_list.xml.twig @@ -1,3 +1,4 @@ +{% if offerings is not empty %} {% set currentTerm = null %} {% for offering in offerings %} @@ -27,3 +28,4 @@ {% endfor %} +{% endif %}