public function executeShow(sfWebRequest $request) { $this->buildParams(); $this->dateRange = ''; $this->aEvent = $this->getRoute()->getObject(); $this->categories = aCategoryTable::getCategoriesForPage($this->page); $this->forward404Unless($this->aEvent); $this->forward404Unless($this->aEvent['status'] == 'published' || $this->getUser()->isAuthenticated()); $this->preview = $this->getRequestParameter('preview'); aBlogItemTable::populatePages(array($this->aEvent)); // Thanks to Giles Smith for catching that we had no titles on our blog post permalink pages! // Too much Chrome will do that to you (: // Title is pre-escaped as valid HTML $prefix = aTools::getOptionI18n('title_prefix'); $suffix = aTools::getOptionI18n('title_suffix'); $this->getResponse()->setTitle($prefix . $this->aEvent->Page->getTitle() . $suffix, false); $this->calendar = $this->buildCalendar($request); return $this->pageTemplate; }
/** * DOCUMENT ME * @param sfWebRequest $request */ public function executeReorganize(sfWebRequest $request) { // Reorganizing the tree = escaping your page-specific security limitations. // So only full CMS admins can do it. $this->flunkUnless($this->getUser()->hasCredential('cms_admin')); $root = aPageTable::retrieveBySlug('/'); $this->forward404Unless($root); $this->treeData = $root->getTreeJSONReady(false); // setTitle takes care of escaping things $this->getResponse()->setTitle(aTools::getOptionI18n('title_prefix') . 'Reorganize' . aTools::getOptionI18n('title_suffix')); }
public static function setPageEnvironment(sfAction $action, aPage $page) { // Title is pre-escaped as valid HTML $prefix = aTools::getOptionI18n('title_prefix'); $action->getResponse()->setTitle($prefix . $page->getTitle(), false); // Necessary to allow the use of // aTools::getCurrentPage() in the layout. // In Symfony 1.1+, you can't see $action->page from // the layout. aTools::setCurrentPage($page); // Borrowed from sfSimpleCMS if (sfConfig::get('app_a_use_bundled_layout', true)) { $action->setLayout(sfContext::getInstance()->getConfiguration()->getTemplateDir('a', 'layout.php') . '/layout'); } // Loading the a helper at this point guarantees not only // helper functions but also necessary JavaScript and CSS sfContext::getInstance()->getConfiguration()->loadHelpers('a'); }
public static function searchBody($action, $slugMatch, $modelClass, $categories, sfWebRequest $request) { $now = date('YmdHis'); // create the array of pages matching the query $ajax = false; if ($request->hasParameter('term')) { $ajax = true; $q = $request->getParameter('term'); // Wildcarding is better for autocomplete $q .= '*'; } else { $q = $request->getParameter('q'); if ($request->hasParameter('x')) { // We sometimes like to use input type="image" for presentation reasons, but it generates // ugly x and y parameters with click coordinates. Get rid of those and come back. Keep // all the other stuff return $action->redirect(sfContext::getInstance()->getController()->genUrl(aUrl::addParams($request->getParameter('module') . '/' . $request->getParameter('action'), array('q' => $q, 'cat' => $request->getParameter('cat'), 'tag' => $request->getParameter('tag'), 'year' => $request->getParameter('year'), 'month' => $request->getParameter('month'), 'day' => $request->getParameter('day'))))); } } $key = strtolower(trim($q)); $key = preg_replace('/\\s+/', ' ', $key); $replacements = sfConfig::get('app_a_search_refinements', array()); if (isset($replacements[$key])) { $q = $replacements[$key]; } try { $q = "({$q}) AND slug:{$slugMatch}"; $values = aZendSearch::searchLuceneWithValues(Doctrine::getTable('aPage'), $q, aTools::getUserCulture()); } catch (Exception $e) { // Lucene search error. TODO: display it nicely if they are always safe things to display. For now: just don't crash $values = array(); } $nvalues = array(); // The truth is that Zend cannot do all of our filtering for us, especially // permissions-based. So we can do some other filtering as well, although it // would be bad not to have Zend take care of the really big cuts (if 99% are // not being prefiltered by Zend, and we have a Zend max results of 1000, then // we are reduced to working with a maximum of 10 real results). if ($request->hasParameter('cat')) { $categories = Doctrine::getTable('aCategory')->createQuery()->where('slug = ?', array($request->getParameter('cat')))->execute(array(), Doctrine::HYDRATE_ARRAY); } if (is_null($categories)) { $categoryIds = array(); } else { $categoryIds = aArray::getIds($categories); } foreach ($values as $value) { if ($ajax && count($nvalues) >= sfConfig::get('app_aBlog_autocomplete_max', 10)) { break; } // 1.5: the names under which we store columns in Zend Lucene have changed to // avoid conflict with also indexing them $info = unserialize($value->info_stored); // Do a whole bunch of filtering that can't be easily done at the Lucene level. // This is not ideal because the 1000 results we consider might not meet the // criteria and some later set of results might. For 2.0 we need to find something // that fully merges text search and other criteria without complaint // The main performance killer isn't MySQL, it's Doctrine object hydration. Just keep it light if (count($categoryIds) && !count(Doctrine::getTable('aPage')->createQuery('p')->where('p.id = ?', $info['id'])->innerJoin('p.Categories c')->select('p.id, c.id')->andWhereIn('c.id', $categoryIds)->execute(array(), Doctrine::HYDRATE_NONE))) { continue; } if ($request->hasParameter('tag') && !count(Doctrine::getTable('Tagging')->createQuery('ta')->innerJoin('ta.Tag t WITH t.name = ?', $request->getParameter('tag'))->where('ta.taggable_model = ? AND ta.taggable_id = ?', array('aPage', $info['id']))->execute(array(), Doctrine::HYDRATE_NONE))) { continue; } // Filter search results chronologically. How to do this depends on whether // we're dealing with blog or events $year = sprintf("%04d", $request->getParameter('year')); $month = sprintf("%02d", $request->getParameter('month')); $day = sprintf("%02d", $request->getParameter('day')); // This if is gross and ought to be refactored by calling a method on // the actions class which is differently implemented by the two classes if (get_class($action) === 'aEventActions') { if ($day > 0) { if (!aBlogToolkit::between("{$year}-{$month}-{$day}", $value->start_date, $value->end_date)) { continue; } } elseif ($month > 0) { if (!aBlogToolkit::between("{$year}-{$month}", substr($value->start_date, 0, 7), substr($value->end_date, 0, 7))) { continue; } } elseif ($year > 0) { if (!aBlogToolkit::between("{$year}", substr($value->start_date, 0, 4), substr($value->end_date, 0, 4))) { continue; } } } else { // We store this one real picky in a keyword so it's searchable at the lucene level if (preg_match('/^(\\d\\d\\d\\d)(\\d\\d)(\\d\\d)/', $value->published_at, $matches)) { list($dummy, $pyear, $pmonth, $pday) = $matches; if ($year > 0) { if ($pyear != $year) { continue; } } if ($month > 0) { if ($pmonth != $month) { continue; } } if ($day > 0) { if ($pday != $day) { continue; } } } } // Regardless of the above if it ain't published yet we can't see it if ($value->published_at > $now) { continue; } if (!aPageTable::checkPrivilege('view', $info)) { continue; } $nvalue = $value; $nvalue->page_id = $info['id']; $nvalue->slug = $nvalue->slug_stored; $nvalue->title = $nvalue->title_stored; $nvalue->summary = $nvalue->summary_stored; // Virtual page slug is a named Symfony route, it wants search results to go there $nvalue->url = $action->getController()->genUrl($nvalue->slug, true); $nvalue->class = $modelClass; $nvalues[] = $nvalue; } $values = $nvalues; if ($ajax) { // We need the IDs of the blog posts, not their virtual pages $pageIds = array(); foreach ($values as $value) { $pageIds[] = $value->page_id; } $action->results = array(); if (count($pageIds)) { $infos = Doctrine::getTable($modelClass)->createQuery('p')->select('p.id, p.page_id, p.status')->whereIn('p.page_id', $pageIds)->fetchArray(); // At this point, if we're an admin, we have some posts on our list that are not actually // useful to return as AJAX results because we only care about posts that are published when // we're building up a posts slot foreach ($infos as $info) { if ($info['status'] !== 'published') { continue; } $pageIdToPostId[$info['page_id']] = $info['id']; } foreach ($values as $value) { if (isset($pageIdToPostId[$value->page_id])) { // Titles are stored as entity-escaped HTML text, so decode to meet // the expectations of autocomplete $action->results[] = array('label' => html_entity_decode($value->title, ENT_COMPAT, 'UTF-8'), 'value' => $pageIdToPostId[$value->page_id]); } } } return 'Autocomplete'; } $action->pager = new aArrayPager(null, sfConfig::get('app_a_search_results_per_page', 10)); $action->pager->setResultArray($values); $action->pager->setPage($request->getParameter('page', 1)); $action->pager->init(); $action->pagerUrl = "aBlog/search?" . http_build_query(array("q" => $q)); // setTitle takes care of escaping things $action->getResponse()->setTitle(aTools::getOptionI18n('title_prefix') . 'Search for ' . $q . aTools::getOptionI18n('title_suffix')); $action->results = $action->pager->getResults(); }