/** * Split a string into a clean array of keywords * @param $text string * @param $allowWildcards boolean * @return array of keywords */ function &filterKeywords($text, $allowWildcards = false) { $minLength = Config::getVar('search', 'min_word_length'); $maxLength = Config::getVar('search', 'max_word_length'); $stopwords =& SearchIndex::loadStopwords(); // Remove punctuation if (is_array($text)) { $text = join("\n", $text); } $cleanText = String::regexp_replace('/[!"\\#\\$%\'\\(\\)\\.\\?@\\[\\]\\^`\\{\\}~]/', '', $text); $cleanText = String::regexp_replace('/[\\+,:;&\\/<=>\\|\\\\]/', ' ', $cleanText); $cleanText = String::regexp_replace('/[\\*]/', $allowWildcards ? '%' : ' ', $cleanText); $cleanText = String::strtolower($cleanText); // Split into words $words = String::regexp_split('/\\s+/', $cleanText); // FIXME Do not perform further filtering for some fields, e.g., author names? // Remove stopwords $keywords = array(); foreach ($words as $k) { if (!isset($stopwords[$k]) && String::strlen($k) >= $minLength && !is_numeric($k)) { $keywords[] = String::substr($k, 0, $maxLength); } } return $keywords; }
/** * Return a instance of SearchIndex. * @return SearchIndex Instance of SearchIndex */ public static function getInstance() { if (self::$oInstance === null) { self::$oInstance = new self(); } return self::$oInstance; }
/** * Query parsing helper routine. * Returned structure is based on that used by the Search::QueryParser Perl module. */ function _parseQuery($signTokens, $tokens, &$pos, $total) { $return = array('+' => array(), '' => array(), '-' => array()); $postBool = $preBool = ''; $notOperator = String::strtolower(__('search.operator.not')); $andOperator = String::strtolower(__('search.operator.and')); $orOperator = String::strtolower(__('search.operator.or')); while ($pos < $total) { if (!empty($signTokens[$pos])) { $sign = $signTokens[$pos]; } else { if (empty($sign)) { $sign = '+'; } } $token = String::strtolower($tokens[$pos++]); switch ($token) { case $notOperator: $sign = '-'; break; case ')': return $return; case '(': $token = Search::_parseQuery($signTokens, $tokens, $pos, $total); default: $postBool = ''; if ($pos < $total) { $peek = String::strtolower($tokens[$pos]); if ($peek == $orOperator) { $postBool = 'or'; $pos++; } else { if ($peek == $andOperator) { $postBool = 'and'; $pos++; } } } $bool = empty($postBool) ? $preBool : $postBool; $preBool = $postBool; if ($bool == 'or') { $sign = ''; } if (is_array($token)) { $k = $token; } else { $k = SearchIndex::filterKeywords($token, true); } if (!empty($k)) { $return[$sign][] = $k; } $sign = ''; break; } } return $return; }
public function __actionEdit() { $synonym = $_POST['synonym']; // remove existing instance of hash if ($synonym['hash'] != '') { unset($this->_synonyms[$synonym['hash']]); } $this->_synonyms[sha1($synonym['word'])] = array('word' => $synonym['word'], 'synonyms' => $synonym['synonyms']); SearchIndex::saveSynonyms($this->_synonyms); redirect("{$this->_uri}/synonyms/"); }
/** * コンテンツメタ情報を更新する * * @param Model $model * @return boolean */ public function updateSearchIndexMeta(Model $model) { $db = ConnectionManager::getDataSource('default'); $contentTypes = array(); $searchIndexes = $this->SearchIndex->find('all', array('fields' => array('SearchIndex.type'), 'group' => array('SearchIndex.type'), 'conditions' => array('SearchIndex.status' => true))); foreach ($searchIndexes as $searchIndex) { if ($searchIndex['SearchIndex']['type']) { $contentTypes[$searchIndex['SearchIndex']['type']] = $searchIndex['SearchIndex']['type']; } } $siteConfigs['SiteConfig']['content_types'] = BcUtil::serialize($contentTypes); $SiteConfig = ClassRegistry::init('SiteConfig'); return $SiteConfig->saveKeyValue($siteConfigs); }
/** * @method POST */ function get() { parse_str($this->request->data, $request); // parse request $term = $request['term']; $language = $request['language']; $siteUniqId = SITE_UNIQ_ID; $site = Site::GetBySiteUniqId($siteUniqId); $showSecure = false; if (isset($_SESSION[$site['FriendlyId'] . '.UserId'])) { $showSecure = true; } $results = SearchIndex::Search($siteUniqId, $language, $term, $showSecure); // return a json response $response = new Tonic\Response(Tonic\Response::OK); $response->contentType = 'application/json'; $response->body = json_encode($results); return $response; }
public function __viewIndex() { // create a DS and filter on System ID of the current entry to build the entry's XML $ds = new ReindexDataSource(Administration::instance(), NULL, FALSE); $ds->dsSource = (string) $_GET['section']; $ds->dsParamFILTERS = $this->_index['filters']; $param_pool = array(); $grab_xml = $ds->grab($param_pool); $xml = $grab_xml->generate(); $dom = new DomDocument(); $dom->loadXML($xml); $xpath = new DomXPath($dom); foreach ($xpath->query("//entry") as $entry) { $context = (object) array('section' => $this->_section, 'entry' => reset($this->_entryManager->fetch($entry->getAttribute('id')))); SearchIndex::indexEntry($context->entry, $context->section); } header('Content-type: text/xml'); echo $xml; exit; }
/** * Resets all references to other model objects or collections of model objects. * * This method is a user-space workaround for PHP's inability to garbage collect * objects with circular references (even in PHP 5.3). This is currently necessary * when using Propel in certain daemon or large-volume/high-memory operations. * * @param boolean $deep Whether to also clear the references on all referrer objects. */ public function clearAllReferences($deep = false) { if ($deep && !$this->alreadyInClearAllReferencesDeep) { $this->alreadyInClearAllReferencesDeep = true; if ($this->aSearchIndex instanceof Persistent) { $this->aSearchIndex->clearAllReferences($deep); } if ($this->aUserRelatedByCreatedBy instanceof Persistent) { $this->aUserRelatedByCreatedBy->clearAllReferences($deep); } if ($this->aUserRelatedByUpdatedBy instanceof Persistent) { $this->aUserRelatedByUpdatedBy->clearAllReferences($deep); } $this->alreadyInClearAllReferencesDeep = false; } // if ($deep) $this->aSearchIndex = null; $this->aUserRelatedByCreatedBy = null; $this->aUserRelatedByUpdatedBy = null; }
public function __viewIndex() { // create a DS and filter on System ID of the current entry to build the entry's XML $ds = new ReindexDataSource(NULL, FALSE); $ds->dsSource = (string) $_GET['section']; $ds->dsParamFILTERS = $this->_index['filters']; $param_pool = array(); $grab_xml = $ds->grab($param_pool); $xml = $grab_xml->generate(); $dom = new DomDocument(); $dom->loadXML($xml); $xpath = new DomXPath($dom); $entry_ids = array(); foreach ($xpath->query("//entry") as $entry) { $entry_ids[] = $entry->getAttribute('id'); } SearchIndex::indexEntry($entry_ids, $ds->dsSource, FALSE); header('Content-type: text/xml'); echo $xml; exit; }
/** * Delete this entry's search index * * @param object $context */ public function deleteEntryIndex($context) { SearchIndex::deleteIndexByEntry($context['entry_id']); }
/** * Parse the indexable content for an entry * * @param int $entry * @param int $section */ public function indexEntry($entry, $section, $check_filters = TRUE) { self::assert(); if (is_object($entry)) { $entry = $entry->get('id'); } if (is_object($section)) { $section = $section->get('id'); } // get a list of sections that have indexing enabled $indexed_sections = self::getIndexes(); // go no further if this section isn't being indexed if (!isset($indexed_sections[$section])) { return; } // delete existing index for this entry self::deleteIndexByEntry($entry); // get the current section index config $section_index = $indexed_sections[$section]; // only pass entries through filters if we need to. If entry is being sent // from the Re-Index AJAX it has already gone through filtering, so no need here if ($check_filters === TRUE) { if (self::$_where == NULL || self::$_joins == NULL) { // modified from class.datasource.php // create filters and build SQL required for each if (is_array($section_index['filters']) && !empty($section_index['filters'])) { foreach ($section_index['filters'] as $field_id => $filter) { if (is_array($filter) && empty($filter) || trim($filter) == '') { continue; } if (!is_array($filter)) { $filter_type = DataSource::__determineFilterType($filter); $value = preg_split('/' . ($filter_type == DS_FILTER_AND ? '\\+' : ',') . '\\s*/', $filter, -1, PREG_SPLIT_NO_EMPTY); $value = array_map('trim', $value); } else { $value = $filter; } $field = self::$_entry_manager->fieldManager->fetch($field_id); $field->buildDSRetrivalSQL($value, $joins, $where, $filter_type == DS_FILTER_AND ? TRUE : FALSE); } } self::$_where = $where; self::$_joins = $joins; } // run entry though filters $entry_prefilter = self::$_entry_manager->fetch($entry, $section, 1, 0, self::$_where, self::$_joins, FALSE, FALSE); // if no entry found, it didn't pass the pre-filtering if (empty($entry_prefilter)) { return; } // if entry passes filtering, pass entry_id as a DS filter to the EntryXMLDataSource DS $entry = reset($entry_prefilter); $entry = $entry['id']; } if (!is_array($entry)) { $entry = array($entry); } // create a DS and filter on System ID of the current entry to build the entry's XML #$ds = new EntryXMLDataSource(Administration::instance(), NULL, FALSE); self::$_entry_xml_datasource->dsParamINCLUDEDELEMENTS = $indexed_sections[$section]['fields']; self::$_entry_xml_datasource->dsParamFILTERS['id'] = implode(',', $entry); self::$_entry_xml_datasource->dsSource = (string) $section; $param_pool = array(); $entry_xml = self::$_entry_xml_datasource->grab($param_pool); require_once TOOLKIT . '/class.xsltprocess.php'; $xml = simplexml_load_string($entry_xml->generate()); /* MULTILANGUAGE SUPPORT: */ require_once TOOLKIT . '/class.extensionmanager.php'; require_once TOOLKIT . '/class.fieldmanager.php'; $fieldManager = new FieldManager($this); $extensionManager = new ExtensionManager($this); $status = $extensionManager->fetchStatus('multilanguage'); $multilingualFields = array(); $languages = array(); if ($status == EXTENSION_ENABLED) { // Check if this section has multilingual fields: $results = Symphony::Database()->fetch('SELECT `element_name` FROM `tbl_fields` WHERE `parent_section` = ' . $section . ' AND `multilanguage` = 1;'); foreach ($results as $result) { $multilingualFields[] = $result['element_name']; } $languages = explode(',', file_get_contents(MANIFEST . '/multilanguage-languages')); } foreach ($xml->xpath("//entry") as $entry_xml) { // get text value of the entry (default behaviour) $proc = new XsltProcess(); $data = $proc->process($entry_xml->asXML(), file_get_contents(EXTENSIONS . '/search_index/lib/parse-entry.xsl')); $dataLanguages = array(); foreach ($languages as $language) { foreach ($entry_xml->children() as $child) { $name = $child->getName(); if (in_array($name, $multilingualFields)) { // Bingo! // Get the correct value for this item: $field_id = $fieldManager->fetchFieldIDFromElementName($name); $entry_id = $entry_xml->attributes()->id; $values = Symphony::Database()->fetch('SELECT * FROM `tbl_multilanguage_values` WHERE `id_entry` = ' . $entry_id . ' AND `id_field` = ' . $field_id . ' AND `language` = \'' . $language . '\';'); if (count($values) >= 1) { // Value found: foreach ($values as $value) { switch ($value['field_name']) { case 'value': $entry_xml->{$name} = $value['value']; break; } } } } } // Store it: $proc = new XsltProcess(); $dataLanguages[$language] = $proc->process($entry_xml->asXML(), file_get_contents(EXTENSIONS . '/search_index/lib/parse-entry.xsl')); } self::saveEntryIndex((int) $entry_xml->attributes()->id, $section, $data, $dataLanguages); /* END MULTILANGUAGE SUPPORT */ } }
public function execute(array &$param_pool = null) { $result = new XMLElement($this->dsParamROOTELEMENT); $config = (object) Symphony::Configuration()->get('search_index'); // Setup /*-----------------------------------------------------------------------*/ // look for key in GET array if it's specified if (!empty($config->{'get-param-prefix'})) { if ($config->{'get-param-prefix'} == 'param_pool') { $_GET = $this->_env['param']; } else { $_GET = $_GET[$config->{'get-param-prefix'}]; } } // get input parameters from GET request $param_keywords = isset($_GET[$config->{'get-param-keywords'}]) ? trim($_GET[$config->{'get-param-keywords'}]) : ''; $param_sort = isset($_GET[$config->{'get-param-sort'}]) ? $_GET[$config->{'get-param-sort'}] : $config->{'default-sort'}; $param_direction = isset($_GET[$config->{'get-param-direction'}]) ? strtolower($_GET[$config->{'get-param-direction'}]) : $config->{'default-direction'}; // set pagination on the data source $this->dsParamSTARTPAGE = isset($_GET[$config->{'get-param-page'}]) ? (int) $_GET[$config->{'get-param-page'}] : $this->dsParamSTARTPAGE; $this->dsParamLIMIT = isset($_GET[$config->{'get-param-per-page'}]) && (int) $_GET[$config->{'get-param-per-page'}] > 0 ? (int) $_GET[$config->{'get-param-per-page'}] : $config->{'default-per-page'}; // build ORDER BY statement for later switch ($param_sort) { case 'date': $sql_order_by = "e.creation_date {$param_direction}"; break; case 'id': $sql_order_by = "e.id {$param_direction}"; break; default: $sql_order_by = "score {$param_direction}"; break; } // Find valid sections to query /*-----------------------------------------------------------------------*/ if (isset($_GET[$config->{'get-param-sections'}]) && !empty($_GET[$config->{'get-param-sections'}])) { $param_sections = $_GET[$config->{'get-param-sections'}]; // allow sections to be sent as an array if the user wishes (multi-select or checkboxes) if (is_array($param_sections)) { implode(',', $param_sections); } } elseif (!empty($config->{'default-sections'})) { $param_sections = $config->{'default-sections'}; } else { $param_sections = ''; } $sections = array(); foreach (array_map('trim', explode(',', $param_sections)) as $handle) { $section = Symphony::Database()->fetchRow(0, sprintf("SELECT `id`, `name` FROM `tbl_sections` WHERE handle = '%s' LIMIT 1", Symphony::Database()->cleanValue($handle))); if ($section) { $sections[$section['id']] = array('handle' => $handle, 'name' => $section['name']); } } if (count($sections) == 0) { return $this->errorXML('Invalid search sections'); } // Set up and manipulate keywords /*-----------------------------------------------------------------------*/ // should we apply word stemming? $do_stemming = $config->{'stem-words'} == 'yes' ? TRUE : FALSE; // replace synonyms $keywords = SearchIndex::applySynonyms($param_keywords); $keywords_boolean = SearchIndex::parseKeywordString($keywords, $do_stemming); $keywords_highlight = trim(implode(' ', $keywords_boolean['highlight']), '"'); // Set up weighting /*-----------------------------------------------------------------------*/ $sql_weighting = ''; foreach (SearchIndex::getIndexes() as $section_id => $index) { $weight = isset($index['weighting']) ? $index['weighting'] : 2; switch ($weight) { case 0: $weight = 4; break; // highest // highest case 1: $weight = 2; break; // high // high case 2: $weight = 1; break; // none // none case 3: $weight = 0.5; break; // low // low case 4: $weight = 0.25; break; // lowest } $sql_weighting .= sprintf("WHEN e.section_id = %d THEN %d \n", $section_id, $weight); } // Build search SQL /*-----------------------------------------------------------------------*/ $mode = !is_null($config->{'mode'}) ? $config->{'mode'} : 'like'; $mode = strtoupper($mode); switch ($mode) { case 'FULLTEXT': $sql = sprintf("SELECT\n\t\t\t\t\t\t\tSQL_CALC_FOUND_ROWS\n\t\t\t\t\t\t\te.id as `entry_id`,\n\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\te.section_id as `section_id`,\n\t\t\t\t\t\t\tUNIX_TIMESTAMP(e.creation_date) AS `creation_date`,\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tMATCH(index.data) AGAINST ('%1\$s') *\n\t\t\t\t\t\t\t\tCASE\n\t\t\t\t\t\t\t\t\t%2\$s\n\t\t\t\t\t\t\t\t\tELSE 1\n\t\t\t\t\t\t\t\tEND\n\t\t\t\t\t\t\t\t%3\$s\n\t\t\t\t\t\t\t) AS `score`\n\t\t\t\t\t\tFROM\n\t\t\t\t\t\t\ttbl_search_index as `index`\n\t\t\t\t\t\t\tJOIN tbl_entries as `e` ON (index.entry_id = e.id)\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\tMATCH(index.data) AGAINST ('%4\$s' IN BOOLEAN MODE)\n\t\t\t\t\t\t\tAND e.section_id IN ('%5\$s')\n\t\t\t\t\t\tORDER BY\n\t\t\t\t\t\t\t%6\$s\n\t\t\t\t\t\tLIMIT %7\$d, %8\$d", Symphony::Database()->cleanValue($keywords), $sql_weighting, $param_sort == 'score-recency' ? '/ SQRT(GREATEST(1, DATEDIFF(NOW(), creation_date)))' : '', Symphony::Database()->cleanValue($keywords), implode("','", array_keys($sections)), Symphony::Database()->cleanValue($sql_order_by), max(0, ($this->dsParamSTARTPAGE - 1) * $this->dsParamLIMIT), (int) $this->dsParamLIMIT); break; case 'LIKE': case 'REGEXP': $sql_locate = ''; $sql_replace = ''; $sql_where = ''; // by default, no wildcard separators $prefix = ''; $suffix = ''; // append wildcard for LIKE if ($mode == 'LIKE') { $prefix = $suffix = '%'; } // apply word boundary separator if ($mode == 'REGEXP') { $prefix = '[[:<:]]'; $suffix = '[[:>:]]'; } // all words to include in the query (single words and phrases) foreach ($keywords_boolean['include-words-all'] as $keyword) { $keyword_stem = NULL; $keyword = Symphony::Database()->cleanValue($keyword); if ($do_stemming) { $keyword_stem = Symphony::Database()->cleanValue(PorterStemmer::Stem($keyword)); } // if the word can be stemmed, look for the word or the stem version if ($do_stemming && $keyword_stem != $keyword) { $sql_where .= "(index.data {$mode} '{$prefix}{$keyword}{$suffix}' OR index.data {$mode} '{$prefix}{$keyword}{$suffix}') AND "; } else { $sql_where .= "index.data {$mode} '{$prefix}{$keyword}{$suffix}' AND "; } // if this keyword exists in the entry contents, add 1 to "keywords_matched" // which represents number of unique keywords in the search string that are found $sql_locate .= "IF(LOCATE('{$keyword}', LOWER(`data`)) > 0, 1, 0) + "; // see how many times this word is found in the entry contents by removing it from // the column text then compare length to see how many times it was removed $sql_replace .= "(LENGTH(`data`) - LENGTH(REPLACE(LOWER(`data`),LOWER('{$keyword}'),''))) / LENGTH('{$keyword}') + "; } // all words or phrases that we do not want foreach ($keywords_boolean['exclude-words-all'] as $keyword) { $keyword = Symphony::Database()->cleanValue($keyword); $sql_where .= "index.data NOT {$mode} '{$prefix}{$keyword}{$suffix}' AND "; } // append to complete SQL $sql_locate = $sql_locate == '' ? $sql_locate = '1' : ($sql_locate .= '0'); $sql_replace = $sql_replace == '' ? $sql_replace = '1' : ($sql_replace .= '0'); $sql_where = $sql_where == '' ? $sql_where = 'NOT 1' : $sql_where; // trim unnecessary boolean conditions from SQL $sql_where = preg_replace("/ OR \$/", "", $sql_where); $sql_where = preg_replace("/ AND \$/", "", $sql_where); // if ordering by score, use a function of the two columns // we are calculating rather than just "score" if (preg_match("/^score/", $sql_order_by)) { $sql_order_by = preg_replace("/^score/", "(keywords_matched * score)", $sql_order_by); } $sql = sprintf("SELECT\n\t\t\t\t\t\t\tSQL_CALC_FOUND_ROWS\n\t\t\t\t\t\t\te.id as `entry_id`,\n\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\te.section_id as `section_id`,\n\t\t\t\t\t\t\tUNIX_TIMESTAMP(e.creation_date) AS `creation_date`,\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t%1\$s\n\t\t\t\t\t\t\t) AS keywords_matched,\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t(%2\$s)\n\t\t\t\t\t\t\t\t*\n\t\t\t\t\t\t\t\tCASE\n\t\t\t\t\t\t\t\t\t%3\$s\n\t\t\t\t\t\t\t\t\tELSE 1\n\t\t\t\t\t\t\t\tEND\n\t\t\t\t\t\t\t\t%4\$s\n\t\t\t\t\t\t\t) AS score\n\t\t\t\t\t\tFROM\n\t\t\t\t\t\t\ttbl_search_index as `index`\n\t\t\t\t\t\t\tJOIN tbl_entries as `e` ON (index.entry_id = e.id)\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t%5\$s\n\t\t\t\t\t\t\tAND e.section_id IN ('%6\$s')\n\t\t\t\t\t\tORDER BY\n\t\t\t\t\t\t\t%7\$s\n\t\t\t\t\t\tLIMIT\n\t\t\t\t\t\t\t%8\$d, %9\$d", $sql_locate, $sql_replace, $sql_weighting, $param_sort == 'score-recency' ? '/ SQRT(GREATEST(1, DATEDIFF(NOW(), creation_date)))' : '', $sql_where, implode("','", array_keys($sections)), Symphony::Database()->cleanValue($sql_order_by), max(0, ($this->dsParamSTARTPAGE - 1) * $this->dsParamLIMIT), (int) $this->dsParamLIMIT); //echo $sql;die; break; } // Add soundalikes ("did you mean?") to XML /*-----------------------------------------------------------------------*/ // we have search words, check for soundalikes if (count($keywords_boolean['include-words-all']) > 0) { $sounds_like = array(); foreach ($keywords_boolean['include-words-all'] as $word) { $soundalikes = Symphony::Database()->fetchCol('keyword', sprintf("SELECT keyword FROM tbl_search_index_keywords WHERE SOUNDEX(keyword) = SOUNDEX('%s')", Symphony::Database()->cleanValue($word))); foreach ($soundalikes as $i => &$soundalike) { if ($soundalike == $word) { unset($soundalikes[$i]); continue; } $soundalike = array('word' => $soundalike, 'distance' => levenshtein($soundalike, $word)); } usort($soundalikes, array('datasourcesearch', 'sortWordDistance')); $sounds_like[$word] = $soundalikes[0]['word']; } // add words to XML if (count($sounds_like) > 0) { $alternative_spelling = new XMLElement('alternative-keywords'); foreach ($sounds_like as $word => $soundalike) { $alternative_spelling->appendChild(new XMLElement('keyword', NULL, array('original' => $word, 'alternative' => $soundalike, 'distance' => levenshtein($soundalike, $word)))); } $result->appendChild($alternative_spelling); } } // Run search SQL! /*-----------------------------------------------------------------------*/ // get our entries, returns entry IDs $entries = Symphony::Database()->fetch($sql); $total_entries = Symphony::Database()->fetchVar('total', 0, 'SELECT FOUND_ROWS() AS `total`'); // append input values $result->setAttributeArray(array('keywords' => General::sanitize($keywords), 'sort' => General::sanitize($param_sort), 'direction' => General::sanitize($param_direction))); // append pagination $result->appendChild(General::buildPaginationElement($total_entries, ceil($total_entries * (1 / $this->dsParamLIMIT)), $this->dsParamLIMIT, $this->dsParamSTARTPAGE)); // append list of sections $sections_xml = new XMLElement('sections'); foreach ($sections as $id => $section) { $sections_xml->appendChild(new XMLElement('section', General::sanitize($section['name']), array('id' => $id, 'handle' => $section['handle']))); } $result->appendChild($sections_xml); // Append entries to XML, build if desired /*-----------------------------------------------------------------------*/ // if true then the entire entry will be appended to the XML. If not, only // a "stub" of the entry ID is provided, allowing other data sources to // supplement with the necessary fields $build_entries = $config->{'build-entries'} == 'yes' ? TRUE : FALSE; if ($build_entries) { $field_pool = array(); } // container for entry ID output parameter $param_output = array(); foreach ($entries as $entry) { $param_output[] = $entry['entry_id']; $entry_xml = new XMLElement('entry', NULL, array('id' => $entry['entry_id'], 'section' => $sections[$entry['section_id']]['handle'])); // add excerpt with highlighted search terms $excerpt = SearchIndex::parseExcerpt($keywords_highlight, $entry['data']); $excerpt = $this->fixEncoding($excerpt); $entry_xml->appendChild(new XMLElement('excerpt', $excerpt)); // build and append entry data if ($build_entries) { $e = reset(EntryManager::fetch($entry['entry_id'])); $data = $e->getData(); foreach ($data as $field_id => $values) { if (!isset($field_pool[$field_id]) || !is_object($field_pool[$field_id])) { $field_pool[$field_id] = FieldManager::fetch($field_id); } $field_pool[$field_id]->appendFormattedElement($entry_xml, $values, FALSE, !empty($values['value_formatted']) ? 'formatted' : null, $e->get('id')); } } $result->appendChild($entry_xml); } // send entry IDs as Output Parameterss $param_pool['ds-' . $this->dsParamROOTELEMENT . '.id'] = $param_output; $param_pool['ds-' . $this->dsParamROOTELEMENT] = $param_output; // Log query /*-----------------------------------------------------------------------*/ if ($config->{'log-keywords'} == 'yes' && trim($keywords)) { $section_handles = array_map('reset', array_values($sections)); // has this search (keywords+sections) already been logged this session? $already_logged = Symphony::Database()->fetch(sprintf("SELECT * FROM `tbl_search_index_logs` WHERE keywords='%s' AND sections='%s' AND session_id='%s'", Symphony::Database()->cleanValue($param_keywords), Symphony::Database()->cleanValue(implode(',', $section_handles)), session_id())); $log_sql = sprintf("INSERT INTO `tbl_search_index_logs`\n\t\t\t\t\t(date, keywords, keywords_manipulated, sections, page, results, session_id)\n\t\t\t\t\tVALUES('%s', '%s', '%s', '%s', %d, %d, '%s')", date('Y-m-d H:i:s', time()), Symphony::Database()->cleanValue($param_keywords), Symphony::Database()->cleanValue($keywords), Symphony::Database()->cleanValue(implode(',', $section_handles)), $this->dsParamSTARTPAGE, $total_entries, session_id()); Symphony::Database()->query($log_sql); } return $result; }
<h1>Cross References</h1> <ul>'; foreach ($law->references as $reference) { $sidebar .= '<li><span class="identifier">' . SECTION_SYMBOL . ' <a href="' . $reference->url . '" class="law">' . $reference->section_number . '</a></span> <span class="title">' . $reference->catch_line . '</li>'; } $sidebar .= '</ul> </section>'; } /* * If we have a list of related laws, list them. * Note that Solr < 4.6 will probably die horribly trying this. * We catch any exceptions as a result and go about our business. */ try { $search_client = new SearchIndex(array('config' => json_decode(SEARCH_CONFIG, TRUE))); $related_laws = $search_client->find_related($law, 3); if ($related_laws && count($related_laws->get_results()) > 0) { $sidebar .= ' <section class="related-group grid-box" id="related-links"> <h1>Related Laws</h1> <ul id="related">'; $related_law = new Law(); foreach ($related_laws->get_results() as $result) { $related_law->law_id = $result->law_id; $related_law->get_law(); $related_law->permalink = $related_law->get_url($result->law_id); $sidebar .= '<li>' . SECTION_SYMBOL . ' <a href="' . $related_law->permalink->url . '">' . $related_law->section_number . '</a> ' . $related_law->catch_line . '</li>'; } $sidebar .= ' </ul>
/** * Filter the query by a related SearchIndex object * * @param SearchIndex|PropelObjectCollection $searchIndex The related object(s) to use as filter * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return SearchIndexWordQuery The current query, for fluid interface * @throws PropelException - if the provided filter is invalid. */ public function filterBySearchIndex($searchIndex, $comparison = null) { if ($searchIndex instanceof SearchIndex) { return $this->addUsingAlias(SearchIndexWordPeer::SEARCH_INDEX_ID, $searchIndex->getId(), $comparison); } elseif ($searchIndex instanceof PropelObjectCollection) { if (null === $comparison) { $comparison = Criteria::IN; } return $this->addUsingAlias(SearchIndexWordPeer::SEARCH_INDEX_ID, $searchIndex->toKeyValue('Id', 'Id'), $comparison); } else { throw new PropelException('filterBySearchIndex() only accepts arguments of type SearchIndex or PropelCollection'); } }
private function index(array $aPath) { $oNavigationItem = $this->oRootNavigationItem; PageNavigationItem::clearCache(); while (count($aPath) > 0) { $oNavigationItem = $oNavigationItem->namedChild(array_shift($aPath), $this->sLanguageId, true, true); } FilterModule::getFilters()->handleNavigationPathFound($this->oRootNavigationItem, $oNavigationItem); FrontendManager::$CURRENT_NAVIGATION_ITEM = $oNavigationItem; $oPageNavigationItem = $oNavigationItem; while (!$oPageNavigationItem instanceof PageNavigationItem) { $oPageNavigationItem = $oPageNavigationItem->getParent(); } FrontendManager::$CURRENT_PAGE = $oPageNavigationItem->getMe(); $oPage = FrontendManager::$CURRENT_PAGE; $bIsNotFound = false; FilterModule::getFilters()->handlePageHasBeenSet($oPage, $bIsNotFound, $oNavigationItem); FilterModule::getFilters()->handleRequestStarted(); FilterModule::getFilters()->handlePageNotFoundDetectionComplete($bIsNotFound, $oPage, $oNavigationItem, array(&$bIsNotFound)); if ($bIsNotFound) { return false; } $sDescription = $oNavigationItem->getDescription($this->sLanguageId); if ($sDescription === null) { $sDescription = $oPage->getDescription($this->sLanguageId); } $aKeywords = array(); foreach ($oPage->getConsolidatedKeywords($this->sLanguageId, true) as $sKeyword) { $aKeywords = array_merge($aKeywords, StringUtil::getWords($sKeyword)); } $sTitle = $oNavigationItem->getTitle($this->sLanguageId); $sLinkText = $oNavigationItem->getLinkText($this->sLanguageId); if (!$sLinkText) { $sLinkText = $sTitle; } $sName = $oNavigationItem->getName(); // Page type can prevent indexing if (!self::doIndex($oPage->getPageType(), $oNavigationItem)) { return false; } $oPageType = PageTypeModule::getModuleInstance($oPage->getPageType(), $oPage, $oNavigationItem); $aWords = $oPageType->getWords(); $aWords = array_merge($aWords, StringUtil::getWords($sDescription), $aKeywords, StringUtil::getWords($sTitle), StringUtil::getWords($sLinkText), array($sName)); $aPagePath = $oPage->getLink(); $aNavigationItemPath = $oNavigationItem->getLink(); $sPath = implode('/', array_diff($aNavigationItemPath, $aPagePath)); $oSearchIndex = new SearchIndex(); $oSearchIndex->setPageId($oPage->getId()); $oSearchIndex->setPath($sPath); $oSearchIndex->setLinkText($sLinkText); $oSearchIndex->setPageTitle($sTitle); $oSearchIndex->setLanguageId($this->sLanguageId); $oSearchIndex->save(); foreach ($aWords as $sWord) { $sWord = Synonyms::rootFor($sWord, $this->sLanguageId); $oSearchIndexWord = SearchIndexWordQuery::create()->filterBySearchIndex($oSearchIndex)->filterByWord($sWord)->findOne(); if ($oSearchIndexWord === null) { $oSearchIndexWord = new SearchIndexWord(); $oSearchIndexWord->setSearchIndex($oSearchIndex); $oSearchIndexWord->setWord($sWord); } else { $oSearchIndexWord->incrementCount(); } $oSearchIndexWord->save(); } return true; }
function insertRecordCallback($hookName, $args) { // Handle the record. $record =& $args[0]; $schemaPlugin =& $record->getSchemaPlugin(); $schemaPluginName = $schemaPlugin->getName(); $fieldDao =& DAORegistry::getDAO('FieldDAO'); foreach ($schemaPlugin->getFieldList() as $fieldName) { $field =& $fieldDao->buildField($fieldName, $schemaPluginName); $fieldValue = $schemaPlugin->getFieldValue($record, $fieldName, SORT_ORDER_TYPE_STRING); SearchIndex::updateTextIndex($record->getRecordId(), $field->getFieldId(), $fieldValue); } return false; }
public static function BuildSearchIndex($site, $page, $root = '../') { // get content from published fragment $content = ''; $fragment = $root . 'sites/' . $site['FriendlyId'] . '/fragments/publish/' . $page['PageUniqId'] . '.html'; if (file_exists($fragment)) { $content = file_get_contents($fragment); } // remove existing index SearchIndex::Remove($page['PageUniqId']); // build the search index for the page in the default language $isDefaultLanguage = true; Utilities::BuildSearchIndex($site, $page, $site['Language'], $isDefaultLanguage, $content, $root); // get a list of other languages $rootPrefix = $root . 'sites/' . $site['FriendlyId'] . '/'; // build index for non-default languages $languages = Utilities::GetSupportedLanguages($rootPrefix); $isDefaultLanguage = false; foreach ($languages as $language) { if ($language != $site['Language']) { Utilities::BuildSearchIndex($site, $page, $language, $isDefaultLanguage, $content, $root); } } }
public function __viewIndex() { $this->setPageType('table'); $this->setTitle(__('Symphony') . ' – ' . __('Search Indexes')); $page = @(int) $_GET['pg'] > 1 ? (int) $_GET['pg'] : 1; $page_size = (int) Symphony::Configuration()->get('pagination_maximum_rows', 'symphony'); $sort_column = 'date'; $sort_order = 'desc'; $filter_keywords = ''; $filter_view = ''; if (isset($_GET['sort'])) { $sort_column = $_GET['sort']; } if (isset($_GET['order'])) { $sort_order = $_GET['order']; } if (isset($_GET['keywords'])) { $filter_keywords = $_GET['keywords']; } if (isset($_GET['view'])) { $filter_view = $_GET['view']; } $logs = SearchIndex::getLogs($sort_column, $sort_order, $filter_view == 'export' ? NULL : $page, $filter_keywords); if ($filter_view == 'export') { $file_path = sprintf('%s/search-index.log.%d.csv', TMP, time()); $csv = fopen($file_path, 'w'); fputcsv($csv, array(__('Date'), __('Keywords'), __('Adjusted Keywords'), __('Results'), __('Depth'), __('Session ID')), ',', '"'); foreach ($logs as $log) { fputcsv($csv, array($log['date'], $log['keywords'], $log['keywords_manipulated'], $log['results'], $log['depth'], $log['session_id']), ',', '"'); } fclose($csv); header('Content-type: application/csv'); header('Content-Disposition: attachment; filename="' . end(explode('/', $file_path)) . '"'); readfile($file_path); unlink($file_path); exit; } $start = max(1, ($page - 1) * $page_size); $end = $start == 1 ? $page_size : $start + count($logs); $total = SearchIndex::countLogs($filter_keywords); $pages = ceil($total / $page_size); $filter_form = Widget::Form($this->_uri . '/logs/', 'get'); $filters = new XMLElement('div', NULL, array('class' => 'search-index-log-filters')); $label = new XMLElement('label', __('Filter searches containing the keywords %s', array(Widget::Input('keywords', $filter_keywords)->generate()))); $filters->appendChild($label); $filters->appendChild(new XMLElement('input', NULL, array('type' => 'submit', 'value' => __('Filter'), 'class' => 'create button'))); $filters->appendChild(Widget::Anchor(__('Clear'), $this->_uri . '/logs/', NULL, 'button clear')); $filter_form->appendChild($filters); $this->insertDrawer(Widget::Drawer('search_index', __('Filter Logs'), $filter_form, 'opened'), 'horizontal'); $this->appendSubheading(__('Logs'), Widget::Anchor(__('Export CSV'), $this->_uri . '/logs/?view=export&sort=' . $sort_column . '&order=' . $sort_order . '&keywords=' . $filter_keywords, NULL, 'button')); $stats = array('unique-users' => SearchIndex::getStatsCount('unique-users', $filter_keywords), 'unique-searches' => SearchIndex::getStatsCount('unique-searches', $filter_keywords), 'unique-terms' => SearchIndex::getStatsCount('unique-terms', $filter_keywords), 'average-results' => SearchIndex::getStatsCount('average-results', $filter_keywords)); $this->addStylesheetToHead(URL . '/extensions/search_index/assets/search_index.css', 'screen', 100); $this->Form->appendChild(new XMLElement('p', sprintf(__('<strong>%s</strong> unique searches from <strong>%s</strong> unique users via <strong>%s</strong> distinct search terms. Each search yielded an average of <strong>%s</strong> results.', array($stats['unique-searches'], $stats['unique-users'], $stats['unique-terms'], $stats['average-results']))), array('class' => 'intro'))); $tableHead = array(); $tableBody = array(); $tableHead = array(array(Widget::Anchor(__('Date'), Administration::instance()->getCurrentPageURL() . '?pg=1&sort=date&order=' . ($sort_column == 'date' && $sort_order == 'desc' ? 'asc' : 'desc') . '&keywords=' . $filter_keywords, '', $sort_column == 'date' ? 'active' : ''), 'col'), array(Widget::Anchor(__('Keywords'), Administration::instance()->getCurrentPageURL() . '?pg=1&sort=keywords&order=' . ($sort_column == 'keywords' && $sort_order == 'asc' ? 'desc' : 'asc') . '&keywords=' . $filter_keywords, '', $sort_column == 'keywords' ? 'active' : ''), 'col'), array(__('Adjusted Keywords'), 'col'), array(Widget::Anchor(__('Results'), Administration::instance()->getCurrentPageURL() . '?pg=1&sort=results&order=' . ($sort_column == 'results' && $sort_order == 'desc' ? 'asc' : 'desc') . '&keywords=' . $filter_keywords, '', $sort_column == 'results' ? 'active' : ''), 'col'), array(Widget::Anchor(__('Depth'), Administration::instance()->getCurrentPageURL() . '?pg=1&sort=depth&order=' . ($sort_column == 'depth' && $sort_order == 'desc' ? 'asc' : 'desc') . '&keywords=' . $filter_keywords, '', $sort_column == 'depth' ? 'active' : ''), 'col'), array(__('Session ID'), 'col')); if (!is_array($logs) or empty($logs)) { $tableBody = array(Widget::TableRow(array(Widget::TableData(__('None Found.'), 'inactive', null, count($tableHead))))); } else { foreach ($logs as $hash => $log) { $row = array(); $row[] = Widget::TableData(DateTimeObj::get(__SYM_DATETIME_FORMAT__, strtotime($log['date']))); $keywords = $log['keywords']; $keywords_class = ''; if ($keywords == '') { $keywords = __('None'); $keywords_class = 'inactive'; } $row[] = Widget::TableData(htmlentities($keywords, ENT_QUOTES), $keywords_class); $adjusted = $log['keywords_manipulated']; $adjusted_class = ''; if ($log['keywords_manipulated'] == '' || strtolower(trim($log['keywords'])) == strtolower(trim($log['keywords_manipulated']))) { $adjusted = __('None'); $adjusted_class = 'inactive'; } $row[] = Widget::TableData(htmlentities($adjusted, ENT_QUOTES), $adjusted_class); $row[] = Widget::TableData($log['results']); $row[] = Widget::TableData($log['depth']); $row[] = Widget::TableData($log['session_id']); //$row[] = Widget::TableData($log['session_id'] . Widget::Input("items[{$log['id']}]", null, 'checkbox')->generate()); $tableBody[] = Widget::TableRow($row); } } $table = Widget::Table(Widget::TableHead($tableHead), null, Widget::TableBody($tableBody)); $this->Form->appendChild($table); $div = new XMLElement('div'); $div->setAttribute('class', 'actions'); $this->Form->appendChild($div); // Pagination: if ($pages > 1) { $ul = new XMLElement('ul'); $ul->setAttribute('class', 'page'); ## First $li = new XMLElement('li'); if ($page > 1) { $li->appendChild(Widget::Anchor(__('First'), Administration::instance()->getCurrentPageURL() . '?pg=1&sort=' . $sort_column . '&order=' . $sort_order . '&keywords=' . $filter_keywords)); } else { $li->setValue(__('First')); } $ul->appendChild($li); ## Previous $li = new XMLElement('li'); if ($page > 1) { $li->appendChild(Widget::Anchor(__('← Previous'), Administration::instance()->getCurrentPageURL() . '?pg=' . ($page - 1) . '&sort=' . $sort_column . '&order=' . $sort_order . '&keywords=' . $filter_keywords)); } else { $li->setValue('← ' . __('Previous')); } $ul->appendChild($li); ## Summary $li = new XMLElement('li'); $li->setAttribute('title', __('Viewing %1$s - %2$s of %3$s entries', array($start, $end, $total))); $pgform = Widget::Form(Administration::instance()->getCurrentPageURL(), 'get', 'paginationform'); $pgmax = max($page, $pages); $pgform->appendChild(Widget::Input('pg', NULL, 'text', array('data-active' => __('Go to page …'), 'data-inactive' => __('Page %1$s of %2$s', array((string) $page, $pgmax)), 'data-max' => $pgmax))); $li->appendChild($pgform); $ul->appendChild($li); ## Next $li = new XMLElement('li'); if ($page < $pages) { $li->appendChild(Widget::Anchor(__('Next →'), Administration::instance()->getCurrentPageURL() . '?pg=' . ($page + 1) . '&sort=' . $sort_column . '&order=' . $sort_order . '&keywords=' . $filter_keywords)); } else { $li->setValue(__('Next') . ' →'); } $ul->appendChild($li); ## Last $li = new XMLElement('li'); if ($page < $pages) { $li->appendChild(Widget::Anchor(__('Last'), Administration::instance()->getCurrentPageURL() . '?pg=' . $pages . '&sort=' . $sort_column . '&order=' . $sort_order . '&keywords=' . $filter_keywords)); } else { $li->setValue(__('Last')); } $ul->appendChild($li); $this->Contents->appendChild($ul); } }
/** * Set up static members */ private function assert() { if (self::$_entry_manager == NULL) self::$_entry_manager = new EntryManager(Administration::instance()); }
/** * Exclude object from result * * @param SearchIndex $searchIndex Object to remove from the list of results * * @return SearchIndexQuery The current query, for fluid interface */ public function prune($searchIndex = null) { if ($searchIndex) { $this->addCond('pruneCond0', $this->getAliasedColName(SearchIndexPeer::ID), $searchIndex->getId(), Criteria::NOT_EQUAL); $this->addCond('pruneCond1', $this->getAliasedColName(SearchIndexPeer::LANGUAGE_ID), $searchIndex->getLanguageId(), Criteria::NOT_EQUAL); $this->combine(array('pruneCond0', 'pruneCond1'), Criteria::LOGICAL_OR); } return $this; }
public function index_laws($args) { if (!isset($this->edition)) { $edition_obj = new Edition(array('db' => $this->db)); $this->edition = $edition_obj->current(); } if (!isset($this->edition)) { throw new Exception('No edition, cannot index laws.'); } if ($this->edition->current != '1') { $this->logger->message('The edition is not current, skipping the update of the search ' . ' index', 9); return; } if (!defined('SEARCH_CONFIG')) { $this->logger->message('Solr is not in use, skipping index', 9); return; } else { /* * Index the laws. */ $this->logger->message('Updating search index', 5); $this->logger->message('Indexing laws', 6); $search_index = new SearchIndex(array('config' => json_decode(SEARCH_CONFIG, TRUE))); $law_obj = new Law(array('db' => $this->db)); $result = $law_obj->get_all_laws($this->edition->id, true); $search_index->start_update(); while ($law = $result->fetch()) { // Get the full data of the actual law. $document = new Law(array('db' => $this->db)); $document->law_id = $law['id']; $document->config->get_all = TRUE; $document->get_law(); // Bring over our edition info. $document->edition = $this->edition; try { $search_index->add_document($document); } catch (Exception $error) { $this->logger->message('Search index error "' . $error->getStatusMessage() . '"', 10); return FALSE; } } $search_index->commit(); // $this->logger->message('Indexing structures', 6); ### TODO: Index structures $this->logger->message('Laws were indexed', 5); return TRUE; } }
private function deleteSearchIndex($intId) { $strSql = sprintf("SELECT * FROM pcms_search_index WHERE elementId = '%s'", quote_smart($intId)); $objSearchIndexes = SearchIndex::select($strSql); foreach ($objSearchIndexes as $objSearchIndex) { $objSearchIndex->delete(); } }
public function __actionEdit() { $fields = $_POST['fields']; $is_new = !isset($this->_indexes[$this->_section->get('id')]); $this->_indexes[$this->_section->get('id')]['fields'] = $fields['included_elements']; $this->_indexes[$this->_section->get('id')]['weighting'] = $fields['weighting']; if (!is_array($fields['filter'])) { $fields['filter'] = array($fields['filter']); } $filters = array(); foreach ($fields['filter'] as $filter) { if (is_null($filter)) { continue; } $filters[key($filter)] = $filter[key($filter)]; } $this->_indexes[$this->_section->get('id')]['filters'] = $filters; SearchIndex::saveIndexes($this->_indexes); redirect("{$this->_uri}/indexes/"); }
public static function BuildSearchIndex($site, $page, $language, $isDefaultLanguage, $content, $root = '../') { $html = str_get_html($content, true, true, DEFAULT_TARGET_CHARSET, false, DEFAULT_BR_TEXT); $url = $page['FriendlyId']; $isSecure = 0; $image = $page['Image']; if ($page['PageTypeId'] != -1) { $pageType = PageType::GetByPageTypeId($page['PageTypeId']); $url = $pageType['FriendlyId'] . '/' . $page['FriendlyId']; if ($pageType['IsSecure'] == 1) { $isSecure = 1; } } if ($isDefaultLanguage == false) { // set language to the domain for the site $domain = $root . 'sites/' . $site['FriendlyId'] . '/locale'; // set the language Utilities::SetLanguage($language, $domain); } $name = $page['Name']; $text = ''; $h1s = ''; $h2s = ''; $h3s = ''; $description = $page['Description']; if ($isDefaultLanguage == false) { $name = _($name); // get translated version $description = _($description); } if ($html == null) { return ''; } // setup gettext blockquote, h1, h2, h3, p, td, th, li, meta tags for multi-lingual support foreach ($html->find('blockquote') as $el) { if ($isDefaultLanguage == false) { $text .= _($el->innertext) . ' '; // get translated version } else { $text .= $el->innertext . ' '; } } foreach ($html->find('h1') as $el) { if ($isDefaultLanguage == false) { $h1s .= _($el->innertext) . ' '; // get translated version } else { $h1s .= $el->innertext . ' '; } } foreach ($html->find('h2') as $el) { if ($isDefaultLanguage == false) { $h2s .= _($el->innertext) . ' '; // get translated version } else { $h2s .= $el->innertext . ' '; } } foreach ($html->find('h3') as $el) { if ($isDefaultLanguage == false) { $h3s .= _($el->innertext) . ' '; // get translated version } else { $h3s .= $el->innertext . ' '; } } foreach ($html->find('p') as $el) { if ($isDefaultLanguage == false) { $text .= _($el->innertext) . ' '; // get translated version } else { $text .= $el->innertext . ' '; } } foreach ($html->find('td') as $el) { if ($isDefaultLanguage == false) { $text .= _($el->innertext) . ' '; // get translated version } else { $text .= $el->innertext . ' '; } } foreach ($html->find('th') as $el) { if ($isDefaultLanguage == false) { $text .= _($el->innertext) . ' '; // get translated version } else { $text .= $el->innertext . ' '; } } foreach ($html->find('li') as $el) { if ($isDefaultLanguage == false) { $text .= _($el->innertext) . ' '; // get translated version } else { $text .= $el->innertext . ' '; } } foreach ($html->find('meta[name=description]') as $el) { if ($isDefaultLanguage == false) { $description = _($el->innertext); // get translated version } else { $description = $el->innertext; } } // strip any html $h1s = strip_tags($h1s); $h2s = strip_tags($h2s); $h3s = strip_tags($h3s); $description = strip_tags($description); $text = strip_tags($text); // add to search index SearchIndex::Add($page['PageUniqId'], $site['SiteUniqId'], $language, $url, $name, $image, $isSecure, $h1s, $h2s, $h3s, $description, $text); }
/** * Build SQL for Data Source filter * * @param array $data * @param string $joins * @param string $where * @param boolean $andOperation */ function buildDSRetrivalSQL($data, &$joins, &$where, $andOperation = FALSE) { $field_id = $this->get('id'); if (!is_array($data)) { $data = array($data); } foreach ($data as &$value) { $value = SearchIndex::wildcardSearchKeywords($this->cleanValue($value)); } $this->_key++; $data = implode("', '", $data); $joins .= " LEFT JOIN `tbl_search_index` AS search_index ON (e.id = search_index.entry_id) "; $where .= " AND MATCH(search_index.data) AGAINST ('{$data}' IN BOOLEAN MODE) "; return TRUE; }
public function fieldData($field, $forceType = null, $extraOptions = array()) { // Ensure that 'boost' is recorded here without being captured by solr $boost = null; if (array_key_exists('boost', $extraOptions)) { $boost = $extraOptions['boost']; unset($extraOptions['boost']); } $data = parent::fieldData($field, $forceType, $extraOptions); // Boost all fields with this name if (isset($boost)) { foreach ($data as $fieldName => $fieldInfo) { $this->boostedFields[$fieldName] = $boost; } } return $data; }
private function deleteSearchIndex($intId) { $strSql = sprintf("DELETE FROM pcms_search_index WHERE elementId = '%s'", self::quote($intId)); SearchIndex::select($strSql); }
public function renderPanel($context) { $config = $context['config']; switch ($context['type']) { case 'search_index': $logs = SearchIndex::getLogs('date', 'desc', 1); $thead = array(array(__('Date'), 'col'), array(__('Keywords'), 'col'), array(__('Results'), 'col')); $tbody = array(); if (!is_array($logs) or empty($logs)) { $tbody = array(Widget::TableRow(array(Widget::TableData(__('No data available.'), 'inactive', null, count($thead))))); } else { foreach ($logs as $log) { $tbody[] = Widget::TableRow(array(Widget::TableData(DateTimeObj::get(__SYM_DATETIME_FORMAT__, strtotime($log['date']))), Widget::TableData($log['keywords']), Widget::TableData($log['results']))); } } $table = Widget::Table(Widget::TableHead($thead), null, Widget::TableBody($tbody), null); $table->setAttribute('class', 'skinny'); $context['panel']->appendChild($table); $context['panel']->appendChild(new XMLElement('p', '<a href="' . (SYMPHONY_URL . '/extension/search_index/logs/') . '">' . __('View full search logs') . ' →</a>', array('style' => 'margin:0.7em;text-align:right;'))); break; } }
/** * Adds an object to the instance pool. * * Propel keeps cached copies of objects in an instance pool when they are retrieved * from the database. In some cases -- especially when you override doSelect*() * methods in your stub classes -- you may need to explicitly add objects * to the cache in order to ensure that the same objects are always returned by doSelect*() * and retrieveByPK*() calls. * * @param SearchIndex $obj A SearchIndex object. * @param string $key (optional) key to use for instance map (for performance boost if key was already calculated externally). */ public static function addInstanceToPool($obj, $key = null) { if (Propel::isInstancePoolingEnabled()) { if ($key === null) { $key = serialize(array((string) $obj->getId(), (string) $obj->getLanguageId())); } // if key === null SearchIndexPeer::$instances[$key] = $obj; } }
public function __viewIndex() { $this->setPageType('table'); $this->setTitle(__('Symphony') . ' – ' . __('Search Indexes')); $this->appendSubheading(__('Indexes')); $this->Form->appendChild(new XMLElement('p', __('Configure how each of your sections are indexed. Choose which field text values to index, which entries to index, and the weighting of the section in search results.'), array('class' => 'intro'))); $this->addElementToHead(new XMLElement('script', "Symphony.Context.add('search_index', " . json_encode(Symphony::Configuration()->get('search_index')) . ")", array('type' => 'text/javascript')), 99); $this->addStylesheetToHead(URL . '/extensions/search_index/assets/search_index.css', 'screen', 100); $this->addScriptToHead(URL . '/extensions/search_index/assets/search_index.js', 101); $tableHead = array(); $tableBody = array(); $tableHead[] = array(__('Section'), 'col'); $tableHead[] = array(__('Fields'), 'col'); $tableHead[] = array(__('Weighting'), 'col'); $tableHead[] = array(__('Index Size'), 'col'); if (!is_array($this->_sections) or empty($this->_sections)) { $tableBody = array(Widget::TableRow(array(Widget::TableData(__('None Found.'), 'inactive', null, count($tableHead))))); } else { $re_index = explode(',', $_GET['section']); foreach ($this->_sections as $section) { $index = NULL; if (isset($this->_indexes[$section->get('id')])) { $index = $this->_indexes[$section->get('id')]; } $col_name = Widget::TableData(Widget::Anchor($section->get('name'), "{$this->_uri}/indexes/edit/{$section->get('id')}/")); if ($index) { $col_name->appendChild(Widget::Input("items[{$section->get('id')}]", null, 'checkbox')); } if ($index && isset($index['fields']) && count($index['fields'] > 0)) { $section_fields = $section->fetchFields(); $fields = $this->_indexes[$section->get('id')]['fields']; $fields_list = ''; foreach ($section_fields as $section_field) { if (in_array($section_field->get('element_name'), array_values($fields))) { $fields_list .= $section_field->get('label') . ', '; } } $fields_list = trim($fields_list, ', '); $col_fields = Widget::TableData($fields_list); } else { $col_fields = Widget::TableData(__('None'), 'inactive'); } if ($index) { if ($index['weighting'] == '') { $index['weighting'] = 2; } $col_weighting = Widget::TableData($this->_weightings[$index['weighting']]); } else { $col_weighting = Widget::TableData(__('None'), 'inactive'); } $count_data = null; $count_class = null; if (isset($_GET['section']) && in_array($section->get('id'), $re_index) && in_array($section->get('id'), array_keys($this->_indexes))) { SearchIndex::deleteIndexBySection($section->get('id')); $count_data = '<span class="to-re-index" id="section-' . $section->get('id') . '">' . __('Waiting to re-index...') . '</span>'; } else { if (isset($this->_indexes[$section->get('id')])) { $count = Symphony::Database()->fetchCol('count', sprintf("SELECT COUNT(entry_id) as `count` FROM tbl_search_index WHERE `section_id`='%d'", $section->get('id'))); $count_data = $count[0] . ' ' . ((int) $count[0] == 1 ? __('entry') : __('entries')); } else { $count_data = __('No index'); $count_class = 'inactive'; } } $col_count = Widget::TableData($count_data, $count_class . ' count-column'); $tableBody[] = Widget::TableRow(array($col_name, $col_fields, $col_weighting, $col_count), 'section-' . $section->get('id')); } } $table = Widget::Table(Widget::TableHead($tableHead), NULL, Widget::TableBody($tableBody), 'selectable', null, array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading', 'data-interactive' => 'data-interactive')); $this->Form->appendChild($table); $actions = new XMLElement('div'); $actions->setAttribute('class', 'actions'); $options = array(array(null, false, __('With Selected...')), array('re-index', false, __('Re-index Entries')), array('delete', false, __('Delete'))); $actions->appendChild(Widget::Apply($options)); $this->Form->appendChild($actions); }