Alpha Framework alpha--controller
[ class tree: alpha--controller ] [ index: alpha--controller ] [ all elements ]

Source for file Search.php

Documentation is available at Search.php

  1. <?php
  2.  
  3. // include the config file
  4. if(!isset($config)) {
  5.     require_once '../util/AlphaConfig.inc';
  6.     $config AlphaConfig::getInstance();
  7. }
  8.  
  9. require_once $config->get('sysRoot').'alpha/controller/AlphaController.inc';
  10. require_once $config->get('sysRoot').'alpha/controller/AlphaControllerInterface.inc';
  11. require_once $config->get('sysRoot').'alpha/model/TagObject.inc';
  12. require_once $config->get('sysRoot').'alpha/view/AlphaView.inc';
  13. require_once $config->get('sysRoot').'alpha/util/LogFile.inc';
  14.  
  15. /**
  16.  * 
  17.  * Generic tag-based search engine controller
  18.  * 
  19.  * @package alpha::controller
  20.  * @since 1.0
  21.  * @author John Collins <dev@alphaframework.org>
  22.  * @version $Id: Search.php 1344 2011-03-17 16:10:20Z johnc $
  23.  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  24.  * @copyright Copyright (c) 2011, John Collins (founder of Alpha Framework).
  25.  *  All rights reserved.
  26.  * 
  27.  *  <pre>
  28.  *  Redistribution and use in source and binary forms, with or
  29.  *  without modification, are permitted provided that the
  30.  *  following conditions are met:
  31.  * 
  32.  *  * Redistributions of source code must retain the above
  33.  *    copyright notice, this list of conditions and the
  34.  *    following disclaimer.
  35.  *  * Redistributions in binary form must reproduce the above
  36.  *    copyright notice, this list of conditions and the
  37.  *    following disclaimer in the documentation and/or other
  38.  *    materials provided with the distribution.
  39.  *  * Neither the name of the Alpha Framework nor the names
  40.  *    of its contributors may be used to endorse or promote
  41.  *    products derived from this software without specific
  42.  *    prior written permission.
  43.  *   
  44.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  45.  *  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  46.  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  47.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  48.  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  49.  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  50.  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  51.  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  52.  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  53.  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  54.  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  55.  *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  56.  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  57.  *  </pre>
  58.  *  
  59.  */
  60. class Search extends AlphaController implements AlphaControllerInterface {
  61.     /**
  62.      * Trace logger
  63.      * 
  64.      * @var Logger 
  65.      * @since 1.0
  66.      */
  67.     private static $logger null;
  68.     
  69.     /**
  70.      * The start number for list pageination
  71.      * 
  72.      * @var integer 
  73.      * @since 1.0
  74.      */
  75.     protected $startPoint;
  76.     
  77.     /**
  78.      * The result count from the search
  79.      * 
  80.      * @var integer 
  81.      * @since 1.0
  82.      */
  83.     private $resultCount 0;
  84.     
  85.     /**
  86.      * The search query supplied
  87.      * 
  88.      * @var string 
  89.      * @since 1.0
  90.      */
  91.     private $query;
  92.     
  93.     /**
  94.      * constructor to set up the object
  95.      * 
  96.      * @param string $visibility The name of the rights group that can access this controller.
  97.      * @since 1.0
  98.      */
  99.     public function __construct($visibility='Public'{
  100.         self::$logger new Logger('Search');
  101.         self::$logger->debug('>>__construct(visibility=['.$visibility.'])');
  102.         
  103.         global $config;
  104.         
  105.         // ensure that the super class constructor is called, indicating the rights group
  106.         parent::__construct($visibility);
  107.         
  108.         self::$logger->debug('<<__construct');
  109.     }
  110.     
  111.     /**
  112.      * Handle GET requests
  113.      * 
  114.      * @param array $params 
  115.      * @since 1.0
  116.      * @throws IllegalArguementException
  117.      */
  118.     public function doGET($params{
  119.         self::$logger->debug('>>doGET($params=['.var_export($paramstrue).'])');
  120.         
  121.         if (isset($params['start']$this->startPoint = $params['start']$this->startPoint = 0);
  122.         
  123.         global $config;
  124.         
  125.         if(isset($params['q'])) {
  126.             
  127.             $this->query $params['q'];
  128.             
  129.             // replace any %20 on the URL with spaces
  130.             $params['q'str_replace('%20'' '$params['q']);
  131.             
  132.             $this->setTitle('Search results - '.$params['q']);            
  133.             echo AlphaView::displayPageHead($this);
  134.             
  135.             // log the user's search query in a log file
  136.             $log new LogFile($config->get('sysRoot').'logs/search.log');        
  137.             $log->writeLine(array($params['q']date('Y-m-d H:i:s')$_SERVER['HTTP_USER_AGENT']$_SERVER['REMOTE_ADDR']));
  138.             
  139.             echo '<h2>Display results for &quot;'.$params['q'].'&quot;</h2>';
  140.             
  141.             // if a BO name is provided, only search tags on that class, otherwise search all BOs
  142.             if(isset($params['bo']))
  143.                 $BOs array($params['bo']);
  144.             else            
  145.                 $BOs AlphaDAO::getBOClassNames();
  146.             
  147.             try {
  148.                 foreach($BOs as $BO{
  149.                     AlphaDAO::loadClassDef($BO);
  150.                     $temp new $BO;
  151.                     
  152.                     if($temp->isTagged()) {
  153.                         // explode the user's query into a set of tokenized transient TagObjects
  154.                         $queryTags TagObject::tokenize($params['q']''''false);            
  155.                         $matchingTags array();
  156.                         
  157.                         // load TagObjects from the DB where content equals the content of one of our transient TagObjects
  158.                         foreach($queryTags as $queryTag{
  159.                             $tags $queryTag->loadAllByAttribute('content'$queryTag->get('content'));
  160.                             $matchingTags array_merge($matchingTags$tags);
  161.                         }
  162.                         
  163.                         self::$logger->debug('There are ['.count($matchingTags).'] TagObjects matching the query ['.$params['q'].']');
  164.                         
  165.                         /*
  166.                          * Build an array of BOs for the matching tags from the DB:
  167.                          * array key = BO ID
  168.                          * array value = weight (the amount of tags matching the BO)
  169.                          */
  170.                         $BOIDs array();
  171.                         
  172.                         foreach($matchingTags as $tag{                            
  173.                             if($tag->get('taggedClass'== $BO{
  174.                                 if(isset($BOIDs[$tag->get('taggedOID')])) {
  175.                                     // increment the weight if the same BO is tagged more than once
  176.                                     $weight intval($BOIDs[$tag->get('taggedOID')]1;
  177.                                     $BOIDs[$tag->get('taggedOID')$weight;                                    
  178.                                 }else{
  179.                                     $BOIDs[$tag->get('taggedOID')1;                                    
  180.                                 }
  181.                                 self::$logger->debug('Found BO ['.$tag->get('taggedOID').'] has weight ['.$BOIDs[$tag->get('taggedOID')].']');                                
  182.                             }
  183.                         }
  184.                         
  185.                         $this->resultCount += count($BOIDs);
  186.                         
  187.                         // sort the BO IDs based on tag frequency weight                        
  188.                         arsort($BOIDs);                        
  189.                         
  190.                         // render the list view for each BO
  191.                         $this->renderResultList($BOIDs$BO$params['q']);                        
  192.                         
  193.                         AlphaDAO::disconnect();
  194.                     }
  195.                 }
  196.             }catch(Exception $e{
  197.                 self::$logger->error($e->getMessage());
  198.                 throw new IllegalArguementException('Error occured while searching for: ['.$params['q'].']');                
  199.             }
  200.         }else{
  201.             $this->setTitle('Search results');            
  202.             echo AlphaView::displayPageHead($this);
  203.             self::$logger->warn('No search query provided!');
  204.         }        
  205.         
  206.         echo AlphaView::displayPageFoot($this);
  207.         
  208.         self::$logger->debug('<<doGET');
  209.     }
  210.     
  211.     /**
  212.      * Renders the search result list
  213.      * 
  214.      * @param array $BOIDs 
  215.      * @param string $BO 
  216.      * @param string $query 
  217.      * @since 1.0
  218.      */
  219.     private function renderResultList($BOIDs$BO$query{
  220.         global $config;
  221.         
  222.         // used to track when our pagination range ends
  223.         $end ($this->startPoint+$config->get('sysListPageAmount'));
  224.         // used to track how many results have been displayed or skipped from the pagination range
  225.         $displayedCount 0;
  226.             
  227.         foreach(array_keys($BOIDsas $oid{
  228.             try {
  229.                 // if we have reached the end of the pagination range then break out
  230.                 if($displayedCount == $end)
  231.                     break;
  232.                             
  233.                 // if our display count is >= the start but < the end...
  234.                 if($displayedCount >= $this->startPoint{
  235.                     $temp new $BO;
  236.                     $temp->load($oid);
  237.                     
  238.                     if($temp instanceof ArticleObject && $temp->get('published'== false){
  239.                         $this->resultCount--;
  240.                     }else{            
  241.                         $view AlphaView::getInstance($temp);
  242.                         echo $view->listView();
  243.                                         
  244.                         $tags $temp->getPropObject('tags')->getRelatedObjects();
  245.                     
  246.                         if(count($tags0{
  247.                             echo '<p>Tags: ';
  248.                                             
  249.                             $queryTerms explode(' 'strtolower($query));
  250.                                             
  251.                             foreach($tags as $tag{
  252.                                 echo (in_array($tag->get('content')$queryTerms'<strong>'.$tag->get('content').' </strong>' $tag->get('content').' ');
  253.                             }
  254.                                         
  255.                             echo '</p>';
  256.                         }
  257.                     }
  258.                 }
  259.                             
  260.                 $displayedCount++;
  261.             }catch(BONotFoundException $e{
  262.                 self::$logger->warn('Orpaned TagObject detected pointing to a non-existant BO of OID ['.$oid.'] and type ['.$BO.'].');
  263.             }
  264.         }
  265.     }
  266.     
  267.     /**
  268.      * Handle POST requests
  269.      * 
  270.      * @param array $params 
  271.      * @since 1.0
  272.      */
  273.     public function doPOST($params{
  274.         self::$logger->debug('>>doPOST($params=['.var_export($paramstrue).'])');
  275.         
  276.         self::$logger->debug('<<doPOST');
  277.     }
  278.     
  279.     /**
  280.      * Displays a search form on the top of the page
  281.      * 
  282.      * @return string 
  283.      * @since 1.0
  284.      */
  285.     public function after_displayPageHead_callback({
  286.         global $config;
  287.         
  288.         $html '<div align="center"><form method="GET" id="search_form" onsubmit="document.location = \''.$config->get('sysURL').'search/q/\'+document.getElementById(\'q\').value; return false;">';
  289.         $html .= 'Search for: <input type="text" size="80" name="q" id="q"/>&nbsp;';        
  290.         $button new Button('document.location = \''.$config->get('sysURL').'search/q/\'+document.getElementById(\'q\').value''Search''searchButton');
  291.         $html .= $button->render();
  292.         $html .= '</form></div>';
  293.         
  294.         return $html;
  295.     }
  296.     
  297.     /**
  298.      * Method to display the page footer with pageination links
  299.      * 
  300.      * @return string 
  301.      * @since 1.0
  302.      */
  303.     public function before_displayPageFoot_callback({
  304.         $html $this->renderPageLinks();
  305.         
  306.         $html .= '<br>';
  307.         
  308.         return $html;
  309.     }
  310.     
  311.     /**
  312.      * Method for rendering the pagination links
  313.      * 
  314.      * @return string 
  315.      * @since 1.0
  316.      */
  317.     protected function renderPageLinks({
  318.         global $config;
  319.         
  320.         $html '';
  321.         
  322.         $end ($this->startPoint+$config->get('sysListPageAmount'));
  323.         
  324.         if($end $this->resultCount)
  325.             $end $this->resultCount;
  326.         
  327.         if($this->resultCount 0)
  328.             $html .= '<p align="center">Displaying '.($this->startPoint+1).' to '.$end.' of <strong>'.$this->resultCount.'</strong>.&nbsp;&nbsp;';
  329.         else
  330.             $html .= AlphaView::displayUpdateMessage('There were no search results for your query.');    
  331.                 
  332.         if ($this->startPoint > 0{
  333.             // handle secure URLs
  334.             if(isset($_GET['tk']))
  335.                 $html .= '<a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.($this->startPoint-$config->get('sysListPageAmount'))).'">&lt;&lt;-Previous</a>&nbsp;&nbsp;';
  336.             else
  337.                 $html .= '<a href="'.$config->get('sysURL').'search/q/'.$this->query.'/start/'.($this->startPoint-$config->get('sysListPageAmount')).'">&lt;&lt;-Previous</a>&nbsp;&nbsp;';
  338.         }elseif($this->resultCount $config->get('sysListPageAmount')){
  339.             $html .= '&lt;&lt;-Previous&nbsp;&nbsp;';
  340.         }
  341.         $page 1;
  342.         for ($i 0$i $this->resultCount$i+=$config->get('sysListPageAmount')) {
  343.             if($i != $this->startPoint{
  344.                 // handle secure URLs
  345.                 if(isset($_GET['tk']))
  346.                     $html .= '&nbsp;<a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.$i).'">'.$page.'</a>&nbsp;';
  347.                 else
  348.                     $html .= '&nbsp;<a href="'.$config->get('sysURL').'search/q/'.$this->query.'/start/'.$i.'">'.$page.'</a>&nbsp;';
  349.             }elseif($this->resultCount $config->get('sysListPageAmount')){
  350.                 $html .= '&nbsp;'.$page.'&nbsp;';
  351.             }
  352.             $page++;
  353.         }
  354.         if ($this->resultCount $end{
  355.             // handle secure URLs
  356.             if(isset($_GET['tk']))
  357.                 $html .= '&nbsp;&nbsp;<a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.($this->startPoint+$config->get('sysListPageAmount'))).'">Next-&gt;&gt;</a>';
  358.             else
  359.                 $html .= '&nbsp;&nbsp;<a href="'.$config->get('sysURL').'search/q/'.$this->query.'/start/'.($this->startPoint+$config->get('sysListPageAmount')).'">Next-&gt;&gt;</a>';
  360.         }elseif($this->resultCount $config->get('sysListPageAmount')){
  361.             $html .= '&nbsp;&nbsp;Next-&gt;&gt;';
  362.         }
  363.         $html .= '</p>';
  364.         
  365.         return $html;
  366.     }
  367. }
  368.  
  369. // now build the new controller
  370. if(basename($_SERVER['PHP_SELF']== 'Search.php'{
  371.     $controller new Search();
  372.     
  373.     if(!empty($_POST)) {            
  374.         $controller->doPOST($_REQUEST);
  375.     }else{
  376.         $controller->doGET($_GET);
  377.     }
  378. }
  379.  
  380. ?>

Documentation generated on Thu, 17 Mar 2011 16:44:48 +0000 by phpDocumentor 1.4.3