/**
  * @param $exerciseId
  * @param bool $addQs
  * @param bool $rmQs
  */
 public function search_engine_edit($exerciseId, $addQs = false, $rmQs = false)
 {
     // update search engine and its values table if enabled
     if (api_get_setting('search_enabled') == 'true' && extension_loaded('xapian')) {
         $course_id = api_get_course_id();
         // get search_did
         $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
         if ($addQs || $rmQs) {
             //there's only one row per question on normal db and one document per question on search engine db
             $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_second_level=%s LIMIT 1';
             $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
         } else {
             $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level=%s LIMIT 1';
             $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $exerciseId, $this->id);
         }
         $res = Database::query($sql);
         if (Database::num_rows($res) > 0 || $addQs) {
             require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
             require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
             $di = new ChamiloIndexer();
             if ($addQs) {
                 $question_exercises = array((int) $exerciseId);
             } else {
                 $question_exercises = array();
             }
             isset($_POST['language']) ? $lang = Database::escape_string($_POST['language']) : ($lang = 'english');
             $di->connectDb(null, null, $lang);
             // retrieve others exercise ids
             $se_ref = Database::fetch_array($res);
             $se_doc = $di->get_document((int) $se_ref['search_did']);
             if ($se_doc !== false) {
                 if (($se_doc_data = $di->get_document_data($se_doc)) !== false) {
                     $se_doc_data = unserialize($se_doc_data);
                     if (isset($se_doc_data[SE_DATA]['type']) && $se_doc_data[SE_DATA]['type'] == SE_DOCTYPE_EXERCISE_QUESTION) {
                         if (isset($se_doc_data[SE_DATA]['exercise_ids']) && is_array($se_doc_data[SE_DATA]['exercise_ids'])) {
                             foreach ($se_doc_data[SE_DATA]['exercise_ids'] as $old_value) {
                                 if (!in_array($old_value, $question_exercises)) {
                                     $question_exercises[] = $old_value;
                                 }
                             }
                         }
                     }
                 }
             }
             if ($rmQs) {
                 while (($key = array_search($exerciseId, $question_exercises)) !== false) {
                     unset($question_exercises[$key]);
                 }
             }
             // build the chunk to index
             $ic_slide = new IndexableChunk();
             $ic_slide->addValue("title", $this->question);
             $ic_slide->addCourseId($course_id);
             $ic_slide->addToolId(TOOL_QUIZ);
             $xapian_data = array(SE_COURSE_ID => $course_id, SE_TOOL_ID => TOOL_QUIZ, SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_QUESTION, 'exercise_ids' => $question_exercises, 'question_id' => (int) $this->id), SE_USER => (int) api_get_user_id());
             $ic_slide->xapian_data = serialize($xapian_data);
             $ic_slide->addValue("content", $this->description);
             //TODO: index answers, see also form validation on question_admin.inc.php
             $di->remove_document((int) $se_ref['search_did']);
             $di->addChunk($ic_slide);
             //index and return search engine document id
             if (!empty($question_exercises)) {
                 // if empty there is nothing to index
                 $did = $di->index();
                 unset($di);
             }
             if ($did || $rmQs) {
                 // save it to db
                 if ($addQs || $rmQs) {
                     $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_second_level=\'%s\'';
                     $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
                 } else {
                     $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=\'%s\' AND ref_id_second_level=\'%s\'';
                     $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $exerciseId, $this->id);
                 }
                 Database::query($sql);
                 if ($rmQs) {
                     if (!empty($question_exercises)) {
                         $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, ref_id_second_level, search_did)
                           VALUES (NULL , \'%s\', \'%s\', %s, %s, %s)';
                         $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, array_shift($question_exercises), $this->id, $did);
                         Database::query($sql);
                     }
                 } else {
                     $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, ref_id_second_level, search_did)
                         VALUES (NULL , \'%s\', \'%s\', %s, %s, %s)';
                     $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $exerciseId, $this->id, $did);
                     Database::query($sql);
                 }
             }
         }
     }
 }
 /**
  * Set index specified prefix terms for all items in this path
  * @param   string  Comma-separated list of terms
  * @param   char Xapian term prefix
  * @return  boolean False on error, true otherwise
  */
 public function set_terms_by_prefix($terms_string, $prefix)
 {
     $em = Database::getManager();
     $course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id());
     if (api_get_setting('search.search_enabled') !== 'true') {
         return false;
     }
     if (!extension_loaded('xapian')) {
         return false;
     }
     $terms_string = trim($terms_string);
     $terms = explode(',', $terms_string);
     array_walk($terms, 'trim_value');
     $stored_terms = $this->get_common_index_terms_by_prefix($prefix);
     // Don't do anything if no change, verify only at DB, not the search engine.
     if (count(array_diff($terms, $stored_terms)) == 0 && count(array_diff($stored_terms, $terms)) == 0) {
         return false;
     }
     require_once 'xapian.php';
     // TODO: Try catch every xapian use or make wrappers on API.
     require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
     require_once api_get_path(LIBRARY_PATH) . 'search/xapian/XapianQuery.php';
     require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
     $items_table = Database::get_course_table(TABLE_LP_ITEM);
     // TODO: Make query secure agains XSS : use member attr instead of post var.
     $lp_id = intval($_POST['lp_id']);
     $sql = "SELECT * FROM {$items_table} WHERE c_id = {$course->getId()} AND lp_id = {$lp_id}";
     $result = Database::query($sql);
     $di = new ChamiloIndexer();
     while ($lp_item = Database::fetch_array($result)) {
         $lpCourse = $em->getRepository('ChamiloCoreBundle:Course')->findOneBy(['code' => $this->cc]);
         // Get search_did.
         $se_ref = $em->getRepository('ChamiloCoreBundle:SearchEngineRef')->findOneBy(['course' => $lpCourse, 'toolId' => TOOL_LEARNPATH, 'refIdHighLevel' => $lp_id, 'refIdSecondLevel' => $lp_item['id']]);
         if ($se_ref) {
             // Compare terms.
             $doc = $di->get_document($se_ref->getSearchDid());
             $xapian_terms = xapian_get_doc_terms($doc, $prefix);
             $xterms = array();
             foreach ($xapian_terms as $xapian_term) {
                 $xterms[] = substr($xapian_term['name'], 1);
             }
             $dterms = $terms;
             $missing_terms = array_diff($dterms, $xterms);
             $deprecated_terms = array_diff($xterms, $dterms);
             // Save it to search engine.
             foreach ($missing_terms as $term) {
                 $doc->add_term($prefix . $term, 1);
             }
             foreach ($deprecated_terms as $term) {
                 $doc->remove_term($prefix . $term);
             }
             $di->getDb()->replace_document($se_ref->getSearchDid(), $doc);
             $di->getDb()->flush();
         } else {
             //@todo What we should do here?
         }
     }
     return true;
 }
 /**
  * Set index specified prefix terms for all items in this path
  * @param   string  Comma-separated list of terms
  * @param   char Xapian term prefix
  * @return  boolean False on error, true otherwise
  */
 public function set_terms_by_prefix($terms_string, $prefix)
 {
     $course_id = api_get_course_int_id();
     if (api_get_setting('search_enabled') !== 'true') {
         return false;
     }
     if (!extension_loaded('xapian')) {
         return false;
     }
     $terms_string = trim($terms_string);
     $terms = explode(',', $terms_string);
     array_walk($terms, 'trim_value');
     $stored_terms = $this->get_common_index_terms_by_prefix($prefix);
     // Don't do anything if no change, verify only at DB, not the search engine.
     if (count(array_diff($terms, $stored_terms)) == 0 && count(array_diff($stored_terms, $terms)) == 0) {
         return false;
     }
     require_once 'xapian.php';
     // TODO: Try catch every xapian use or make wrappers on API.
     require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
     require_once api_get_path(LIBRARY_PATH) . 'search/xapian/XapianQuery.php';
     require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
     $items_table = Database::get_course_table(TABLE_LP_ITEM);
     // TODO: Make query secure agains XSS : use member attr instead of post var.
     $lp_id = intval($_POST['lp_id']);
     $sql = "SELECT * FROM {$items_table} WHERE c_id = {$course_id} AND lp_id = {$lp_id}";
     $result = Database::query($sql);
     $di = new ChamiloIndexer();
     while ($lp_item = Database::fetch_array($result)) {
         // Get search_did.
         $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
         $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level=%d LIMIT 1';
         $sql = sprintf($sql, $tbl_se_ref, $this->cc, TOOL_LEARNPATH, $lp_id, $lp_item['id']);
         //echo $sql; echo '<br>';
         $res = Database::query($sql);
         if (Database::num_rows($res) > 0) {
             $se_ref = Database::fetch_array($res);
             // Compare terms.
             $doc = $di->get_document($se_ref['search_did']);
             $xapian_terms = xapian_get_doc_terms($doc, $prefix);
             $xterms = array();
             foreach ($xapian_terms as $xapian_term) {
                 $xterms[] = substr($xapian_term['name'], 1);
             }
             $dterms = $terms;
             $missing_terms = array_diff($dterms, $xterms);
             $deprecated_terms = array_diff($xterms, $dterms);
             // Save it to search engine.
             foreach ($missing_terms as $term) {
                 $doc->add_term($prefix . $term, 1);
             }
             foreach ($deprecated_terms as $term) {
                 $doc->remove_term($prefix . $term);
             }
             $di->getDb()->replace_document((int) $se_ref['search_did'], $doc);
             $di->getDb()->flush();
         } else {
             //@todo What we should do here?
         }
     }
     return true;
 }
 public function search_engine_edit($exerciseId, $addQs = false, $rmQs = false)
 {
     // update search engine and its values table if enabled
     if (api_get_setting('search.search_enabled') == 'true' && extension_loaded('xapian')) {
         $em = Database::getManager();
         $course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id());
         // get search_did
         if ($addQs || $rmQs) {
             //there's only one row per question on normal db and one document per question on search engine db
             $se_ref = $em->getRepository('ChamiloCoreBundle:SearchEngineRef')->findOneBy(['course' => $course, 'toolId' => TOOL_QUIZ, 'refIdSecondLevel' => $this->id]);
         } else {
             $se_ref = $em->getRepository('ChamiloCoreBundle:SearchEngineRef')->findOneBy(['course' => $course, 'toolId' => TOOL_QUIZ, 'refIdHighLevel' => $exerciseId, 'refIdSecondLevel' => $this->id]);
         }
         if ($se_ref || $addQs) {
             require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
             require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
             $di = new ChamiloIndexer();
             if ($addQs) {
                 $question_exercises = array((int) $exerciseId);
             } else {
                 $question_exercises = array();
             }
             isset($_POST['language']) ? $lang = Database::escape_string($_POST['language']) : ($lang = 'english');
             $di->connectDb(NULL, NULL, $lang);
             // retrieve others exercise ids
             $se_doc = $di->get_document($se_ref->getSearchDid());
             if ($se_doc !== FALSE) {
                 if (($se_doc_data = $di->get_document_data($se_doc)) !== FALSE) {
                     $se_doc_data = unserialize($se_doc_data);
                     if (isset($se_doc_data[SE_DATA]['type']) && $se_doc_data[SE_DATA]['type'] == SE_DOCTYPE_EXERCISE_QUESTION) {
                         if (isset($se_doc_data[SE_DATA]['exercise_ids']) && is_array($se_doc_data[SE_DATA]['exercise_ids'])) {
                             foreach ($se_doc_data[SE_DATA]['exercise_ids'] as $old_value) {
                                 if (!in_array($old_value, $question_exercises)) {
                                     $question_exercises[] = $old_value;
                                 }
                             }
                         }
                     }
                 }
             }
             if ($rmQs) {
                 while (($key = array_search($exerciseId, $question_exercises)) !== FALSE) {
                     unset($question_exercises[$key]);
                 }
             }
             // build the chunk to index
             $ic_slide = new IndexableChunk();
             $ic_slide->addValue("title", $this->question);
             $ic_slide->addCourseId($course->getCode());
             $ic_slide->addToolId(TOOL_QUIZ);
             $xapian_data = array(SE_COURSE_ID => $course->getCode(), SE_TOOL_ID => TOOL_QUIZ, SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_QUESTION, 'exercise_ids' => $question_exercises, 'question_id' => (int) $this->id), SE_USER => (int) api_get_user_id());
             $ic_slide->xapian_data = serialize($xapian_data);
             $ic_slide->addValue("content", $this->description);
             //TODO: index answers, see also form validation on question_admin.inc.php
             $di->remove_document($se_ref->getSearchDid());
             $di->addChunk($ic_slide);
             //index and return search engine document id
             if (!empty($question_exercises)) {
                 // if empty there is nothing to index
                 $did = $di->index();
                 unset($di);
             }
             if ($did || $rmQs) {
                 // save it to db
                 if ($addQs || $rmQs) {
                     $em->createQuery('
                             DELETE FROM ChamiloCoreBundle:SearchEngineRef ser
                             WHERE ser.course = ?1 AND ser.toolId = ?2 AND ser.refIdSecondLevel = ?3
                         ')->execute([1 => $course, 2 => TOOL_QUIZ, 3 => $this->id]);
                 } else {
                     $em->createQuery('
                             DELETE FROM ChamiloCoreBundle:SearchEngineRef ser
                             WHERE ser.course = ?1 AND
                                 ser.toolId = ?2 AND
                                 ser.refIdHighLevel = ?3 AND
                                 ser.refIdSecondLevel = ?4
                         ')->execute([1 => $course, 2 => TOOL_QUIZ, 3 => $exerciseId, 4 => $this->id]);
                 }
                 if ($rmQs) {
                     if (!empty($question_exercises)) {
                         $searchEngineRef = new \Chamilo\CoreBundle\Entity\SearchEngineRef();
                         $searchEngineRef->setCourse($course)->setToolId(TOOL_QUIZ)->setRefIdHighLevel(array_shift($question_exercises))->setRefIdSecondLevel($this->id)->setSearchDid($did);
                         $em->persist($searchEngineRef);
                         $em->flush();
                     }
                 } else {
                     $searchEngineRef = new \Chamilo\CoreBundle\Entity\SearchEngineRef();
                     $searchEngineRef->setCourse($course)->setToolId(TOOL_QUIZ)->setRefIdHighLevel($exerciseId)->setRefIdSecondLevel($this->id)->setSearchDid($did);
                     $em->persist($searchEngineRef);
                     $em->flush();
                 }
             }
         }
     }
 }