/** * Executes autocomplete action. * returns formated list of best matching names and their ids */ public function executeAutocomplete() { sfLoader::loadHelpers(array('General')); $model = $this->model_class; $module = c2cTools::model2module($model); $string = $this->getRequestParameter($module . '_name'); // useful protection: if (strlen($string) < sfConfig::get('app_autocomplete_min_chars')) { return $this->renderText('<ul></ul>'); } // return all documents matching $string in given module/model // NB: autocomplete on outings only returns those for which the current user is linked to // autocomplete on articles and images only returns collaborative and proper personal ones (all for moderators) $user = $this->getUser(); $filter_personal_content = !$user->hasCredential('moderator') && ($module == 'articles' || $module == 'images'); $results = Document::searchByName($string, $model, $user->getId(), $filter_personal_content); $nb_results = count($results); if ($nb_results == 0) { return $this->ajax_feedback_autocomplete('no results'); } if ($nb_results > sfConfig::get('app_autocomplete_max_results') && $nb_results < sfConfig::get('app_list_maxline_number')) { // if there are too many results to display, but if there is at least one exact match, it is in the results returned by the db query // we display the exact matches, if any. We translate some special chars and capital letters sfLoader::loadHelpers(array('General')); $simple_string = remove_accents($string); $exact_matches = array(); foreach ($results as $result) { if (remove_accents($result[$this->model_class . 'I18n'][0]['name']) == $simple_string || $module == 'users' && remove_accents($result['private_data']['username']) == $simple_string) { $exact_matches[] = $result; } } if (count($exact_matches)) { $results = $exact_matches; } else { return $this->ajax_feedback_autocomplete('Too many results. Please go on typing...'); } } elseif ($nb_results == sfConfig::get('app_list_maxline_number')) { // we have the maximum number of results returned by the db query, so we assume there are more // before giving up and returning "too many results", we can try some extra things // if we have lat lon info, we try to limit results to those in the neighboorhood if ($this->hasRequestParameter('lat') && $this->hasRequestParameter('lon') && in_array($module, array('sites', 'huts', 'parkings', 'summits'))) { $near_results = Document::searchByName($string, $model, $user->getId(), $filter_personal_content, false, array('lon' => floatval($this->getRequestParameter('lon')), 'lat' => floatval($this->getRequestParameter('lat')))); $nb_near_results = count($near_results); if ($nb_near_results && $nb_near_results < sfConfig::get('app_autocomplete_max_results')) { $results = $near_results; } else { return $this->ajax_feedback_autocomplete('Too many results. Please go on typing...'); } } else { $exact_results = Document::searchByName($string, $model, $user->getId(), $filter_personal_content, true); $nb_exact_results = count($exact_results); if ($nb_exact_results) { $results = $exact_results; $exact_matches = true; } else { return $this->ajax_feedback_autocomplete('Too many results. Please go on typing...'); } } } // build the actual results based on the user's prefered language $items = Language::getTheBest($results, $model); // if module = summit, site, parking or hut, check for similarities and if any, append regions for disambiguation if (in_array($model, array('Summit', 'Site', 'Parking', 'Hut'))) { $items_copy = $items; for ($i = 1; $i < count($items); $i++) { $item_cmp = array_shift($items_copy); foreach ($items_copy as $item) { if (levenshtein(remove_accents($item_cmp[$this->model_class . 'I18n'][0]['name']), remove_accents($item[$this->model_class . 'I18n'][0]['name'])) <= 3) { $add_region = true; break 2; } } } } if (isset($add_region)) { // retrieve attached regions best names $q = Doctrine_Query::create()->select('m.id, g0.main_id, a.area_type, ai.name, ai.culture')->from("{$model} m")->leftJoin("m.geoassociations g0")->leftJoin('g0.AreaI18n ai')->leftJoin('ai.Area a')->addWhere('g0.main_id IN (' . implode(',', array_keys($items)) . ')')->addWhere("g0.type != 'dm'")->execute(array(), Doctrine::FETCH_ARRAY); $areas_array = Language::getTheBestForAssociatedAreas($q); // choose the best area description (like in homepage) foreach ($areas_array as $item) { $area_name = Area::getBestRegionDescription($item['geoassociations']); if (!empty($area_name)) { $items[$item['id']]['area_name'] = $area_name; } } } // create list of items $html = '<ul>'; foreach ($items as $item) { $identifier = $model == 'Document' ? $this->__(substr($item['module'], 0, -1)) . ' ' : ''; // if module = documents, add the object type inside brackets switch ($model) { case 'Outing': $postidentifier = ' (' . $item['date'] . ')'; // if outings, we append the date break; case 'Summit': case 'Hut': $postidentifier = ' - ' . $item['elevation'] . $this->__('meters'); // if summit or hut, append elevation break; case 'Book': $postidentifier = (check_not_empty($item['author']) ? ' - ' . $item['author'] : '') . (check_not_empty($item['publication_date']) ? ' - ' . $item['publication_date'] : ''); break; case 'User': $postidentifier = ' (' . $item['private_data']['username'] . ')'; // if user, append forum nickname break; default: $postidentifier = ''; } $postidentifier .= isset($item['area_name']) ? ' (' . $item['area_name'] . ')' : ''; // if region attached, we append it $html .= '<li id="' . $item['id'] . '">' . $item[$this->model_class . 'I18n'][0]['name'] . '<span class="informal">' . "<em>{$postidentifier}</em> <small>[{$identifier}" . $item['id'] . ']</small></span></li>'; } if (isset($exact_matches)) { $html .= '<div class="feedback">' . $this->__('only exact matches. Go on typing') . '</div>'; } if (isset($nb_near_results) && $nb_near_results) { $html .= '<div class="feedback">' . $this->__('only near matches. Go on typing') . '</div>'; } $html .= '</ul>'; return $this->renderText($html); }
$timedate = $item['date']; if ($timedate != $date) { echo '<span class="date">' . format_date($timedate, $item_date_format) . '</span>'; $date = $timedate; } echo get_paginated_activities($item['activities']) . ' '; $i18n = $item['OutingI18n'][0]; $id = $item['id']; $lang = $i18n['culture']; echo link_to($i18n['name'], "@document_by_id_lang_slug?module=outings&id={$id}&lang={$lang}&slug=" . make_slug($i18n['name']), array('hreflang' => $lang)); $outing_data = array(); $max_elevation = displayWithSuffix($item['max_elevation'], 'meters'); if (!empty($max_elevation)) { $outing_data[] = $max_elevation; } $area_name = Area::getBestRegionDescription($item['geoassociations'], true); if (!empty($area_name)) { $outing_data[] = $area_name; } if (count($outing_data) > 0) { echo ' <span class="meta">(' . implode(' - ', $outing_data) . ')</span>'; } if (isset($item['nb_images'])) { $images = picto_tag('picto_images_light', format_number_choice('[1]1 image|(1,+Inf]%1% images', array('%1%' => $item['nb_images']), $item['nb_images'])) . ' '; echo $images; } ?> </li> <?php } ?>