Actions

Source Code of This Project

/doc/UML/SearchSystem.png

/apps/frontend/modules/search/actions/actions.class.php

<?php
/*
 * This file is part of the pwp package.
 * (c) 2009-2010 Victor Rad' <victor.v.rad[at]gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
*/

/**
 * Search actions
 *
 * @package    pwp
 * @subpackage search
 * @author     Victor Rad'
 */
class searchActions extends sfActions
{
    /**
     * Forming of friendly URL from the POST query of search string
     */
    public function preExecute()
    {
        // prepare data
        $request = sfContext::getInstance()->getRequest();
        $query = $request->getParameter('query');

        // forming friendly URL and redirect
        if ($request->isMethod('post') and strlen($query)){
            $this->redirect('@search_query?query='.$query);
        }
        elseif ($request->isMethod('post') and !strlen($query)){
            $this->redirect('@homepage');
        }
    }

    /**
     * Executes index action
     *
     * @param sfRequest $request A request object
     */
    public function executeIndex(sfWebRequest $request)
    {
        // do search
        $query = $request->getParameter('query');
        $search = new Search_Composite(new Search_Resume(), new Search_Portfolio(), new Search_News());
        $foundIds = $search->find($query);

        // pager
        $this->pager = new SearchPager('Search_Composite', sfConfig::get('app_search_per_page'));
        $this->pager->setFoundIds($foundIds);
        $this->pager->setPage($request->getParameter('page', 1));
        $this->pager->init();

        // pager slice
        $foundIdsSlice = $this->pager->getResults();
        $search->setFoundIds($foundIdsSlice);

        // get found data
        $this->foundRendered = $search->render();
        $this->foundData = $search->getFoundData();

        // count items for current page
        $this->countFoundSlice = 0;
        foreach ($foundIdsSlice as $ids){
            $this->countFoundSlice += count($ids);
        }

        // HTML meta tags
        $this->getResponse()->setTitle('Search');
        $this->getResponse()->addMeta('description', 'Results for "'. $query .'"');
    }

    /**
     * First column on page
     */
    public function postExecute()
    {
        $this->getResponse()->setSlot('colOne', $this->getPartial('colOne'));
    }
}
                    

/lib/model/search/Composite.php

<?php
/*
 * This file is part of the pwp package.
 * (c) 2009-2010 Victor Rad' <victor.v.rad[at]gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
*/

/**
 * Search collection
 * Represent of Composite pattern
 *
 * @package    pwp
 * @subpackage Search
 * @author     Victor Rad'
 */
class Search_Composite extends Search
{
    protected $instances = array();

    /**
     * Register new instances of search collection
     *
     * @param array of search $instances
     */
    public function __construct()
    {
        $searchInstances = func_get_args();
        $this->register($searchInstances);
    }

    /**
     * Setter found ids for search collection
     */
    public function setFoundIds($foundIds)
    {
        foreach ($foundIds as $key => $ids){
            $this->instances[$key]->setFoundIds($ids);
        }
    }

    /**
     * Getter found ids for search collection
     */
    public function getFoundIds()
    {
        foreach ($this->instances as $instance){
            $foundIds[] = $instance->getFoundIds();
        }

        return $foundIds;
    }

    /**
     * Getter found data for search collection
     */
    public function getFoundData()
    {
        foreach ($this->instances as $instance){
            $foundData[] = $instance->getFoundData();
        }

        return $foundData;
    }

    /**
     * Register new instances of search collection
     *
     * @param array of search $instances
     */
    public function register($instances)
    {
        foreach ($instances as $instance) {
            if ($instance instanceof Search){
                array_push($this->instances, $instance);
            }
            else{
                throw new Exception(sprintf('Instance %s must implements of Search class', $instance));
            }
        }
    }

    /**
     * Find words in search collection
     *
     * @param string $query
     */
    public function find($query)
    {
        $foundIds = array();
        foreach ($this->instances as $instance){
            $foundIds[] = $instance->find($query);
        }

        return $foundIds;
    }

    /**
     * Render templates in search collection
     *
     * @return string
     */
    public function render()
    {
        $rendered = '';
        foreach ($this->instances as $instance){
            $rendered .= $instance->render();
        }

        return $rendered;
    }

    /**
     * Delete indexes and load
     * all data from scratch in search collection
     *
     * @return <type>
     */
    public function rebuildIndex()
    {
        foreach ($this->instances as $instance){
            $instance->rebuildIndex();
        }
    }

}                    

/lib/model/search/News.php

<?php
/*
 * This file is part of the pwp package.
 * (c) 2009-2010 Victor Rad' <victor.v.rad[at]gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
*/

/**
 * Class of news for search system
 *
 * @package    pwp
 * @subpackage Search
 * @author     Victor Rad'
 */
class Search_News extends Search
{
    // added to $indexPath
    protected $indexName = 'news';

    /**
     * Update or insert document into index
     *
     * @param mixed $obj with data
     */
    public function update($obj)
    {
        // remove existing entries
        foreach ($this->index->find('pk:'.$obj->getId()) as $hit){
            $this->index->delete($hit->id);
        }

        $doc = new Zend_Search_Lucene_Document();
        // index fields
        $doc->addField(Zend_Search_Lucene_Field::Keyword('pk', $obj->getId()));
        $doc->addField(Zend_Search_Lucene_Field::UnStored('title', $obj->getTitle(), 'utf-8'));
        $doc->addField(Zend_Search_Lucene_Field::UnStored('description', $obj->getDescription(), 'utf-8'));

        // add item to the index
        $this->index->addDocument($doc);
        $this->index->commit();
    }

    /**
     * See Search::render()
     */
    public function render()
    {
        // prepare data
        $newsRendered = '';
        $newsList = null;
        sfContext::getInstance()->getConfiguration()->loadHelpers('Partial');
        sfContext::getInstance()->getConfiguration()->loadHelpers('Text');
        $highlighter = new My_Zend_Search_Lucene_Search_Highlighter_Default();
        $highlighter->setHighlightColors(sfConfig::get('app_search_highlight_color'));

        // get data
        $newsList = $this->loadData();
        if ($newsList) {
            // highlight found strings and render the partial
            foreach ($newsList as $newsOne) {
                $newsOne->setTitle('News: '.$newsOne->getTitle());
                $newsOne->setDescription(truncate_text($newsOne->getDescription(), 400, '...', true));
                $newsOne->setDescription($this->query->htmlFragmentHighlightMatches( $newsOne->getDescription(), '', $highlighter));
                $newsRendered .= get_partial('news/item', array('news' => $newsOne));
            }
        }

        return $newsRendered;
    }

    /**
     * See Search::find()
     */
    public function find($query)
    {
        return $this->_find($query);
    }

    /**
     * Get data by found ids
     *
     * @return Doctrine_Collection
     */
    public function loadData()
    {
        $newsList = null;
        $foundIds = $this->getFoundIds();

        if ($foundIds) {
            $newsList = DFactory::get('News')
                    ->getBuilder()
                    ->joinProvides()
                    ->getQuery()
                    ->whereIn('n.id', $foundIds)
                    ->execute();
            $this->setFoundData($newsList);
        }

        return $newsList;
    }

    /**
     * See Search::rebuildIndex()
     */
    public function rebuildIndex()
    {
        // delete index files
        sfContext::getInstance()->getConfiguration()->loadHelpers('MyUtil');
        my_unlink($this->indexPath, true);
        // prepare data
        $index = $this->getIndex('create');
        $doc = new Zend_Search_Lucene_Document();
        // get all news from db
        $news = DFactory::get('News')->getTable()->findAll();

        foreach ($news as $newsOne) {
            // index fields
            $doc->addField(Zend_Search_Lucene_Field::Keyword('pk', $newsOne->getId()));
            $doc->addField(Zend_Search_Lucene_Field::UnStored('title', $newsOne->getTitle(), 'utf-8'));
            $doc->addField(Zend_Search_Lucene_Field::UnStored('description', $newsOne->getDescription(), 'utf-8'));
            // add to the index
            $index->addDocument($doc);
            $index->commit();
        }
    }

}