/** * Get all searched objects ids * * @access private * @return array of object ids unsorted */ protected function _getIds() { $IDs = array(); $statusSuffix = $this->_public ? "_public" : "_edited"; //loop on each conditions foreach ($this->_whereConditions as $type => $typeWhereConditions) { foreach ($typeWhereConditions as $whereConditionsValues) { $value = $whereConditionsValues['value']; $operator = $whereConditionsValues['operator']; $sql = ''; switch ($type) { case "object": //add previously found IDs to where clause $where = $IDs ? ' and id_moo in (' . $this->_getSQLTmpList() . ')' : ''; //to remove deleted objects from results $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tid_moo as objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_object_polyobjects\n\t\t\t\t\twhere\n\t\t\t\t\t\tobject_type_id_moo = '" . $this->_object->getID() . "'\n\t\t\t\t\t\tand deleted_moo = '0'\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; break; case "item": //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; //check operator $supportedOperator = array('=', '!=', '>=', '>', '<=', '<'); if ($operator && !in_array($operator, $supportedOperator)) { $this->raiseError("Unknown search operator : " . $operator . ", use default search instead"); $operator = false; } if (!$operator) { $operator = '='; } $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_text" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " '" . $value . "'\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " '" . $value . "'\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_string" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " '" . $value . "'\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_date" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " '" . $value . "'\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; break; case "items": //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; //check operator $supportedOperator = array('in', 'not in'); if ($operator && !in_array($operator, $supportedOperator)) { $this->raiseError("Unknown search operator : " . $operator . ", use default search instead"); $operator = false; } if (!$operator) { $operator = 'in'; } //no values to found so break search if ((!is_array($value) || !$value) && $operator == 'in') { $IDs = array(); break; } //no filter to do so break search if ((!is_array($value) || !$value) && $operator == 'not in') { break; } $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_text" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_string" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\tunion distinct\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_date" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectID " . $operator . " (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; break; case "profile": //if user has no right on module, he cannot search object on it if (!$value->hasModuleClearance($this->_object->getValue('module'), CLEARANCE_MODULE_VIEW)) { break; } //if object has categories, check rights on it if ($this->_object->hasCategories()) { //get field of categories for searched object type (assume it uses categories) $categoriesFields = CMS_poly_object_catalog::objectHasCategories($this->_object->getId()); //BUG : in websites without APPLICATION_ENFORCES_ACCESS_CONTROL, backend rights on categories are checked on visibility instead of edition if (!$this->_public) { $clearance = CLEARANCE_MODULE_EDIT; $strict = true; } else { $clearance = CLEARANCE_MODULE_VIEW; $strict = false; } //get a list of all viewvable categories for current user $cats = array_keys(CMS_moduleCategories_catalog::getViewvableCategoriesForProfile($value, $this->_object->getValue('module'), true, $clearance, $strict)); foreach ($categoriesFields as $categoriesField) { //load category field if not exists if (!isset($this->_fieldsDefinitions[$categoriesField]) || !is_object($this->_fieldsDefinitions[$categoriesField])) { //get object fields definition $this->_fieldsDefinitions = CMS_poly_object_catalog::getFieldsDefinition($this->_object->getID()); } if (!isset($this->_fieldsDefinitions[$categoriesField])) { break; } //we can see objects without categories only if is not public or field is not required and user has admin right on module if ($this->_public && !$this->_fieldsDefinitions[$categoriesField]->getValue('required') || !$this->_public && $value->hasModuleClearance($this->_object->getValue('module'), CLEARANCE_MODULE_EDIT)) { //add deleted cats to searchs $viewvableCats = array_merge(CMS_moduleCategories_catalog::getDeletedCategories($this->_object->getValue('module')), $cats); //add zero value for objects without categories $viewvableCats[] = 0; } else { $viewvableCats = $cats; //add zero value for objects without categories $viewvableCats[] = 0; } //if no viewvable categories, user has no rights to view anything if (!$viewvableCats) { break; } $removedIDs = array(); //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; $sqlTmp = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\tobjectFieldID = '" . $categoriesField . "'\n\t\t\t\t\t\t\t\t\tand value not in (" . @implode(',', $viewvableCats) . ")\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t"; $qTmp = new CMS_query($sqlTmp); while ($r = $qTmp->getArray()) { if ($r['objectID'] && isset($IDs[$r['objectID']])) { $removedIDs[$r['objectID']] = $r['objectID']; } } //add (again) ids which has a category visible and a category not visible if ($removedIDs) { $sqlTmp = "\n\t\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t\tobjectFieldID = '" . $categoriesField . "'\n\t\t\t\t\t\t\t\t\t\tand value in (" . @implode(',', $viewvableCats) . ")\n\t\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t"; $qTmp = new CMS_query($sqlTmp); while ($r = $qTmp->getArray()) { if ($r['objectID'] && isset($removedIDs[$r['objectID']])) { unset($removedIDs[$r['objectID']]); } } //then finally remove ids foreach ($removedIDs as $idToRemove) { unset($IDs[$idToRemove]); } } //if no IDs break if (!$IDs) { break; } //if field is required and if it is a public search, object must have this category in DB if ($this->_fieldsDefinitions[$categoriesField]->getValue('required') && $this->_public) { //update tmp table with found ids $this->_updateTmpList($IDs); $sqlTmp = "\n\t\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t\tobjectFieldID = '" . $categoriesField . "'\n\t\t\t\t\t\t\t\t\t\tand objectID in (" . $this->_getSQLTmpList() . ")\n\t\t\t\t\t\t\t\t"; $qTmp = new CMS_query($sqlTmp); $IDs = array(); while ($r = $qTmp->getArray()) { $IDs[$r['objectID']] = $r['objectID']; } } //if no IDs break if (!$IDs) { break; } } //if no IDs break if (!$IDs) { break; } } elseif (!$this->_public && !$value->hasModuleClearance($this->_object->getValue('module'), CLEARANCE_MODULE_EDIT)) { break; } elseif ($this->_public && !$value->hasModuleClearance($this->_object->getValue('module'), CLEARANCE_MODULE_VIEW)) { break; } //update tmp table with found ids $this->_updateTmpList($IDs); //add previously found IDs to where clause $where = $IDs ? ' id_moo in (' . $this->_getSQLTmpList() . ')' : ''; $sql = "\n\t\t\t\t\t\tselect\n\t\t\t\t\t\t\tdistinct id_moo as objectID\n\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\tmod_object_polyobjects\n\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t"; break; case "keywords": if ($value) { //check operators $supportedOperator = array('any', 'all', 'phrase', 'beginswith'); if ($operator && !in_array($operator, $supportedOperator)) { $this->raiseError("Unkown search operator : " . $operator . ", use default search instead"); $operator = 'any'; } elseif (!$operator) { $operator = 'any'; } //if ASE module exists (and is active) and object is indexed, and search is public, use it to do this search if ($operator == 'any' && class_exists('CMS_module_ase') && CMS_module_ase::isActive() && $this->_object->getValue('indexable') && $this->_public) { //get language code for stemming $languageCode = ''; if ($languageFieldIDs = CMS_poly_object_catalog::objectHasLanguageField($this->_object->getID())) { $languageFieldID = array_shift($languageFieldIDs); //if any query use this field, use the queried value for stemming strategy if (isset($this->_whereConditions[$languageFieldID]) && $this->_whereConditions[$languageFieldID]) { $languageCode = $this->_whereConditions[$languageFieldID][0]['value']; } } //otherwise, we use current language if (!$languageCode) { global $cms_language; $languageCode = $cms_language->getCode(); } if (!$languageCode) { $languageCode = io::strtolower(APPLICATION_DEFAULT_LANGUAGE); } $module = $this->_object->getValue('module'); //create Xapian search object $search = new CMS_XapianQuery(trim($value), array($module), $languageCode, true); //load module interface if (!($moduleInterface = CMS_ase_interface_catalog::getModuleInterface($module))) { $this->raiseError('No active Xapian interface for module : ' . $module); return false; } //add previously found IDs to search filters $moduleInterface->addFilter('items', $IDs); //set module interface to search engine $search->setModuleInterface($module, $moduleInterface); //set page number and max results for xapian query //we must do a complete search all the time so we start from page 0 $page = 0; //we limit to a maximum of 1000 results $maxResults = 1000; //then search if (!$search->query($page, $maxResults)) { $this->raiseError('Error in Xapian query for search : ' . io::htmlspecialchars($value)); return false; } //pr($search->getQueryDesc(true)); //if no results : break if (!$search->getMatchesNumbers()) { break; } $xapianResults = $search->getMatches(); } else { //get fields if (!isset($this->_fieldsDefinitions[$type]) || !is_object($this->_fieldsDefinitions[$type])) { //get object fields definition $this->_fieldsDefinitions = CMS_poly_object_catalog::getFieldsDefinition($this->_object->getID()); } //search only in "searchable" fields $fields = array(); $aseExists = class_exists('CMS_module_ase') && CMS_module_ase::isActive() && $this->_object->getValue('indexable') ? true : false; foreach ($this->_fieldsDefinitions as $fieldDefinition) { if ($fieldDefinition->getValue($aseExists ? 'indexable' : 'searchable')) { $fields[] = $fieldDefinition->getID(); } } if (!$fields) { //if no fields after cleaning, return break; } //add previously found IDs to where clause $where = $IDs ? ' objectID in (' . $this->_getSQLTmpList() . ') and ' : ''; //filter on specified fields $where .= $fields ? ' objectFieldID in (' . implode(',', $fields) . ') and ' : ''; //clean user keywords (never trust user input, user is evil) $value = strtr($value, ",;", " "); $words = array(); $words = array_map("trim", array_unique(explode(" ", $value))); $cleanedWords = array(); foreach ($words as $aWord) { if ($aWord && $aWord != '' && io::strlen($aWord) >= 3) { $aWord = str_replace(array('%', '_'), array('\\%', '\\_'), $aWord); $cleanedWords[] = $aWord; } } if (!$cleanedWords) { //if no words after cleaning, return break; } switch ($operator) { case 'any': $where .= '('; //then add keywords $count = '0'; foreach ($cleanedWords as $aWord) { $where .= $count ? ' or ' : ''; $count++; $where .= "value like '%" . $aWord . "%'"; if (htmlentities($aWord) != $aWord) { $where .= " or value like '%" . htmlentities($aWord) . "%'"; } } $where .= ')'; break; case 'all': $where .= '('; //then add keywords $count = '0'; foreach ($cleanedWords as $aWord) { $where .= $count ? ' and ' : ''; $count++; if (htmlentities($aWord) != $aWord) { $where .= "(value like '%" . $aWord . "%' or value like '%" . htmlentities($aWord) . "%')"; } else { $where .= "value like '%" . $aWord . "%'"; } } $where .= ')'; break; case 'phrase': $value = str_replace(array('%', '_'), array('\\%', '\\_'), trim($value)); if (htmlentities($value) != $value) { $where .= "(value like '%" . $value . "%' or value like '%" . htmlentities($value) . "%')"; } else { $where .= "value like '%" . $value . "%'"; } break; case 'beginswith': $value = str_replace(array('%', '_'), array('\\%', '\\_'), trim($value)); if (htmlentities($value) != $value) { $where .= "(value like '" . $value . "%' or value like '" . htmlentities($value) . "%')"; } else { $where .= "value like '" . $value . "%'"; } break; } $sql = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_text" . $statusSuffix . "\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\tunion distinct\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\tunion distinct\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_string" . $statusSuffix . "\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\tunion distinct\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_date" . $statusSuffix . "\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t"; } } break; case "publication date after": // Date start //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; $sql = "\n\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\tand publicationDateStart_rs >= '" . $value->getDBValue(true) . "'\n\t\t\t\t\t\t\t\tand publicationDateStart_rs != '0000-00-00'\n\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t"; break; case "publication date before": // Date End //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; $sql = "\n\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\tand publicationDateStart_rs <= '" . $value->getDBValue(true) . "'\n\t\t\t\t\t\t\t\tand publicationDateStart_rs != '0000-00-00'\n\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t"; break; case "publication date end": // End Date of publication //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; $sql = "\n\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\tand (publicationDateEnd_rs >= '" . $value->getDBValue(true) . "'\n\t\t\t\t\t\t\t\tor publicationDateEnd_rs = '0000-00-00')\n\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t"; break; case "status": // Publication status //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; switch ($value) { case 'online': $sql = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\t\tand location_rs='" . RESOURCE_LOCATION_USERSPACE . "'\n\t\t\t\t\t\t\t\t\tand publication_rs='" . RESOURCE_PUBLICATION_PUBLIC . "'\n\t\t\t\t\t\t\t\t\tand publicationDateStart_rs <= '" . date('Y-m-d') . "'\n\t\t\t\t\t\t\t\t\tand publicationDateStart_rs != '0000-00-00'\n\t\t\t\t\t\t\t\t\tand (publicationDateEnd_rs >= '" . date('Y-m-d') . "'\n\t\t\t\t\t\t\t\t\tor publicationDateEnd_rs = '0000-00-00')\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t"; break; case 'offline': $sql = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\t\tand (publication_rs='" . RESOURCE_PUBLICATION_NEVERVALIDATED . "' or publication_rs='" . RESOURCE_PUBLICATION_VALIDATED . "')\n\t\t\t\t\t\t\t\t\tand (publicationDateStart_rs > '" . date('Y-m-d') . "' or publicationDateEnd_rs < '" . date('Y-m-d') . "')\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t"; break; case 'validated': $sql = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\t\tand editions_rs=0\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t"; break; case 'awaiting': $sql = "\n\t\t\t\t\t\t\t\tselect\n\t\t\t\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\t\t\t\tresources,\n\t\t\t\t\t\t\t\t\tresourceStatuses\n\t\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\t\tobjectFieldID = '0'\n\t\t\t\t\t\t\t\t\tand value = id_res\n\t\t\t\t\t\t\t\t\tand status_res=id_rs\n\t\t\t\t\t\t\t\t\tand editions_rs!=0\n\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t"; break; } break; default: //add previously found IDs to where clause $where = $IDs ? ' and objectID in (' . $this->_getSQLTmpList() . ')' : ''; if (!isset($this->_fieldsDefinitions[$type]) || !is_object($this->_fieldsDefinitions[$type])) { //get object fields definition $this->_fieldsDefinitions = CMS_poly_object_catalog::getFieldsDefinition($this->_object->getID()); } //get type object for field if (isset($this->_fieldsDefinitions[$type])) { $objectField = $this->_fieldsDefinitions[$type]->getTypeObject(); $sql = $objectField->getFieldSearchSQL($type, $value, $operator, $where, $this->_public); } else { $this->raiseError('Unknown field ' . $type . ' to filter with value ' . print_r($value, true)); } break; } if ($sql || isset($xapianResults) || isset($fullTextResults)) { if ($sql) { //pr($sql); //$this->raiseError($sql); $q = new CMS_query($sql); $IDs = array(); if (!$q->hasError()) { while ($id = $q->getValue('objectID')) { $IDs[$id] = $id; } } } elseif (isset($xapianResults)) { $IDs = array(); foreach ($xapianResults as $id) { $IDs[$id] = $id; } //if we only have objectID as orderCondition or if order by relevance is queried, use order provided by Xapian if (isset($this->_orderConditions['objectID']) && $this->_orderConditions['objectID'] && sizeof($this->_orderConditions) <= 1 || isset($this->_orderConditions['relevance']) && $this->_orderConditions['relevance']) { if ($this->_orderConditions['relevance'] == 'desc') { $this->_orderConditions = array('itemsOrdered' => array('order' => array_reverse($IDs, true))); } else { $this->_orderConditions = array('itemsOrdered' => array('order' => $IDs)); } if (isset($this->_orderConditions['relevance']) && $this->_orderConditions['relevance']) { unset($this->_orderConditions['relevance']); } } } else { //if we only have objectID as orderCondition or if order by relevance is queried, use order provided by MySQL Fulltext if (isset($this->_orderConditions['relevance']) && $this->_orderConditions['relevance']) { if ($this->_orderConditions['relevance'] == 'desc') { $this->_orderConditions = array('itemsOrdered' => array('order' => array_reverse($fullTextResults, true))); } else { $this->_orderConditions = array('itemsOrdered' => array('order' => $fullTextResults)); } unset($this->_orderConditions['relevance']); } } //if no results, no need to continue if (!$IDs) { $IDs = array(); $this->_numRows = 0; return $IDs; } //update tmp table with found ids $this->_updateTmpList($IDs); } else { //if no sql request, then no results (can be used by 'profile'), no need to continue $IDs = array(); $this->_numRows = sizeof($IDs); return $IDs; } } } $this->_numRows = sizeof($IDs); return $IDs; }
/** * Builds where statement with a key and its value * The key can be known, this class will create statements in consequence * or not known so key is understood as a field name and this * method will append a statement such $key='$value' * * @access public * @param string $key name of statement to set * @param string $value , the value to give */ function addWhereCondition($type, $value) { switch ($type) { case "language": array_push($this->_where, "language_frm='" . SensitiveIO::sanitizeSQLString($value->getCode()) . "'"); break; case "profile": if (APPLICATION_ENFORCES_ACCESS_CONTROL != false) { $a_where = CMS_moduleCategories_catalog::getViewvableCategoriesForProfile($value, MOD_CMS_FORMS_CODENAME, true); array_push($this->_tables, "modulesCategories"); array_push($this->_where, "id_mca=category_fca"); array_push($this->_tables, "mod_cms_forms_categories"); array_push($this->_where, "id_frm=form_fca"); if (sizeof($a_where)) { $a_where = array_keys($a_where); array_push($this->_where, 'category_fca in (' . @implode(',', $a_where) . ')'); } else { $a_where = array_keys($a_where); array_push($this->_where, 'category_fca = NULL'); } } break; case "category": $value = $this->_sanitizeSQLString($value); if (SensitiveIO::isPositiveInteger($value) && ($s_lineage = CMS_moduleCategories_catalog::getLineageOfCategoryAsString($value))) { array_push($this->_tables, "modulesCategories"); array_push($this->_tables, "mod_cms_forms_categories"); array_push($this->_where, "id_mca=category_fca"); array_push($this->_where, "id_frm=form_fca"); array_push($this->_where, "(lineage_mca = '" . SensitiveIO::sanitizeSQLString($s_lineage) . "' or lineage_mca like '" . SensitiveIO::sanitizeSQLString($s_lineage) . ";%')"); } break; case "keywords": $value = $this->_sanitizeSQLString($value); $kwrds = @explode(" ", $value); $kwrds = SensitiveIO::sanitizeSQLString(@implode("%", $kwrds)); if (trim($kwrds) != '%') { array_push($this->_where, "name_frm like '%" . $kwrds . "%'"); } break; default: $value = $this->_sanitizeSQLString($value); array_push($this->_where, $type . "='" . SensitiveIO::sanitizeSQLString($value) . "'"); break; } $this->_tables = @array_unique($this->_tables); $this->_where = @array_unique($this->_where); }
/** * Return categories found in given module in current language * * @static * @access public * @param array $attrs, search criteria * Array ( * "module" => string * "language" => CMS_language * "level" => integer (Default -1) * "root" => integer (Default -1) * "cms_user" => CMS_profile * "clearanceLevel" => mixed (default : false) * - false : CLEARANCE_MODULE_VIEW * - true : CLEARANCE_MODULE_EDIT * - constant value : clearanceLevel value * "strict" => boolean (default : false) * ) * @return array(CMS_moduleCategory) */ function getAll($attrs) { $items = array(); if (!$attrs["module"]) { CMS_grandFather::raiseError("Not a valid module codename given"); return $items; } if (!isset($attrs["clearanceLevel"])) { $attrs["clearanceLevel"] = false; } if (!isset($attrs["strict"])) { $attrs["strict"] = false; } //for backward compatibility if (isset($attrs["editableOnly"]) && $attrs["editableOnly"]) { $attrs["clearanceLevel"] = true; } // Prepare SQL $s_where = $s_table = ''; // Limit to module if ($attrs["module"]) { $s_where .= "\n\t\t\t\tand module_mca='" . SensitiveIO::sanitizeSQLString($attrs["module"]) . "'"; } // Limit to user permissions on module categories if (isset($attrs["cms_user"]) && is_a($attrs["cms_user"], 'CMS_profile')) { $a_where = CMS_moduleCategories_catalog::getViewvableCategoriesForProfile($attrs["cms_user"], $attrs["module"], true, $attrs["clearanceLevel"], $attrs['strict']); //pr(array_keys($a_where)); if (is_array($a_where) && $a_where) { $a_where = array_keys($a_where); $s_where .= ' and id_mca in (' . @implode(',', $a_where) . ')'; } else { //user as no permissions on categories so return nothing return array(); } } // Limit to parent and/or root categories given if (isset($attrs["level"]) && $attrs["level"] !== false && (int) $attrs["level"] > -1) { $s_where .= "\n\t\t\t\tand parent_mca='" . SensitiveIO::sanitizeSQLString($attrs["level"]) . "'"; } if (isset($attrs["root"]) && $attrs["root"] !== false && (int) $attrs["root"] > -1) { $s_where .= "\n\t\t\t\tand root_mca='" . SensitiveIO::sanitizeSQLString($attrs["root"]) . "'"; } if (isset($attrs["language"]) && is_a($attrs["language"], 'CMS_language')) { $s_table .= ',modulesCategories_i18nm '; $s_where .= "and id_mca=category_mcl and language_mcl='" . SensitiveIO::sanitizeSQLString($attrs["language"]->getCode()) . "'"; } $sql = "\n\t\t\tselect\n\t\t\t\tid_mca as id\n\t\t\tfrom\n\t\t\t\tmodulesCategories\n\t\t\t\t{$s_table}\n\t\t\twhere\n\t\t\t\t1 = 1\n\t\t\t\t{$s_where}\n\t\t\tgroup by\n\t\t\t\tid_mca\n\t\t\torder by\n\t\t\t\torder_mca asc\n\t\t"; //pr($sql); $q = new CMS_query($sql); while ($id = $q->getValue('id')) { $obj = CMS_moduleCategories_catalog::getByID($id, $attrs["language"]); if (!$obj->hasError()) { $items[] = $obj; } } return $items; }
/** * Get field search SQL request (used by class CMS_object_search) * * @param integer $fieldID : this field id in object (aka $this->_field->getID()) * @param integer $value : the category value to search * @param string $operator : additionnal search operator * @param string $where : where clauses to add to SQL * @param boolean $public : values are public or edited ? (default is edited) * @return string : the SQL request * @access public */ function getFieldSearchSQL($fieldID, $value, $operator, $where, $public = false) { $statusSuffix = $public ? "_public" : "_edited"; $supportedOperator = array('editableOnly', 'strict', 'not in', 'not in strict'); if ($operator && !in_array($operator, $supportedOperator)) { $this->raiseError("Unkown search operator : " . $operator . ", use default search instead"); $operator = false; } if ($operator == 'editableOnly') { global $cms_user; //get module codename $moduleCodename = CMS_poly_object_catalog::getModuleCodenameForField($this->_field->getID()); //get a list of all viewvable categories for current user $editableCats = array_keys(CMS_moduleCategories_catalog::getViewvableCategoriesForProfile($cms_user, $moduleCodename, true, true)); //if no viewvable categories, user has no rights to view anything if (!$editableCats) { return false; } //add previously found IDs to where clause $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\t\tand value in (" . @implode(',', $editableCats) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; $q = new CMS_query($sql); $IDs = array(); if (!$q->hasError()) { while ($id = $q->getValue('objectID')) { $IDs[$id] = $id; } } //if no results, no need to continue if (!$IDs) { return false; } $where = $IDs ? ' and objectID in (' . implode(',', $IDs) . ')' : ''; } if ($value == CMS_moduleCategory::LINEAGE_PARK_POSITION) { //if it is a public search, and field is mandatory, no objects should be returned if ($this->_field->getValue('required') && $public) { return false; } $module = CMS_poly_object_catalog::getModuleCodenameForField($fieldID); //add deleted cats to searchs $viewvableCats = CMS_moduleCategories_catalog::getDeletedCategories($module); //add zero value for objects without categories $viewvableCats[] = 0; //get object type id $objectID = CMS_poly_object_catalog::getObjectIDForField($fieldID); //first we get objects with deleted or no categories (value 0) $sqlTmp = "\n\t\t\t\tselect\n\t\t\t\t\tdistinct objectID\n\t\t\t\tfrom\n\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\twhere\n\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\tand value in (" . implode(',', $viewvableCats) . ")\n\t\t\t\t\t{$where}\n\t\t\t\t"; $qTmp = new CMS_query($sqlTmp); $deletedIDs = array(); while ($r = $qTmp->getArray()) { if ($r['objectID']) { $deletedIDs[$r['objectID']] = $r['objectID']; } } //then if we get objects with no categories at all (not referenced in mod_subobject_integer table) $sqlTmp = "\n\t\t\t\tselect\n\t\t\t\t\tdistinct objectID\n\t\t\t\tfrom\n\t\t\t\t\tmod_subobject_integer" . $statusSuffix . "\n\t\t\t\twhere\n\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\t{$where}\n\t\t\t\t"; $qTmp = new CMS_query($sqlTmp); $noCatsIDs = $catsIDs = array(); while ($r = $qTmp->getArray()) { if ($r['objectID']) { $catsIDs[$r['objectID']] = $r['objectID']; } } $IDs = array(); if (preg_match_all('#\\d+#', $where, $IDs)) { $IDs = array_shift($IDs); } $noCatsIDs = array_diff($IDs, $catsIDs); $IDs = array_merge($deletedIDs, $noCatsIDs); //if no results, no need to continue if (!$IDs) { return false; } //then we mix the too results and we return it as a fake SQL request to keep system compatibility $sql = "\n\t\t\t\tselect\n\t\t\t\t\tdistinct id_moo as objectID\n\t\t\t\tfrom\n\t\t\t\t\tmod_object_polyobjects\n\t\t\t\twhere \n\t\t\t\t\tid_moo in (" . implode(',', $IDs) . ")\n\t\t\t\t"; } else { if ($operator == 'strict') { if (!is_array($value)) { $value = array($value); } //get categories searched $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\tmodulesCategories\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\t\tand id_mca = value\n\t\t\t\t\t\tand value in (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; } elseif ($operator == 'not in strict') { if (!is_array($value)) { $value = array($value); } //get categories searched $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\tmodulesCategories\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\t\tand id_mca = value\n\t\t\t\t\t\tand value not in (" . implode(',', $value) . ")\n\t\t\t\t\t\t{$where}\n\t\t\t\t\t"; } else { if (!is_array($value)) { $value = array($value); } $lineages = array(); foreach ($value as $catID) { if ($catID) { //get lineage of category searched $lineages[] = CMS_moduleCategories_catalog::getLineageOfCategoryAsString($catID); } } $sql = ''; if ($operator == 'not in') { foreach ($lineages as $lineage) { $sql .= $sql ? ' and ' : ''; $sql .= "\n\t\t\t\t\t\tlineage_mca != '" . SensitiveIO::sanitizeSQLString($lineage) . "'\n\t\t\t\t\t\tand lineage_mca not like '" . SensitiveIO::sanitizeSQLString($lineage) . ";%' "; } } else { foreach ($lineages as $lineage) { $sql .= $sql ? ' or ' : ''; $sql .= "\n\t\t\t\t\t\tlineage_mca = '" . SensitiveIO::sanitizeSQLString($lineage) . "'\n\t\t\t\t\t\tor lineage_mca like '" . SensitiveIO::sanitizeSQLString($lineage) . ";%' "; } } $sql = "\n\t\t\t\t\tselect\n\t\t\t\t\t\tdistinct objectID\n\t\t\t\t\tfrom\n\t\t\t\t\t\tmod_subobject_integer" . $statusSuffix . ",\n\t\t\t\t\t\tmodulesCategories\n\t\t\t\t\twhere\n\t\t\t\t\t\tobjectFieldID = '" . $fieldID . "'\n\t\t\t\t\t\tand id_mca=value\n\t\t\t\t\t\t" . ($sql ? " and (" . $sql . ") " : '') . "\n\t\t\t\t\t\t{$where}"; } } return $sql; }
/** * Returns each category ID and label in a module given user can see * * @access public * @param CMS_language $cms_language, the language of the labels * @param boolean $restrictToUsedCat, restrict returned categories to used ones only (default false) * @return array(string) the statements or false if profile hasn't any access to any categories */ function getAllCategoriesAsArray($language = false, $restrictToUsedCat = false) { global $cms_user; $categories = CMS_moduleCategories_catalog::getAllCategoriesAsArray($cms_user, MOD_CMS_FORMS_CODENAME, $language); //pr($categories); if (!$restrictToUsedCat) { return $categories; } else { //Get all used categories IDS for this object field $usedCategories = CMS_forms_formularCategories::getAllUsedCategoriesForField($language); if (sizeof($usedCategories)) { //get all categories lineage $catArbo = CMS_moduleCategories_catalog::getViewvableCategoriesForProfile($cms_user, MOD_CMS_FORMS_CODENAME, true); //pr($catArbo); //need to remove all unused categories from list $categoriesToKeep = array(); foreach ($usedCategories as $catID) { $cats = explode(';', $catArbo[$catID]); foreach ($cats as $aCat) { $categoriesToKeep[$aCat] = $aCat; } } //pr($categoriesToKeep); //then remove unused categories from initial list foreach ($categories as $catID => $catLabel) { if (!isset($categoriesToKeep[$catID])) { unset($categories[$catID]); } } //pr($categories); return $categories; } else { //no categories used return array(); } } }