/**
  * Searches for tags.
  */
 public function actionSearchForTags()
 {
     $this->requirePostRequest();
     $this->requireAjaxRequest();
     $search = craft()->request->getPost('search');
     $tagSetId = craft()->request->getPost('tagSetId');
     $excludeIds = craft()->request->getPost('excludeIds', array());
     $notIds = array();
     foreach ($excludeIds as $id) {
         $notIds[] = 'not ' . $id;
     }
     $criteria = craft()->elements->getCriteria(ElementType::Tag);
     $criteria->setId = $tagSetId;
     $criteria->search = 'name:' . $search . '*';
     $criteria->id = implode(', ', $notIds);
     $tags = $criteria->find();
     $return = array();
     $exactMatches = array();
     $tagNameLengths = array();
     $exactMatch = false;
     $normalizedSearch = StringHelper::normalizeKeywords($search);
     foreach ($tags as $tag) {
         $return[] = array('id' => $tag->id, 'name' => $tag->name);
         $tagNameLengths[] = strlen($tag->name);
         $normalizedName = StringHelper::normalizeKeywords($tag->name);
         if ($normalizedName == $normalizedSearch) {
             $exactMatches[] = 1;
             $exactMatch = true;
         } else {
             $exactMatches[] = 0;
         }
     }
     array_multisort($exactMatches, SORT_DESC, $tagNameLengths, $return);
     $this->returnJson(array('tags' => $return, 'exactMatch' => $exactMatch));
 }
 /**
  * Fork of tags/searchForTags adjusted to cope with any element
  */
 public function actionSearchForElements()
 {
     $this->requirePostRequest();
     $this->requireAjaxRequest();
     $search = craft()->request->getPost('search');
     $excludeIds = craft()->request->getPost('excludeIds', array());
     // Get the post data
     $elementType = craft()->request->getPost('elementType');
     $sources = craft()->request->getPost('sources');
     // Deal with Entries
     if ($elementType == ElementType::Entry) {
         // Start the criteria
         $criteria = craft()->elements->getCriteria(ElementType::Entry);
         // Fangle the sections out of the sources
         $sections = array();
         if (is_array($sources)) {
             foreach ($sources as $source) {
                 switch ($source) {
                     case 'singles':
                         $sections = array_merge($sections, craft()->sections->getSectionsByType(SectionType::Single));
                         break;
                     default:
                         if (preg_match('/^section:(\\d+)$/', $source, $matches)) {
                             $section = craft()->sections->getSectionById($matches[1]);
                             if ($section) {
                                 $sections = array_merge($sections, array($section));
                             }
                         }
                 }
             }
         }
         $criteria->section = $sections;
     } else {
         if ($elementType == ElementType::Category) {
             // Start the criteria
             $criteria = craft()->elements->getCriteria(ElementType::Category);
         }
     }
     // Add and exclude ids
     $notIds = array('and');
     foreach ($excludeIds as $id) {
         $notIds[] = 'not ' . $id;
     }
     // Set the rest of the criteria
     $criteria->title = '*' . DbHelper::escapeParam($search) . '*';
     $criteria->id = $notIds;
     $criteria->status = null;
     $criteria->limit = 20;
     $elements = $criteria->find();
     $return = array();
     $exactMatches = array();
     $exactMatch = false;
     $normalizedSearch = StringHelper::normalizeKeywords($search);
     foreach ($elements as $element) {
         if ($elementType == ElementType::Entry) {
             if (!is_array($sources)) {
                 $sourceKey = "*";
             } else {
                 if ($element->section->type == SectionType::Single) {
                     $sourceKey = "singles";
                 } else {
                     $sourceKey = "section:" . $element->section->id;
                 }
             }
             $return[$sourceKey][] = array('id' => $element->id, 'title' => $element->getContent()->title, 'status' => $element->status, 'sourceName' => $element->section->name);
         } else {
             if ($elementType == ElementType::Category) {
                 $sourceKey = "group:" . $element->group->id;
                 $return[$sourceKey][] = array('id' => $element->id, 'title' => $element->getContent()->title, 'status' => $element->status, 'sourceName' => $element->group->name);
             }
         }
         $normalizedTitle = StringHelper::normalizeKeywords($element->getContent()->title);
         if ($normalizedTitle == $normalizedSearch) {
             $exactMatches[] = 1;
             $exactMatch = true;
         } else {
             $exactMatches[] = 0;
         }
     }
     // NOTE: We’ve lost the sorting by exact match
     // array_multisort($exactMatches, SORT_DESC, $return);
     $this->returnJson(array('elements' => $return, 'exactMatch' => $exactMatch));
 }
 /**
  * Searches for tags.
  *
  * @return null
  */
 public function actionSearchForTags()
 {
     $this->requirePostRequest();
     $this->requireAjaxRequest();
     $search = craft()->request->getPost('search');
     $tagGroupId = craft()->request->getPost('tagGroupId');
     $excludeIds = craft()->request->getPost('excludeIds', array());
     $notIds = array('and');
     foreach ($excludeIds as $id) {
         $notIds[] = 'not ' . $id;
     }
     $criteria = craft()->elements->getCriteria(ElementType::Tag);
     $criteria->groupId = $tagGroupId;
     $criteria->title = DbHelper::escapeParam($search) . '*';
     $criteria->id = $notIds;
     $tags = $criteria->find();
     $return = array();
     $exactMatches = array();
     $tagTitleLengths = array();
     $exactMatch = false;
     $normalizedSearch = StringHelper::normalizeKeywords($search);
     foreach ($tags as $tag) {
         $return[] = array('id' => $tag->id, 'title' => $tag->getContent()->title);
         $tagTitleLengths[] = mb_strlen($tag->getContent()->title);
         $normalizedTitle = StringHelper::normalizeKeywords($tag->getContent()->title);
         if ($normalizedTitle == $normalizedSearch) {
             $exactMatches[] = 1;
             $exactMatch = true;
         } else {
             $exactMatches[] = 0;
         }
     }
     array_multisort($exactMatches, SORT_DESC, $tagTitleLengths, $return);
     $this->returnJson(array('tags' => $return, 'exactMatch' => $exactMatch));
 }
 /**
  * Normalize term from tokens, keep a record for cache.
  *
  * @param string $term
  *
  * @return string
  */
 private function _normalizeTerm($term)
 {
     static $terms = array();
     if (!array_key_exists($term, $terms)) {
         $terms[$term] = StringHelper::normalizeKeywords($term);
     }
     return $terms[$term];
 }
 /**
  * Get database records for current collection.
  */
 private function _getRecordsForCollection()
 {
     // Get element criteria
     $criteria = craft()->elements->getCriteria($this->_collection->elementType);
     $criteria->locale = $this->_getSearchParam('locale');
     $criteria->limit = null;
     // Get element type
     $elementType = $criteria->getElementType();
     // Set element source
     if ($this->_getCollectionSetting('source')) {
         $sources = $this->_getCollectionSetting('source');
         if (!is_array($sources)) {
             $sources = array($sources);
         }
         // Gather all criteria
         $sourcesCriteria = array();
         foreach ($sources as $source) {
             $elementSource = $elementType->getSource($source);
             // Does the source specify any criteria attributes?
             if ($elementSource && !empty($elementSource['criteria'])) {
                 foreach ($elementSource['criteria'] as $key => $value) {
                     // Add to the gathered criteria
                     if (!isset($sourcesCriteria[$key])) {
                         $sourcesCriteria[$key] = is_array($value) ? $value : array($value);
                     } elseif (is_array($value)) {
                         $sourcesCriteria[$key] = array_merge($sourcesCriteria[$key], $value);
                     } else {
                         $sourcesCriteria[$key][] = $value;
                     }
                 }
             }
         }
         // Criteria fixes
         switch ($this->_collection->elementType) {
             case ElementType::Entry:
                 if (isset($sourcesCriteria['editable'])) {
                     unset($sourcesCriteria['editable']);
                 }
                 break;
         }
         // Set all criteria now!
         $criteria->setAttributes($sourcesCriteria);
     }
     // Set element status
     if ($this->_getCollectionSetting('status')) {
         $criteria->status = $this->_getCollectionSetting('status');
     }
     // Get the element's query
     $query = craft()->elements->buildElementsQuery($criteria);
     if (!$query) {
         return false;
     }
     // Set search criteria?
     $this->_keywords = null;
     // Always reset first, regardless of param
     $this->_scoreResults = null;
     // Always reset first, regardless of param
     if ($this->_getSearchParam('keywords') && trim($this->_getSearchParam('keywords')) != '') {
         $this->_keywords = StringHelper::normalizeKeywords($this->_getSearchParam('keywords'));
         if (!$this->_setSearchCriteria($criteria, $query)) {
             return false;
             // No search results!
         }
     }
     // Get user fullName if correct collection is given
     if ($this->_collection->elementType == ElementType::User) {
         $query->addSelect('IF (users.lastName != "", CONCAT_WS(" ", users.firstName, users.lastName), users.firstName) AS fullName');
     }
     // Find records!
     $elements = $query->queryAll();
     // Handle found elements
     if ($elements) {
         // Handle elements!
         $this->_handleElements($elements);
     }
 }