Source for file Search.php
Documentation is available at Search.php
// include the config file
require_once '../util/AlphaConfig.inc';
require_once $config->get('sysRoot'). 'alpha/controller/AlphaController.inc';
require_once $config->get('sysRoot'). 'alpha/controller/AlphaControllerInterface.inc';
require_once $config->get('sysRoot'). 'alpha/model/TagObject.inc';
require_once $config->get('sysRoot'). 'alpha/view/AlphaView.inc';
require_once $config->get('sysRoot'). 'alpha/util/LogFile.inc';
* Generic tag-based search engine controller
* @package alpha::controller
* @author John Collins <dev@alphaframework.org>
* @version $Id: Search.php 1344 2011-03-17 16:10:20Z johnc $
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License
* @copyright Copyright (c) 2011, John Collins (founder of Alpha Framework).
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
* * Neither the name of the Alpha Framework nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
private static $logger = null;
* The start number for list pageination
* The result count from the search
private $resultCount = 0;
* The search query supplied
* constructor to set up the object
* @param string $visibility The name of the rights group that can access this controller.
self::$logger = new Logger('Search');
self::$logger->debug('>>__construct(visibility=['. $visibility. '])');
// ensure that the super class constructor is called, indicating the rights group
parent::__construct($visibility);
self::$logger->debug('<<__construct');
* @throws IllegalArguementException
public function doGET($params) {
self::$logger->debug('>>doGET($params=['. var_export($params, true). '])');
if(isset ($params['q'])) {
$this->query = $params['q'];
// replace any %20 on the URL with spaces
$this->setTitle('Search results - '. $params['q']);
// log the user's search query in a log file
$log = new LogFile($config->get('sysRoot'). 'logs/search.log');
$log->writeLine(array($params['q'], date('Y-m-d H:i:s'), $_SERVER['HTTP_USER_AGENT'], $_SERVER['REMOTE_ADDR']));
echo '<h2>Display results for "'. $params['q']. '"</h2>';
// if a BO name is provided, only search tags on that class, otherwise search all BOs
$BOs = array($params['bo']);
// explode the user's query into a set of tokenized transient TagObjects
// load TagObjects from the DB where content equals the content of one of our transient TagObjects
foreach($queryTags as $queryTag) {
$tags = $queryTag->loadAllByAttribute('content', $queryTag->get('content'));
self::$logger->debug('There are ['. count($matchingTags). '] TagObjects matching the query ['. $params['q']. ']');
* Build an array of BOs for the matching tags from the DB:
* array value = weight (the amount of tags matching the BO)
foreach($matchingTags as $tag) {
if($tag->get('taggedClass') == $BO) {
if(isset ($BOIDs[$tag->get('taggedOID')])) {
// increment the weight if the same BO is tagged more than once
$weight = intval($BOIDs[$tag->get('taggedOID')]) + 1;
$BOIDs[$tag->get('taggedOID')] = $weight;
$BOIDs[$tag->get('taggedOID')] = 1;
self::$logger->debug('Found BO ['. $tag->get('taggedOID'). '] has weight ['. $BOIDs[$tag->get('taggedOID')]. ']');
$this->resultCount += count($BOIDs);
// sort the BO IDs based on tag frequency weight
// render the list view for each BO
$this->renderResultList($BOIDs, $BO, $params['q']);
self::$logger->error($e->getMessage());
throw new IllegalArguementException('Error occured while searching for: ['. $params['q']. ']');
self::$logger->warn('No search query provided!');
echo AlphaView::displayPageFoot($this);
self::$logger->debug('<<doGET');
* Renders the search result list
private function renderResultList($BOIDs, $BO, $query) {
// used to track when our pagination range ends
$end = ($this->startPoint+ $config->get('sysListPageAmount'));
// used to track how many results have been displayed or skipped from the pagination range
foreach(array_keys($BOIDs) as $oid) {
// if we have reached the end of the pagination range then break out
if($displayedCount == $end)
// if our display count is >= the start but < the end...
if($temp instanceof ArticleObject && $temp->get('published') == false){
$tags = $temp->getPropObject('tags')->getRelatedObjects();
echo (in_array($tag->get('content'), $queryTerms) ? '<strong>'. $tag->get('content'). ' </strong>' : $tag->get('content'). ' ');
self::$logger->warn('Orpaned TagObject detected pointing to a non-existant BO of OID ['. $oid. '] and type ['. $BO. '].');
public function doPOST($params) {
self::$logger->debug('>>doPOST($params=['. var_export($params, true). '])');
self::$logger->debug('<<doPOST');
* Displays a search form on the top of the page
$html = '<div align="center"><form method="GET" id="search_form" onsubmit="document.location = \''. $config->get('sysURL'). 'search/q/\'+document.getElementById(\'q\').value; return false;">';
$html .= 'Search for: <input type="text" size="80" name="q" id="q"/> ';
$button = new Button('document.location = \''. $config->get('sysURL'). 'search/q/\'+document.getElementById(\'q\').value', 'Search', 'searchButton');
$html .= $button->render();
$html .= '</form></div>';
* Method to display the page footer with pageination links
* Method for rendering the pagination links
$end = ($this->startPoint+ $config->get('sysListPageAmount'));
if($end > $this->resultCount)
$end = $this->resultCount;
if($this->resultCount > 0)
$html .= '<p align="center">Displaying '. ($this->startPoint+ 1). ' to '. $end. ' of <strong>'. $this->resultCount. '</strong>. ';
$html .= '<a href="'. $config->get('sysURL'). 'search/q/'. $this->query. '/start/'. ($this->startPoint- $config->get('sysListPageAmount')). '"><<-Previous</a> ';
}elseif($this->resultCount > $config->get('sysListPageAmount')){
$html .= '<<-Previous ';
for ($i = 0; $i < $this->resultCount; $i+= $config->get('sysListPageAmount')) {
$html .= ' <a href="'. $config->get('sysURL'). 'search/q/'. $this->query. '/start/'. $i. '">'. $page. '</a> ';
}elseif($this->resultCount > $config->get('sysListPageAmount')){
$html .= ' '. $page. ' ';
if ($this->resultCount > $end) {
$html .= ' <a href="'. $config->get('sysURL'). 'search/q/'. $this->query. '/start/'. ($this->startPoint+ $config->get('sysListPageAmount')). '">Next->></a>';
}elseif($this->resultCount > $config->get('sysListPageAmount')){
$html .= ' Next->>';
// now build the new controller
if(basename($_SERVER['PHP_SELF']) == 'Search.php') {
$controller->doPOST($_REQUEST);
$controller->doGET($_GET);
|