Prechádzať zdrojové kódy

Use resource/node/links in exercise creation.

CQuiz Repository added
Refactor document repository functions
Add php docs
Julio Montoya 5 rokov pred
rodič
commit
cd9a176b6d

+ 0 - 2
assets/js/exercise.js

@@ -6,5 +6,3 @@ import 'xcolor/jquery.xcolor.js';
 import '../../main/inc/lib/javascript/epiclock/javascript/jquery.dateformat.min.js';
 import '../../main/inc/lib/javascript/epiclock/javascript/jquery.epiclock.js';
 import '../../main/inc/lib/javascript/epiclock/renderers/minute/epiclock.minute.js';
-
-

+ 61 - 56
main/exercise/exercise.class.php

@@ -2,7 +2,9 @@
 /* For licensing terms, see /license.txt */
 
 use Chamilo\CoreBundle\Entity\GradebookLink;
+use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
 use Chamilo\CoreBundle\Entity\TrackEHotspot;
+use Chamilo\CoreBundle\Framework\Container;
 use Chamilo\CourseBundle\Entity\CExerciseCategory;
 use ChamiloSession as Session;
 use Doctrine\DBAL\Types\Type;
@@ -1493,11 +1495,9 @@ class Exercise
     /**
      * updates the exercise in the data base.
      *
-     * @param string $type_e
-     *
      * @author Olivier Brouckaert
      */
-    public function save($type_e = '')
+    public function save()
     {
         $_course = $this->course;
         $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
@@ -1528,6 +1528,8 @@ class Exercise
         }
         $expired_time = (int) $this->expired_time;
 
+        $repo = Container::getExerciseRepository();
+
         // Exercise already exists
         if ($id) {
             // we prepare date in the database using the api_get_utc_datetime() function
@@ -1546,53 +1548,50 @@ class Exercise
                 'description' => $description,
             ];
 
-            $paramsExtra = [];
-            if ($type_e != 'simple') {
-                $paramsExtra = [
-                    'sound' => $sound,
-                    'type' => $type,
-                    'random' => $random,
-                    'random_answers' => $random_answers,
-                    'active' => $active,
-                    'feedback_type' => $feedback_type,
-                    'start_time' => $start_time,
-                    'end_time' => $end_time,
-                    'max_attempt' => $attempts,
-                    'expired_time' => $expired_time,
-                    'propagate_neg' => $propagate_neg,
-                    'save_correct_answers' => $saveCorrectAnswers,
-                    'review_answers' => $review_answers,
-                    'random_by_category' => $randomByCat,
-                    'text_when_finished' => $text_when_finished,
-                    'display_category_name' => $display_category_name,
-                    'pass_percentage' => $pass_percentage,
-                    'results_disabled' => $results_disabled,
-                    'question_selection_type' => $this->getQuestionSelectionType(),
-                    'hide_question_title' => $this->getHideQuestionTitle(),
-                ];
+            $paramsExtra = [
+                'sound' => $sound,
+                'type' => $type,
+                'random' => $random,
+                'random_answers' => $random_answers,
+                'active' => $active,
+                'feedback_type' => $feedback_type,
+                'start_time' => $start_time,
+                'end_time' => $end_time,
+                'max_attempt' => $attempts,
+                'expired_time' => $expired_time,
+                'propagate_neg' => $propagate_neg,
+                'save_correct_answers' => $saveCorrectAnswers,
+                'review_answers' => $review_answers,
+                'random_by_category' => $randomByCat,
+                'text_when_finished' => $text_when_finished,
+                'display_category_name' => $display_category_name,
+                'pass_percentage' => $pass_percentage,
+                'results_disabled' => $results_disabled,
+                'question_selection_type' => $this->getQuestionSelectionType(),
+                'hide_question_title' => $this->getHideQuestionTitle(),
+            ];
 
-                $allow = api_get_configuration_value('allow_quiz_show_previous_button_setting');
-                if ($allow === true) {
-                    $paramsExtra['show_previous_button'] = $this->showPreviousButton();
-                }
+            $allow = api_get_configuration_value('allow_quiz_show_previous_button_setting');
+            if ($allow === true) {
+                $paramsExtra['show_previous_button'] = $this->showPreviousButton();
+            }
 
-                $allow = api_get_configuration_value('allow_exercise_categories');
-                if ($allow === true) {
-                    if (!empty($this->getExerciseCategoryId())) {
-                        $paramsExtra['exercise_category_id'] = $this->getExerciseCategoryId();
-                    }
+            $allow = api_get_configuration_value('allow_exercise_categories');
+            if ($allow === true) {
+                if (!empty($this->getExerciseCategoryId())) {
+                    $paramsExtra['exercise_category_id'] = $this->getExerciseCategoryId();
                 }
+            }
 
-                $allow = api_get_configuration_value('allow_notification_setting_per_exercise');
-                if ($allow === true) {
-                    $notifications = $this->getNotifications();
-                    $notifications = implode(',', $notifications);
-                    $paramsExtra['notifications'] = $notifications;
-                }
+            $allow = api_get_configuration_value('allow_notification_setting_per_exercise');
+            if ($allow === true) {
+                $notifications = $this->getNotifications();
+                $notifications = implode(',', $notifications);
+                $paramsExtra['notifications'] = $notifications;
+            }
 
-                if (!empty($this->pageResultConfiguration)) {
-                    $paramsExtra['page_result_configuration'] = $this->pageResultConfiguration;
-                }
+            if (!empty($this->pageResultConfiguration)) {
+                $paramsExtra['page_result_configuration'] = $this->pageResultConfiguration;
             }
 
             $params = array_merge($params, $paramsExtra);
@@ -1603,14 +1602,11 @@ class Exercise
                 ['c_id = ? AND id = ?' => [$this->course_id, $id]]
             );
 
-            // update into the item_property table
-            api_item_property_update(
-                $_course,
-                TOOL_QUIZ,
-                $id,
-                'QuizUpdated',
-                api_get_user_id()
-            );
+            $exerciseEntity = $repo->find($id);
+            $node = $exerciseEntity->getResourceNode();
+            $node->setName($exercise);
+            $repo->getEntityManager()->merge($node);
+            $repo->getEntityManager()->flush();
 
             if (api_get_setting('search_enabled') == 'true') {
                 $this->search_engine_edit();
@@ -1695,6 +1691,16 @@ class Exercise
                         WHERE id = ".$this->id." AND c_id = ".$this->course_id;
                 Database::query($sql);
 
+                $exercise = $repo->find($this->id);
+                $node = $repo->addResourceNode($exercise, api_get_user_entity(api_get_user_id()));
+                $repo->addResourceToCourse(
+                    $node,
+                    ResourceLink::VISIBILITY_PUBLISHED,
+                    api_get_course_entity(),
+                    api_get_session_entity(),
+                    api_get_group_entity()
+                );
+
                 // insert into the item_property table
                 api_item_property_update(
                     $this->course,
@@ -2567,11 +2573,10 @@ class Exercise
      * function which process the creation of exercises.
      *
      * @param FormValidator $form
-     * @param string
      *
      * @return int c_quiz.iid
      */
-    public function processCreation($form, $type = '')
+    public function processCreation($form)
     {
         $this->updateTitle(self::format_title_variable($form->getSubmitValue('exerciseTitle')));
         $this->updateDescription($form->getSubmitValue('exerciseDescription'));
@@ -2655,7 +2660,7 @@ class Exercise
             }
         }
 
-        $iId = $this->save($type);
+        $iId = $this->save();
         if (!empty($iId)) {
             $values = $form->getSubmitValues();
             $values['item_id'] = $iId;

+ 1 - 2
main/exercise/exercise_admin.php

@@ -50,8 +50,7 @@ $htmlHeadXtra[] = '<script>
     }
 
     function option_time_expired() {
-        if(document.getElementById(\'timercontrol\').style.display == \'none\')
-        {
+        if(document.getElementById(\'timercontrol\').style.display == \'none\') {
           document.getElementById(\'timercontrol\').style.display = \'block\';
         } else {
           document.getElementById(\'timercontrol\').style.display = \'none\';

+ 7 - 46
main/inc/lib/document.lib.php

@@ -6213,6 +6213,7 @@ class DocumentManager
      */
     public static function addFileToDocument(CDocument $document, $path, $realPath, $content, $visibility, $group)
     {
+        $repo = Container::getDocumentRepository();
         $debug = true;
         $fileType = $document->getFiletype();
         $resourceNode = $document->getResourceNode();
@@ -6224,13 +6225,8 @@ class DocumentManager
         $em = Database::getManager();
         $title = $document->getTitle();
 
-        // Only create a ResourceFile and Media if there's a file involved
+        // Only create a ResourceFile if there's a file involved
         if ($fileType === 'file') {
-            /** @var League\Flysystem\Adapter\Local $mediaManager */
-            //$mediaManager = Container::$container->get('oneup_flysystem.resources_filesystem');
-            /** @var League\Flysystem\Adapter\Local $mediaManager */
-            //$mediaManager = Container::$container->get('flysystem');
-            //$uploadFile = UploadedFile
             $resourceFile = $resourceNode->getResourceFile();
             if (empty($resourceFile)) {
                 $resourceFile = new ResourceFile();
@@ -6246,12 +6242,12 @@ class DocumentManager
                     $file = new UploadedFile($realPath, $title, null, null, true);
                     $resourceFile->setFile($file);
                 } else {
-                    error_log('Content');
                     // We get the content and create a file
+                    error_log('From content');
                     $handle = tmpfile();
                     fwrite($handle, $content);
                     $meta = stream_get_meta_data($handle);
-                    error_log($meta['uri']);
+                    //error_log($meta['uri']);
                     $file = new UploadedFile($meta['uri'], $title, null, null, true);
                     $resourceFile->setFile($file);
                 }
@@ -6272,47 +6268,14 @@ class DocumentManager
             $visibility = ResourceLink::VISIBILITY_PUBLISHED;
         }
 
-        $link = new ResourceLink();
-        $link
-            ->setCourse($document->getCourse())
-            ->setSession($document->getSession())
-            ->setGroup($group)
-            //->setUser($toUser)
-            ->setResourceNode($resourceNode)
-            ->setVisibility($visibility)
-        ;
-
-        $rights = [];
-        switch ($visibility) {
-            case ResourceLink::VISIBILITY_PENDING:
-            case ResourceLink::VISIBILITY_DRAFT:
-                $editorMask = ResourceNodeVoter::getEditorMask();
-                $resourceRight = new ResourceRight();
-                $resourceRight
-                    ->setMask($editorMask)
-                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
-                ;
-                $rights[] = $resourceRight;
-                break;
-        }
-
-        if (!empty($rights)) {
-            foreach ($rights as $right) {
-                $link->addResourceRight($right);
-            }
-        }
-
-        $em->persist($link);
+        $repo->addResourceToCourse($resourceNode, $visibility, $document->getCourse(), $document->getSession(), $group);
         $em->persist($document);
         $em->flush();
 
         $documentId = $document->getIid();
 
-        if ($debug) {
-            error_log($documentId);
-        }
-
         if ($documentId) {
+            error_log($documentId);
             $table = Database::get_course_table(TABLE_DOCUMENT);
             $sql = "UPDATE $table SET id = iid WHERE iid = $documentId";
             Database::query($sql);
@@ -6413,9 +6376,7 @@ class DocumentManager
         $em->persist($document);
         $em->flush();
 
-        $resourceNode = $documentRepo->addResourceNode($document, $userEntity);
-        $resourceNode->setParent($parentNode);
-        $document->setResourceNode($resourceNode);
+        $documentRepo->addResourceNode($document, $userEntity, $parentNode);
         $document = self::addFileToDocument($document, $path, $realPath, $content, $visibility, $group);
 
         if ($document) {

+ 14 - 3
src/CoreBundle/Entity/Resource/ResourceInterface.php

@@ -5,13 +5,19 @@ namespace Chamilo\CoreBundle\Entity\Resource;
 
 /**
  * Interface ResourceInterface.
- *
- * @package Chamilo\CoreBundle\Entity\Resource
  */
 interface ResourceInterface
 {
+    /**
+     * @param ResourceNode $resourceNode
+     *
+     * @return mixed
+     */
     public function setResourceNode(ResourceNode $resourceNode);
 
+    /**
+     * @return mixed
+     */
     public function getResourceNode();
 
     /**
@@ -21,9 +27,14 @@ interface ResourceInterface
      */
     public function getResourceIdentifier(): int;
 
+    /**
+     * @return string
+     */
     public function getResourceName(): string;
 
+    /**
+     * @return string
+     */
     public function getToolName(): string;
-
     //"getName()", "name()", "isName()", "hasName()", "__get()"
 }

+ 10 - 0
src/CoreBundle/Framework/Container.php

@@ -5,6 +5,7 @@ namespace Chamilo\CoreBundle\Framework;
 
 use Chamilo\CoreBundle\Component\Editor\Editor;
 use Chamilo\CourseBundle\Repository\CDocumentRepository;
+use Chamilo\CourseBundle\Repository\CQuizRepository;
 use Chamilo\PageBundle\Entity\Page;
 use Chamilo\SettingsBundle\Manager\SettingsManager;
 use Sonata\PageBundle\Entity\SiteManager;
@@ -329,6 +330,15 @@ class Container
         return self::$container->get('Chamilo\CourseBundle\Repository\CDocumentRepository');
     }
 
+
+    /**
+     * @return CQuizRepository
+     */
+    public static function getExerciseRepository()
+    {
+        return self::$container->get('Chamilo\CourseBundle\Repository\CQuizRepository');
+    }
+
     /**
      * @param UserManager
      */

+ 9 - 4
src/CoreBundle/Migrations/Schema/V200/Version20.php

@@ -55,7 +55,7 @@ class Version20 extends AbstractMigrationChamilo
         $this->addSql('ALTER TABLE faq_question_translation ADD CONSTRAINT FK_C2D1A2C2AC5D3 FOREIGN KEY (translatable_id) REFERENCES faq_question (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE faq_category_translation ADD CONSTRAINT FK_5493B0FC2C2AC5D3 FOREIGN KEY (translatable_id) REFERENCES faq_category (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE faq_question ADD CONSTRAINT FK_4A55B05912469DE2 FOREIGN KEY (category_id) REFERENCES faq_category (id);');
-        $this->addSql('ALTER TABLE contact_category_translation ADD CONSTRAINT FK_3E770F302C2AC5D3 FOREIGN KEY (translatable_id) REFERENCES contact_category (id) ON DELETE CASCADE;');
+        $this->addSql('ALTER TABLE contact_category_translavERSION20tion ADD CONSTRAINT FK_3E770F302C2AC5D3 FOREIGN KEY (translatable_id) REFERENCES contact_category (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE page__page ADD CONSTRAINT FK_2FAE39EDF6BD1646 FOREIGN KEY (site_id) REFERENCES page__site (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE page__page ADD CONSTRAINT FK_2FAE39ED727ACA70 FOREIGN KEY (parent_id) REFERENCES page__page (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE page__page ADD CONSTRAINT FK_2FAE39ED158E0B66 FOREIGN KEY (target_id) REFERENCES page__page (id) ON DELETE CASCADE;');
@@ -696,7 +696,7 @@ class Version20 extends AbstractMigrationChamilo
         $this->addSql('CREATE TABLE resource_right (id INT AUTO_INCREMENT NOT NULL, resource_link_id INT DEFAULT NULL, role VARCHAR(255) NOT NULL, mask INT NOT NULL, INDEX IDX_9F710F26F004E599 (resource_link_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT = DYNAMIC;');
         $this->addSql('CREATE TABLE resource_node (id INT AUTO_INCREMENT NOT NULL, resource_type_id INT NOT NULL, resource_file_id INT DEFAULT NULL, creator_id INT NOT NULL, parent_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, level INT DEFAULT NULL, path VARCHAR(3000) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_8A5F48FF98EC6B7B (resource_type_id), UNIQUE INDEX UNIQ_8A5F48FFCE6B9E84 (resource_file_id), INDEX IDX_8A5F48FF61220EA6 (creator_id), INDEX IDX_8A5F48FF727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT = DYNAMIC;');
         $this->addSql('CREATE TABLE resource_type (id INT AUTO_INCREMENT NOT NULL, tool_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_83FEF7938F7B22CC (tool_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT = DYNAMIC;');
-        $this->addSql('CREATE TABLE resource_file (id INT AUTO_INCREMENT NOT NULL, media_id INT DEFAULT NULL, enabled TINYINT(1) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, UNIQUE INDEX UNIQ_83BF96AAEA9FDD75 (media_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT = DYNAMIC;');
+        $this->addSql('CREATE TABLE resource_file (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, size INT NOT NULL, media_id INT DEFAULT NULL, enabled TINYINT(1) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, UNIQUE INDEX UNIQ_83BF96AAEA9FDD75 (media_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT = DYNAMIC;');
         $this->addSql('ALTER TABLE classification__tag ADD CONSTRAINT FK_CA57A1C7E25D857E FOREIGN KEY (context) REFERENCES classification__context (id);');
         $this->addSql('ALTER TABLE classification__category ADD CONSTRAINT FK_43629B36727ACA70 FOREIGN KEY (parent_id) REFERENCES classification__category (id) ON DELETE CASCADE;');
         $this->addSql('ALTER TABLE classification__category ADD CONSTRAINT FK_43629B36E25D857E FOREIGN KEY (context) REFERENCES classification__context (id);');
@@ -942,8 +942,13 @@ class Version20 extends AbstractMigrationChamilo
             $this->addSql("INSERT INTO settings_options (variable, value, display_text) VALUES ('configure_exercise_visibility_in_course','false','No')");
         }
 
-        //ALTER TABLE resource_file ADD name VARCHAR(255) NOT NULL, ADD size INT NOT NULL;
-        //ALTER TABLE resource_file_audit ADD name VARCHAR(255) DEFAULT NULL, ADD size INT DEFAULT NULL;
+        $this->addSql("ALTER TABLE c_quiz ADD resource_node_id INT DEFAULT NULL;");
+        $this->addSql("ALTER TABLE c_quiz ADD CONSTRAINT FK_B7A1C31BAD783F FOREIGN KEY (resource_node_id) REFERENCES resource_node (id)");
+        $this->addSql("CREATE UNIQUE INDEX UNIQ_B7A1C31BAD783F ON c_quiz (resource_node_id)");
+
+        $this->addSql("ALTER TABLE c_quiz_question_category ADD resource_node_id INT DEFAULT NULL");
+        $this->addSql("ALTER TABLE c_quiz_question_category ADD CONSTRAINT FK_1414369D1BAD783F FOREIGN KEY (resource_node_id) REFERENCES resource_node (id)");
+        $this->addSql("CREATE UNIQUE INDEX UNIQ_1414369D1BAD783F ON c_quiz_question_category (resource_node_id)");
     }
 
     /**

+ 85 - 34
src/CoreBundle/Repository/ResourceRepository.php

@@ -11,6 +11,7 @@ use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
 use Chamilo\CoreBundle\Entity\Session;
 use Chamilo\CoreBundle\Entity\Tool;
 use Chamilo\CoreBundle\Entity\Usergroup;
+use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
 use Chamilo\CourseBundle\Entity\CGroupInfo;
 use Chamilo\UserBundle\Entity\User;
 use Doctrine\ORM\EntityManager;
@@ -50,12 +51,14 @@ class ResourceRepository
         User $creator,
         AbstractResource $parent = null
     ): ResourceNode {
+        $em = $this->getEntityManager();
         $resourceNode = new ResourceNode();
 
-        $tool = $this->getTool($resource->getToolName());
-        $resourceType = $this->getEntityManager()->getRepository('ChamiloCoreBundle:Resource\ResourceType')->findOneBy(
+        //$tool = $this->getTool($resource->getToolName());
+        $resourceType = $em->getRepository('ChamiloCoreBundle:Resource\ResourceType')->findOneBy(
             ['name' => $resource->getToolName()]
         );
+
         $resourceNode
             ->setName($resource->getResourceName())
             ->setCreator($creator)
@@ -65,22 +68,20 @@ class ResourceRepository
             $resourceNode->setParent($parent->getResourceNode());
         }
 
-        $this->getEntityManager()->persist($resourceNode);
-        $this->getEntityManager()->flush();
+        $resource->setResourceNode($resourceNode);
+        $em->persist($resourceNode);
+        $em->persist($resource);
+        $em->flush();
 
         return $resourceNode;
     }
 
-    public function addResourceMedia(ResourceNode $resourceNode, $file)
-    {
-    }
-
     /**
      * @param ResourceNode $resourceNode
      *
      * @return ResourceLink
      */
-    public function addResourceOnlyToMe(ResourceNode $resourceNode): ResourceLink
+    public function addResourceToMe(ResourceNode $resourceNode): ResourceLink
     {
         $resourceLink = new ResourceLink();
         $resourceLink
@@ -113,6 +114,57 @@ class ResourceRepository
         return $resourceLink;
     }
 
+    /**
+     * @param ResourceNode $resourceNode
+     * @param int          $visibility
+     * @param Course       $course
+     * @param Session      $session
+     * @param CGroupInfo   $group
+     *
+     */
+    public function addResourceToCourse(ResourceNode $resourceNode, $visibility, $course, $session, $group): void
+    {
+        $visibility = (int) $visibility;
+        if (empty($visibility)) {
+            $visibility = ResourceLink::VISIBILITY_PUBLISHED;
+        }
+
+        $link = new ResourceLink();
+        $link
+            ->setCourse($course)
+            ->setSession($session)
+            ->setGroup($group)
+            //->setUser($toUser)
+            ->setResourceNode($resourceNode)
+            ->setVisibility($visibility)
+        ;
+
+        $rights = [];
+        switch ($visibility) {
+            case ResourceLink::VISIBILITY_PENDING:
+            case ResourceLink::VISIBILITY_DRAFT:
+                $editorMask = ResourceNodeVoter::getEditorMask();
+                $resourceRight = new ResourceRight();
+                $resourceRight
+                    ->setMask($editorMask)
+                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
+                ;
+                $rights[] = $resourceRight;
+                break;
+        }
+
+        if (!empty($rights)) {
+            foreach ($rights as $right) {
+                $link->addResourceRight($right);
+            }
+        }
+
+        $em = $this->getEntityManager();
+        $em->persist($link);
+        //$em->persist($document);
+        $em->flush();
+    }
+
     /**
      * @param ResourceNode  $resourceNode
      * @param Course        $course
@@ -120,7 +172,7 @@ class ResourceRepository
      *
      * @return ResourceLink
      */
-    public function addResourceToCourse(ResourceNode $resourceNode, Course $course, ResourceRight $right): ResourceLink
+    private function addResourceToCourse2(ResourceNode $resourceNode, Course $course, ResourceRight $right): ResourceLink
     {
         $resourceLink = new ResourceLink();
         $resourceLink
@@ -139,39 +191,20 @@ class ResourceRepository
      *
      * @return ResourceLink
      */
-    public function addResourceToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
+    private function addResourceToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
     {
         $resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
         $this->getEntityManager()->persist($resourceLink);
 
         return $resourceLink;
     }
-
-    /**
-     * @param ResourceNode $resourceNode
-     * @param array        $userList     User id list
-     */
-    public function addResourceToUserList(ResourceNode $resourceNode, array $userList)
-    {
-        $em = $this->getEntityManager();
-
-        if (!empty($userList)) {
-            foreach ($userList as $userId) {
-                $toUser = $em->getRepository('ChamiloUserBundle:User')->find($userId);
-
-                $resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
-                $em->persist($resourceLink);
-            }
-        }
-    }
-
     /**
      * @param ResourceNode $resourceNode
      * @param User         $toUser
      *
      * @return ResourceLink
      */
-    public function addResourceNodeToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
+    private function addResourceNodeToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
     {
         $resourceLink = new ResourceLink();
         $resourceLink
@@ -189,7 +222,7 @@ class ResourceRepository
      *
      * @return ResourceLink
      */
-    public function addResourceToSession(
+    private function addResourceToSession(
         ResourceNode $resourceNode,
         Course $course,
         Session $session,
@@ -214,7 +247,7 @@ class ResourceRepository
      *
      * @return ResourceLink
      */
-    public function addResourceToCourseGroup(
+    private function addResourceToCourseGroup(
         ResourceNode $resourceNode,
         Course $course,
         CGroupInfo $group,
@@ -238,7 +271,7 @@ class ResourceRepository
      *
      * @return ResourceLink
      */
-    public function addResourceToGroup(
+    private function addResourceToGroup(
         ResourceNode $resourceNode,
         Usergroup $group,
         ResourceRight $right
@@ -252,6 +285,24 @@ class ResourceRepository
         return $resourceLink;
     }
 
+    /**
+     * @param ResourceNode $resourceNode
+     * @param array        $userList     User id list
+     */
+    private function addResourceToUserList(ResourceNode $resourceNode, array $userList)
+    {
+        $em = $this->getEntityManager();
+
+        if (!empty($userList)) {
+            foreach ($userList as $userId) {
+                $toUser = $em->getRepository('ChamiloUserBundle:User')->find($userId);
+
+                $resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
+                $em->persist($resourceLink);
+            }
+        }
+    }
+
     /**
      * @param Course           $course
      * @param Tool             $tool

+ 5 - 2
src/CourseBundle/Entity/CDocument.php

@@ -358,7 +358,7 @@ class CDocument extends AbstractResource implements ResourceInterface
     }
 
     /**
-     * Visiblity types ResourceLink::VISIBILITY_DELETED.
+     * Visibility types ResourceLink::VISIBILITY_DELETED.
      *
      * @return int
      */
@@ -367,7 +367,10 @@ class CDocument extends AbstractResource implements ResourceInterface
         return $this->getCourseSessionResourceLink()->getVisibility();
     }
 
-    public function isVisible()
+    /**
+     * @return bool
+     */
+    public function isVisible(): bool
     {
         return $this->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED;
     }

+ 44 - 1
src/CourseBundle/Entity/CQuiz.php

@@ -3,6 +3,9 @@
 
 namespace Chamilo\CourseBundle\Entity;
 
+use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
+use Chamilo\CoreBundle\Entity\Resource\ResourceInterface;
+use Doctrine\ORM\Event\LifecycleEventArgs;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
@@ -17,7 +20,7 @@ use Doctrine\ORM\Mapping as ORM;
  * )
  * @ORM\Entity
  */
-class CQuiz
+class CQuiz extends AbstractResource implements ResourceInterface
 {
     /**
      * @var int
@@ -927,4 +930,44 @@ class CQuiz
 
         return $this;
     }
+
+    /**
+     * @ORM\PostPersist()
+     *
+     * @param LifecycleEventArgs $args
+     */
+    public function postPersist(LifecycleEventArgs $args)
+    {
+        // Update id with iid value
+        $em = $args->getEntityManager();
+        $this->setId($this->iid);
+        $em->persist($this);
+        $em->flush();
+    }
+
+    /**
+     * Resource identifier.
+     *
+     * @return int
+     */
+    public function getResourceIdentifier(): int
+    {
+        return $this->getIid();
+    }
+
+    /**
+     * @return string
+     */
+    public function getResourceName(): string
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * @return string
+     */
+    public function getToolName(): string
+    {
+        return 'quiz';
+    }
 }

+ 52 - 1
src/CourseBundle/Entity/CQuizQuestionCategory.php

@@ -3,6 +3,9 @@
 
 namespace Chamilo\CourseBundle\Entity;
 
+use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
+use Chamilo\CoreBundle\Entity\Resource\ResourceInterface;
+use Doctrine\ORM\Event\LifecycleEventArgs;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
@@ -16,7 +19,7 @@ use Doctrine\ORM\Mapping as ORM;
  * )
  * @ORM\Entity
  */
-class CQuizQuestionCategory
+class CQuizQuestionCategory extends AbstractResource implements ResourceInterface
 {
     /**
      * @var int
@@ -61,6 +64,14 @@ class CQuizQuestionCategory
      */
     protected $session;
 
+    /**
+     * @return int
+     */
+    public function getIid()
+    {
+        return $this->iid;
+    }
+
     /**
      * Set title.
      *
@@ -156,4 +167,44 @@ class CQuizQuestionCategory
     {
         return $this->cId;
     }
+
+    /**
+     * @ORM\PostPersist()
+     *
+     * @param LifecycleEventArgs $args
+     */
+    public function postPersist(LifecycleEventArgs $args)
+    {
+        // Update id with iid value
+        $em = $args->getEntityManager();
+        $this->setId($this->iid);
+        $em->persist($this);
+        $em->flush();
+    }
+
+    /**
+     * Resource identifier.
+     *
+     * @return int
+     */
+    public function getResourceIdentifier(): int
+    {
+        return $this->getIid();
+    }
+
+    /**
+     * @return string
+     */
+    public function getResourceName(): string
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * @return string
+     */
+    public function getToolName(): string
+    {
+        return 'exercise_category';
+    }
 }

+ 1 - 0
src/CourseBundle/Repository/CDocumentRepository.php

@@ -34,6 +34,7 @@ class CDocumentRepository extends ResourceRepository
      * CDocumentRepository constructor.
      *
      * @param EntityManager $entityManager
+     * @param MountManager  $mountManager
      */
     public function __construct(EntityManager $entityManager, MountManager $mountManager)
     {

+ 66 - 0
src/CourseBundle/Repository/CQuizRepository.php

@@ -0,0 +1,66 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CourseBundle\Repository;
+
+use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
+use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
+use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
+use Chamilo\CoreBundle\Repository\ResourceRepository;
+use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
+use Chamilo\CourseBundle\Entity\CQuiz;
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityRepository;
+use Gaufrette\Exception\FileNotFound;
+use League\Flysystem\FilesystemInterface;
+use League\Flysystem\MountManager;
+
+/**
+ * Class CQuizRepository.
+ */
+class CQuizRepository extends ResourceRepository
+{
+    /**
+     * @var EntityRepository
+     */
+    private $repository;
+
+    /**
+     * @var FilesystemInterface
+     */
+    private $fs;
+
+    /**
+     * CQuizRepository constructor.
+     *
+     * @param EntityManager $entityManager
+     * @param MountManager  $mountManager
+     */
+    public function __construct(EntityManager $entityManager, MountManager $mountManager)
+    {
+        $this->repository = $entityManager->getRepository(CQuiz::class);
+        $this->fs = $mountManager->getFilesystem('resources_fs');
+        $this->entityManager = $entityManager;
+    }
+
+    /**
+     * @param int $id
+     *
+     * @return CQuiz|null
+     */
+    public function find(int $id): ?CQuiz
+    {
+        return $this->repository->find($id);
+    }
+
+    /**
+     * @param array      $criteria
+     * @param array|null $orderBy
+     *
+     * @return CQuiz|null
+     */
+    public function findOneBy(array $criteria, array $orderBy = null): ?CQuiz
+    {
+        return $this->repository->findOneBy($criteria, $orderBy);
+    }
+}

+ 2 - 1
src/CourseBundle/Resources/config/services.yml

@@ -19,11 +19,12 @@ services:
     # Classic entity repositories
     Chamilo\CourseBundle\Repository\:
         resource: ../../Repository
-        exclude: '../../Repository/{CDocumentRepository.php}'
+        exclude: '../../Repository/{CDocumentRepository.php|CQuizRepository.php}'
         tags: ['doctrine.repository_service']
 
     # Entity repository as a service
     Chamilo\CourseBundle\Repository\CDocumentRepository: ~
+    Chamilo\CourseBundle\Repository\CQuizRepository: ~
 
     # Managers
     chamilo_course.entity.manager.group_manager: