-
Notifications
You must be signed in to change notification settings - Fork 556
c_item_property to nodes conversion
The table c_item_property has been removed in Chamilo v2, instead we use the following Resource-related entities:
- AbstractResource
- ResourceNode
For example, in the announcements tool, we have queries like this:
Source from 1.11.x:
https://github.com/chamilo/chamilo-lms/blob/1.11.x/main/inc/lib/AnnouncementManager.php#L2056-L2101
<?php $condition_session = api_get_session_condition( $session_id, true, true, 'announcement.session_id' ); if (api_get_group_id() == 0) { $group_condition = ''; } else { $group_condition = " AND (ip.to_group_id='".api_get_group_id()."' OR ip.to_group_id = 0 OR ip.to_group_id IS NULL)"; } $sql = "SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id FROM $tbl_announcement announcement INNER JOIN $tbl_item_property ip ON (announcement.c_id = ip.c_id AND announcement.id = ip.ref) WHERE announcement.c_id = $courseId AND ip.c_id = $courseId AND ip.tool = 'announcement' AND ip.visibility <> '2' $group_condition $condition_session GROUP BY ip.ref ORDER BY display_order DESC LIMIT 0, $maximum";
You can see the $group_condition and $condition_session variables at the end have been built before building the query, and they are relatively complex. Adding them to the query is a complex operation by itself.
The process has been streamlined in v2, but requires some previous knowledge to use efficiently. Let's analyse the process that is required to completely convert this tool to the new Resource-type structure...
Set up a class like follows, which implements the methods required by the interface. As you can see, each tool-based class should extend AbstractResource and implement ResourceInterface.
Extending AbstractResource (src/CoreBundle/Entity/AbstractResource.php) will ensure some methods are readily available (addCourseLink(), getParent(), getResourceNode(), getResourceName(), etc).
Implementing ResourceInterface will remind you to implement those basic methods: __toString(), getResourceIdentifier(), getResourceName(), setResourceName(), getResourceNode(), setResourceNode(). Those (except the first two) are already defined in the AbstractResource definition, but it's good to have the definition of what methods must be covered at a minimum. This list might change over time.
<?php namespace Chamilo\CourseBundle\Entity; class CAnnouncement extends AbstractResource implements ResourceInterface { }
The CAnnouncement class represents the entity and the actions that can be taken on an announcement object so Chamilo can work with it.
The CAnnouncementRepository class, in contrast, represents the methods to access the announcement in a list (the database or other). So if you want to retrieve the announcement in a table full of announcements, you need a repository class for it.
<?php namespace Chamilo\CourseBundle\Repository; use Chamilo\CourseBundle\Entity\CAnnouncement; use Doctrine\Persistence\ManagerRegistry; final class CAnnouncementRepository extends ResourceRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, CAnnouncement::class); } }
Because we are dealing with legacy code, we need to register this repository in the container for easy use:
<?php namespace Chamilo\CoreBundle\Framework; class Container { /** * @return CAnnouncementRepository */ public static function getAnnouncementRepository() { return self::$container->get('Chamilo\CourseBundle\Repository\CAnnouncementRepository'); }
Legacy code:
$sql = "SELECT $select FROM $tbl_announcement announcement INNER JOIN $tbl_item_property ip ON (announcement.id = ip.ref AND ip.c_id = announcement.c_id) WHERE announcement.c_id = $courseId AND ip.c_id = $courseId AND ip.tool = 'announcement' AND ( ip.to_user_id = $user_id OR ip.to_group_id IS NULL OR ip.to_group_id IN (0, ".implode(", ", $group_memberships).") ) AND ip.visibility IN ('1', '0') $condition_session $searchCondition ORDER BY display_order DESC";
v2 code (no c_item_property):
<?php $repo = Container::getAnnouncementRepository(); $course = api_get_course_entity($courseId); $session = api_get_session_entity($session_id); $group = api_get_group_entity(api_get_group_id()); $qb = $repo->getResourcesByCourse($course, $session, $group); $qb->select('count(resource)'); $count = $qb->getQuery()->getSingleScalarResult();
Because, getResourcesByCourse returns a QueryBuilder, we can overwrite some parameters and return the count instead of all the elements. The method getResourcesByCourse() should handle the conditions to filter by course, session or group natively, so you don't have to set the complex conditions we saw at the beginning anymore.
For this example, we will use the CAnnouncement resource.
Before:
<?php $params = [ 'c_id' => $courseId, 'content' => $newContent, 'title' => $title, 'end_date' => $end_date, 'display_order' => $order, 'session_id' => (int) $sessionId, ]; $last_id = Database::insert($tbl_announcement, $params);
After:
<?php $course = api_get_course_entity($courseId); $session = api_get_session_entity($sessionId); $announcement = new CAnnouncement(); $announcement ->setContent($newContent) ->setTitle($title) ->setEndDate(new DateTime($end_date)) ->setDisplayOrder($order) ->setParent($course) ->addCourseLink($course, $session) ; $repo = Container::getAnnouncementRepository(); $repo->create($announcement);
Any field not treated by the parent AbstractResource class (like setEndDate() in this case) will have to be implemented manually in the resource class (CAnnouncement in this case).
<?php $repo = Container::getAnnouncementRepository(); $announcement = $repo->find($id); /** @var CStudentPublication $announcement */ if ($announcement) { $announcement->setTitle('new title'); $repo->update($announcement); }
Chamilo LMS
-
Home
- Tools and sessions
- Quiz: Importing
- Releases
- Community
- Development
- Getting started
- Development principles
- Technical design decisions
- Coding conventions v1
- Coding conventions v2
- Add a new Chamilo setting
- Database structure
- Date and time management
- Permissions
- Password management
- Session expiry time
- Code annotation types
- Code quality checkers
- Converting legacy SQL
- Settings migration v1 → v2
- Configurations
- Secure development policy
- Plugin development
- Adding page types
- Design
- Integration