Własna wyszukiwarka w aplikacji IP.Board

Dzisiejszy wpis jest delikatnie inny od wcześniejszych wpisów, ponieważ będzie dokładnie opisywał proces tworzenia własnej wyszukiwarki w aplikacjach IP.Board . Artykuł ten jest kontynuacją cyklu wpisów na temat tworzenia dodatków do IP.Board. Nie pozostaje mi nic innego jak zaprosić do czytania dalszej części wpisu.

Zapewne zapytać dlaczego cykl tworzenia aplikacji do IP.Board zaczynam od stworzenia wyszukiwarki a nie od stworzenia szkieletu aplikacji? Odpowiedź jest dość prosta (przynajmniej dla mnie). Wiedzę zdobytą w tej publikacji możemy wykorzystać w dowolnej aplikacji, którą mamy zainstalowaną, a która nie posiada jeszcze własnej wyszukiwarki. Natomiast temat tworzenia szkieletu aplikacji jest bardziej skomplikowany i wymaga więcej czasu ode mnie na napisanie tego, oraz od czytelnika aby przyswoił wiedzę.

Opis tworzenia wyszukiwarki zacznę od opisu struktury katalogów, bo ona jest tutaj bardzo ważna. Na poniższym obrazku przedstawiona jest cała struktura folderu search, który musi znajdować się w katalogu extensions naszej aplikacji:

Teraz znając już strukturę omówię dokładnie co jest czym ;)

Zaczniemy od pliku config.php . Jest to plik konfiguracyjny, który decyduje o tym gdzie można używać wyszukiwarki (chodzi tutaj o wyszukiwanie nowych wpisów, treści użytkownika itp.)

<?php
/* Można szukać w aplikacji */
$CONFIG['can_search']	      = 1;

/* Można widzieć nową zawartość */
$CONFIG['can_viewNewContent'] = 0;

/* Można pokazać aktywną zawartość */
$CONFIG['can_activeContent']  = 0;

/* Można pokazać treść użytkownika */
$CONFIG['can_userContent'] = 0;

/* Typy treści */
$CONFIG['contentTypes'] = array( 'content', 'comments' );
?>

W pliku tym umieszczamy taką zawartość i decydujemy co ma być włączone a co nie. Ustawienia dotyczące typu treści dają nam możliwość w wyszukiwarce wybrania np. sekcji w jakiej chcemy szukać. Przykładowo nasza aplikacja posiada treści i komentarze, w związku z tym możemy szukać w typie treść i w typie komentarze.

Kolejnym plikiem jest form.php , który odpowiada za wyświetlenie formularza z opcjami w wyszukiwarce zaawansowanej. Kod pliku umieszczony jest poniżej.

<?php
/**
 * SolutionrDEVs Application
 * Wyszukiwarka
 *
 * @author      Dawid Baruch
 * @copyright   (c) 2005 - 2012 SolutionDEVs
 * @package     SolutionDEVs Apps
 * @subpackage  PHP
 * @link        http://www.solutiondevs.pl
 * @version     1.0.0 
 *
 */

if ( ! defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.<br />Author: Dawid Baruch <a href='http://www.solutiondevs.pl'><strong>SolutionDEVs.pl</strong></a>";
	exit();
}

class search_form_application
{
	/**
	 * Construct
	 *
	 */
	public function __construct()
	{
		/* Make object */
		$this->registry   =  ipsRegistry::instance();
		$this->DB         =  $this->registry->DB();
		$this->settings   =& $this->registry->fetchSettings();
		$this->request    =& $this->registry->fetchRequest();
		$this->lang       =  $this->registry->getClass('class_localization');
		$this->member     =  $this->registry->member();
		$this->memberData =& $this->registry->member()->fetchMemberData();
		$this->cache      =  $this->registry->cache();
		$this->caches     =& $this->registry->cache()->fetchCaches();
		
		/* Language */
		$this->registry->class_localization->loadLanguageFile( array( 'public_view' ), 'application' );
	}
	

	/**
	 * Return sort drop down
	 * 
	 *
	 * @access	public
	 * @return	array
	 */
	public function fetchSortDropDown()
	{
		$array = array( 
						'content' => array( 
					    					'date'		=> $this->lang->words[ 'sd32_content_date' ],
					    					'title'		=> $this->lang->words[ 'sd32_content_title' ],
										),
					    'comments'  => array( 
					    					'date'		=> $this->lang->words[ 'sd32_comment_date' ],
					    					'title'		=> $this->lang->words[ 'sd32_comment_title' ],
				    					) 
					);
		
		return $array;
	}
	
	/**
	 * Return sort in
	 * Optional function to allow apps to define searchable 'sub-apps'.
	 * 
	 *
	 * @access	public
	 * @return	array
	 */
	public function fetchSortIn()
	{
		$array = array( 
						array( 'content',	$this->lang->words[ 'sd32_search_content' ] ),
					    array( 'comment',	$this->lang->words[ 'sd32_search_comment' ] ) 
					);
		
		return $array;
	}
	
	/**
	 * Retuns the html for displaying the extra groups search filters
	 *
	 * @access	public
	 * @return	string	Filter HTML
	 **/
	public function getHtml()
	{
		return array( 'title' => ipsRegistry::$applications['application']['app_public_title'], 'html' => '' );
	}
}

Metoda fetchSortDropDown() musi zwracać tablicę w podobnej postaci jak w powyższym kodzie. Tablica ta jako klucz zawiera typ treści, a jako wartość tablicę zawierającą pary klucz => opis. Klucz jest nazwą po jakiej będziemy sortować wyniki wyszukiwania.

Metoda fetchSortIn() Zwraca nam tablicę, która definiuje typy treści oraz ich opisową nazwę (nazwę jaką zobaczy użytkownik).

Metoda getHtml() Zwraca nam kod dla dodatkowych ustawień wyszukiwania. Jeśli nie chcemy dawać nic ponad standardowe opcje + możliwość wyszukiwania po różnych typach treści to nie musimy się przejmować tą metodą.

Kolejnym plikiem omówionym przeze mnie będzie format.php

<?php
/**
 * SolutionrDEVs Application
 * Wyszukiwarka
 *
 * @author      Dawid Baruch
 * @copyright   (c) 2005 - 2012 SolutionDEVs
 * @package     SolutionDEVs Apps
 * @subpackage  PHP
 * @link        http://www.solutiondevs.pl
 * @version     1.0.0 
 *
 */

if ( ! defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.<br />Author: Dawid Baruch <a href='http://www.solutiondevs.pl'><strong>SolutionDEVs.pl</strong></a>";
	exit();
}

class search_format_application extends search_format
{
	/**
	 * Constructor
	 */
	public function __construct( ipsRegistry $registry )
	{
		parent::__construct( $registry );
		
		/* Language */
		$this->registry->class_localization->loadLanguageFile( array( 'public_view' ), 'application' );
	}
	
	/**
	 * Parse search results
	 *
	 * @access	private
	 * @param	array 	$r				Search result
	 * @return	array 	$html			Blocks of HTML
	 */
	public function parseAndFetchHtmlBlocks( $rows )
	{
		/* INIT */
		$search_term        = IPSSearchRegistry::get('in.clean_search_term');
				
		/* Go through and build HTML */
		foreach( $rows as $id => $data )
		{
			/* Format content */
			list( $html, $sub ) = $this->formatContent( $data );
			
			$data['content_title'] = IPSText::searchHighlight( $data['content_title'], $search_term );
			
			$results[ $id ] = array( 'html' => $html, 'app' => $data['app'], 'type' => $data['type'], 'sub' => $sub );
		}
		
		return $results;
	}
	
	/**
	 * Formats the forum search result for display
	 *
	 * @access	public
	 * @param	array   $search_row		Array of data from search_index
	 * @return	mixed	Formatted content, ready for display, or array containing a $sub section flag, and content
	 **/
	public function formatContent( $data )
	{
		$template		= ( IPSSearchRegistry::get('application.searchInKey') == 'topics' ) ? 'groupsTopicsSearchResult' : 'groupsGroupSearchResult';

		return array( ipsRegistry::getClass( 'output' )->getTemplate( 'application' )->$template( $data, IPSSearchRegistry::get('display.onlyTitles') ), 0 );
	}

	/**
	 * Decides which type of search this was
	 *
	 * @access public
	 * @return array
	 */
	public function processResults( $ids )
	{
		$this->templates = array( 'group' => 'application', 'template' => 'groupsSearchResult' );
		
		if ( IPSSearchRegistry::get('application.searchInKey') == 'comment' )
		{
			/* Set up wrapper */
			return $this->_processCommentResults( $ids );
		}
		else
		{
			return $this->_processContentResults( $ids );
		}
	}
	
	public function _processContentResults( $ids )
	{
		/* INIT */
		$sort_by     		= IPSSearchRegistry::get('in.search_sort_by');
		$sort_order         = IPSSearchRegistry::get('in.search_sort_order');
		$search_term        = IPSSearchRegistry::get('in.clean_search_term');
		$content_title_only = IPSSearchRegistry::get('opt.searchTitleOnly');
		$onlyPosts          = IPSSearchRegistry::get('opt.onlySearchPosts');
		$order_dir 			= ( $sort_order == 'asc' ) ? 'asc' : 'desc';
		$sortKey			= '';
		$sortType			= '';
		$rows				= array();
		$_rows				= array();
		$members			= array();
		$results			= array();
		
		/* Got some? */
		if ( count( $ids ) )
		{
			/* Sorting */
			switch( $sort_by )
			{
				default:
				case 'date':
					$sortKey  = 'last_post';
					$sortType = 'numerical';
				break;
				
				case 'title':
					$sortKey  = 'g_name';
					$sortType = 'string';
				break;
			}

			/* Set vars */
			IPSSearch::$ask = $sortKey;
			IPSSearch::$aso = strtolower( $order_dir );
			IPSSearch::$ast = $sortType;
			
			/* Fetch data */
			$this->DB->build( array( 
									'select'   => "g.*",
									'from'	   => array( 'c_groups' => 'g' ),
		 							'where'	   => 'g.g_id IN( ' . implode( ',', $ids ) . ')',
									'add_join' => array(
														array(
																'select' => 'f.*',
																'from'   => array( 'forums' => 'f' ),
																'where'  => "f.id=g.g_forum",
																'type'   => 'inner',
															),
														array(
																'select' => 't.*',
																'from'   => array( 'topics' => 't' ),
																'where'  => "t.tid=f.last_id",
																'type'   => 'inner',
															),
														)
							)	);
	
			/* Grab data */
			$res = $this->DB->execute();
			
			/* Grab the results */
			while( $row = $this->DB->fetch( $res ) )
			{
			    IPSText::getTextClass('bbcode')->parse_html 				= 0;
        		IPSText::getTextClass('bbcode')->parse_nl2br				= 1;
        		IPSText::getTextClass('bbcode')->parse_bbcode				= 1;
        		IPSText::getTextClass('bbcode')->parse_smilies				= 0;
        		IPSText::getTextClass('bbcode')->parsing_section			= 'group_add';
    
        		$row['g_desc'] = IPSText::getTextClass( 'bbcode' )->preDisplayParse( $row['g_desc'] );
    		
				$_rows[] = $row;
			}

			/* Sort */
			if ( count( $_rows ) )
			{
				usort( $_rows, array("IPSSearch", "usort") );
		
				foreach( $_rows as $id => $row )
				{				
					/* Got author but no member data? */
					if ( ! empty( $row['last_poster_id'] ) )
					{
						$members[ $row['last_poster_id'] ] = $row['last_poster_id'];
					}
					
					$results[ $row['id'] ] = $this->genericizeResults( $row );
				}
			}

			/* Need to load members? */
		    if ( count( $members ) )
			{
				$mems = IPSMember::load( $members, 'all' );
				
				foreach( $results as $id => $r )
				{
					if ( ! empty( $r['last_poster_id'] ) AND isset( $mems[ $r['last_poster_id'] ] ) )
					{
						$_mem = IPSMember::buildDisplayData( $mems[ $r['last_poster_id'] ], array( 'reputation' => 0, 'warn' => 0 ) );

						$results[ $id ] = array_merge( $results[ $id ], $_mem );
					}
				}
			}
		}

		return $results;
	}
	
	/**
	 * Formats / grabs extra data for results
	 * Takes an array of IDS (can be IDs from anything) and returns an array of expanded data.
	 *
	 * @access public
	 * @return array
	 */
	public function _processCommentResults( $ids )
	{
		/* INIT */
		$sort_by     		= IPSSearchRegistry::get('in.search_sort_by');
		$sort_order         = IPSSearchRegistry::get('in.search_sort_order');
		$search_term        = IPSSearchRegistry::get('in.clean_search_term');
		$content_title_only = IPSSearchRegistry::get('opt.searchTitleOnly');
		$onlyPosts          = IPSSearchRegistry::get('opt.onlySearchPosts');
		$order_dir 			= ( $sort_order == 'asc' ) ? 'asc' : 'desc';
		$sortKey			= '';
		$sortType			= '';
		$rows				= array();
		$_rows				= array();
		$members			= array();
		$results			= array();
		
		/* Got some? */
		if ( count( $ids ) )
		{
			/* Sorting */
			switch( $sort_by )
			{
				default:
				case 'date':
					$sortKey  = 'last_post';
					$sortType = 'numerical';
				break;
				
				case 'title':
					$sortKey  = 'g_name';
					$sortType = 'string';
				break;
				
				case 'reply':
					$sortKey	= 'posts';
					$sortType	= 'numerical';
				break;
				
				case 'views':
					$sortKey	= 'views';
					$sortType	= 'numerical';
				break;
			}

			/* Set vars */
			IPSSearch::$ask = $sortKey;
			IPSSearch::$aso = strtolower( $order_dir );
			IPSSearch::$ast = $sortType;
			
			/* Fetch data */
			$this->DB->build( array( 
									'select'   => "t.*",
									'from'	   => array( 'topics' => 't' ),
		 							'where'	   => 't.tid IN( ' . implode( ',', $ids ) . ')',
									'add_join' => array(
														array(
																'select' => 'g.*',
																'from'   => array( 'c_groups' => 'g' ),
																'where'  => "g.g_forum=t.forum_id",
																'type'   => 'inner',
															),
														)
							)	);
							
			/* Grab data */
			$res = $this->DB->execute();
			
			/* Grab the results */
			while( $row = $this->DB->fetch( $res ) )
			{
			    IPSText::getTextClass('bbcode')->parse_html 				= 0;
        		IPSText::getTextClass('bbcode')->parse_nl2br				= 1;
        		IPSText::getTextClass('bbcode')->parse_bbcode				= 1;
        		IPSText::getTextClass('bbcode')->parse_smilies				= 0;
        		IPSText::getTextClass('bbcode')->parsing_section			= 'group_add';
    
        		$row['g_desc'] = IPSText::getTextClass( 'bbcode' )->preDisplayParse( $row['g_desc'] );
        		
				$_rows[] = $row;
			}

			/* Sort */
			if ( count( $_rows ) )
			{
				usort( $_rows, array("IPSSearch", "usort") );
		
				foreach( $_rows as $id => $row )
				{				
					/* Got author but no member data? */
					if ( ! empty( $row['last_poster_id'] ) )
					{
						$members[ $row['last_poster_id'] ] = $row['last_poster_id'];
					}

					$results[ $row['id'] ] = $this->genericizeResults( $row );
				}
			}

			/* Need to load members? */
			if ( count( $members ) )
			{
				$mems = IPSMember::load( $members, 'all' );
				
				foreach( $results as $id => $r )
				{
				    // Modify by Dawid
					if ( ! empty( $r['last_poster_id'] ) AND isset( $mems[ $r['last_poster_id'] ] ) )
					{
						$_mem = IPSMember::buildDisplayData( $mems[ $r['last_poster_id'] ], array( 'reputation' => 0, 'warn' => 0 ) );

						$results[ $id ] = array_merge( $results[ $id ], $_mem );
					}
				}
			}
		}

		return $results;
	}
	
	/**
	 * Reassigns fields in a generic way for results output
	 *
	 * @param  array  $r
	 * @return array
	 **/
	public function genericizeResults( $r )
	{
		if ( IPSSearchRegistry::get('application.searchInKey') == 'commen' )
		{
			$r['app']                 = 'application';
			$r['content']             = $r['g_desc'];
			$r['content_title']       = $r['title'];
			$r['updated']             = $r['last_post'];
			$r['type_2']              = 'topics';
			$r['type_id_2']           = $r['tid'];
			$r['type_id_3']           = $r['g_id'];
			$r['content_subtitle']    = $r['g_name'];
		}
		else
		{
			$r['app']                 = 'application';
			$r['content']             = $r['g_desc'];
			$r['content_title']       = $r['g_name'];
			$r['updated']             = $r['last_post'];
			$r['type_2']              = 'groups';
			$r['type_id_2']           = $r['g_id'];
			$r['content_subtitle']    = $r['title'];
		}

		return $r;
	}

}

Plik ten odpowiada za prezentację wyników wyszukiwania. Dokładniej metodzie parseAndFetchHtmlBlocks() zwracamy kod html dla poszczególnych wierszy wyników.

Natomiast metoda formatContent() decyduje o tym jakiego szablonu użyć dla konkretnego typu treści.

Pozostałe metody wydaje mi się, że są na tyle przejrzyste, że nie trzeba ich opisywać jakoś szczegółowo.

Przejdźmy zatem do ostatniego już pliku – sql.php

<?php
/**
 * SolutionrDEVs Application
 * Wyszukiwarka
 *
 * @author      Dawid Baruch
 * @copyright   (c) 2005 - 2012 SolutionDEVs
 * @package     SolutionDEVs Apps
 * @subpackage  PHP
 * @link        http://www.solutiondevs.pl
 * @version     1.0.0 
 *
 */

if ( ! defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.<br />Author: Dawid Baruch <a href='http://www.solutiondevs.pl'><strong>SolutionDEVs.pl</strong></a>";
	exit();
}

class search_engine_application extends search_engine
{
	/**
	 * Constructor
	 */
	public function __construct( ipsRegistry $registry )
	{
		/* Hard limit */
		IPSSearchRegistry::set('set.hardLimit', ( ipsRegistry::$settings['search_hardlimit'] ) ? ipsRegistry::$settings['search_hardlimit'] : 200 );

		parent::__construct( $registry );
	}
	
	/**
	 * Decide what type of search we're using
	 *
	 * @access	public
	 * @return	array
	 */
	public function search()
	{
		if ( IPSSearchRegistry::get('application.searchInKey') == 'comment' )
		{
			return $this->_commentSearch();
		}
		else
		{
			return $this->_contentSearch();
		}
	}
	
	/**
	 * Perform a comment search.
	 * Returns an array of a total count (total number of matches)
	 * and an array of IDs ( 0 => 1203, 1 => 928, 2 => 2938 ).. matching the required number based on pagination. The ids returned would be based on the filters and type of search
	 *
	 * So if we had 1000 replies, and we are on page 2 of 25 per page, we'd return 25 items offset by 25
	 *
	 * @access public
	 * @return array
	 */
	public function _contentSearch()
	{
		/* INIT */ 
		$count       		= 0;
		$results     		= array();
		$sort_by     		= IPSSearchRegistry::get('in.search_sort_by');
		$sort_order         = IPSSearchRegistry::get('in.search_sort_order');
		$search_term        = IPSSearchRegistry::get('in.clean_search_term');
		$content_title_only = IPSSearchRegistry::get('opt.searchTitleOnly');
		$order_dir 			= ( $sort_order == 'asc' ) ? 'asc' : 'desc';
		$rows    			= array();
		$count   			= 0;
		$c                  = 0;
		$got     			= 0;
		$sortKey			= '';
		$sortType			= '';

		/* Sorting */
	    switch( $sort_by )
		{
			default:
			case 'date':
				$sortKey  = 'last_post';
				$sortType = 'numerical';
			break;
			
			case 'title':
				$sortKey  = 'g_name';
				$sortType = 'string';
			break;
		}

		/* Fetch data */
		$this->DB->build( array( 
									'select'   => "g.g_id, g.g_name",
									'from'	   => array( 'c_groups' => 'g' ),
									'where'	   => $this->_buildWhereStatement( $search_term, $content_title_only, 'groups' ),
									'limit'    => array(0, IPSSearchRegistry::get('set.hardLimit') + 1),
									'order'	   => "{$sortKey} {$order_dir}",
									'add_join' => array(
														array(
																'from'   => array( 'forums' => 'f' ),
																'where'  => "f.id=g.g_forum",
																'type'   => 'inner',
															),
														array(
																'select' => 't.tid, t.last_poster_id, t.last_post',
																'from'   => array( 'topics' => 't' ),
																'where'  => "t.tid=f.last_id",
																'type'   => 'inner',
															),
														)
						)	);
						
		$this->DB->execute();
		
		/* Fetch count */
		$count = intval( $this->DB->getTotalRows() );
		
		if ( $count > IPSSearchRegistry::get('set.hardLimit') )
		{
			$count = IPSSearchRegistry::get('set.hardLimit');
			
			IPSSearchRegistry::set('set.resultsCutToLimit', true );
		}

		$_rows = array();
		
		/* Fetch to sort */
		while ( $r = $this->DB->fetch() )
		{
			$_rows[ $r['g_id'] ] = $r;
		}
		
		/* Set vars */
		IPSSearch::$ask = $sortKey;
		IPSSearch::$aso = strtolower( $order_dir );
		IPSSearch::$ast = $sortType;
		
		/* Sort */
		if ( count( $_rows ) )
		{
			usort( $_rows, array("IPSSearch", "usort") );

			/* Build result array */
			foreach( $_rows as $r )
			{
				$c++;
				
				if ( IPSSearchRegistry::get('in.start') AND IPSSearchRegistry::get('in.start') >= $c )
				{
					continue;
				}
				
				$rows[ $got ] = $r['g_id'];
							
				$got++;
				
				/* Done? */
				if ( IPSSearchRegistry::get('opt.search_per_page') AND $got >= IPSSearchRegistry::get('opt.search_per_page') )
				{
					break;
				}
			}
		}

		/* Return it */
		return array( 'count' => $count, 'resultSet' => $rows );
	}
	
	/**
	 * Perform an image search.
	 * Returns an array of a total count (total number of matches)
	 * and an array of IDs ( 0 => 1203, 1 => 928, 2 => 2938 ).. matching the required number based on pagination. The ids returned would be based on the filters and type of search
	 *
	 * So if we had 1000 replies, and we are on page 2 of 25 per page, we'd return 25 items offset by 25
	 *
	 * @access public
	 * @return array
	 */
	public function _commentSearch()
	{
		/* INIT */ 
		$count       		= 0;
		$results     		= array();
		$sort_by     		= IPSSearchRegistry::get('in.search_sort_by');
		$sort_order         = IPSSearchRegistry::get('in.search_sort_order');
		$search_term        = IPSSearchRegistry::get('in.clean_search_term');
		$content_title_only = IPSSearchRegistry::get('opt.searchTitleOnly');
		$order_dir 			= ( $sort_order == 'asc' ) ? 'asc' : 'desc';
		$rows    			= array();
		$count   			= 0;
		$c                  = 0;
		$got     			= 0;
		$sortKey			= '';
		$sortType			= '';

		/* Sorting */
	    switch( $sort_by )
		{
			default:
			case 'date':
				$sortKey  = 'last_post';
				$sortType = 'numerical';
			break;
			
			case 'title':
				$sortKey  = 'g_name';
				$sortType = 'string';
			break;
			
			case 'reply':
				$sortKey	= 'posts';
				$sortType	= 'numerical';
			break;
			
			case 'views':
				$sortKey	= 'views';
				$sortType	= 'numerical';
			break;
		}

		/* Fetch data */
		$this->DB->build( array( 
								'select'   => "t.tid, t.last_post, t.last_poster_id, t.views, t.posts",
								'from'	   => array( 'topics' => 't' ),
								'where'	   => $this->_buildWhereStatement( $search_term, $content_title_only ),
								'limit'    => array(0, IPSSearchRegistry::get('set.hardLimit') + 1),
		                        'order'	   => "t.{$sortKey} {$order_dir}",
								'add_join' => array(
														array(
																'select' => 'g.g_id, g.g_name',
																'from'   => array( 'c_groups' => 'g' ),
																'where'  => "g.g_forum=t.forum_id",
																'type'   => 'inner',
															),
														)
								)	);
								
		$this->DB->execute();
		
		/* Fetch count */
		$count = intval( $this->DB->getTotalRows() );
		
		if ( $count > IPSSearchRegistry::get('set.hardLimit') )
		{
			$count = IPSSearchRegistry::get('set.hardLimit');
			
			IPSSearchRegistry::set('set.resultsCutToLimit', true );
		}

		$_rows = array();
		
		/* Fetch to sort */
		while ( $r = $this->DB->fetch() )
		{
			$_rows[ $r['tid'] ] = $r;
		}
		
		/* Set vars */
		IPSSearch::$ask = $sortKey;
		IPSSearch::$aso = strtolower( $order_dir );
		IPSSearch::$ast = $sortType;
		
		/* Sort */
		if ( count( $_rows ) )
		{
			usort( $_rows, array("IPSSearch", "usort") );

			/* Build result array */
			foreach( $_rows as $r )
			{
				$c++;
				
				if ( IPSSearchRegistry::get('in.start') AND IPSSearchRegistry::get('in.start') >= $c )
				{
					continue;
				}
				
				$rows[ $got ] = $r['tid'];
							
				$got++;
				
				/* Done? */
				if ( IPSSearchRegistry::get('opt.search_per_page') AND $got >= IPSSearchRegistry::get('opt.search_per_page') )
				{
					break;
				}
			}
		}

		/* Return it */
		return array( 'count' => $count, 'resultSet' => $rows );
	}
	
	/**
	 * Perform the search for viewUserContent, viewActiveContent, and viewNewContent
	 *
	 * @access	public
	 * @return	array
	 */
	public function _getNonSearchData( $where )
	{
		/* Init */
		$start		= IPSSearchRegistry::get('in.start');
		$perPage	= IPSSearchRegistry::get('opt.search_per_page');
		IPSSearchRegistry::set( 'in.search_sort_by'   , 'date' );
		IPSSearchRegistry::set( 'in.search_sort_order', 'desc' );
		IPSSearchRegistry::set( 'groups.searchInKey'	, in_array( $this->request['search_app_filters']['application']['searchInKey'], array( 'comment', 'content' ) ) ? $this->request['search_app_filters']['application']['searchInKey'] : 'contet' );
		
		/* Fetch the count */
		if( IPSSearchRegistry::get('gapplication.searchInKey') == 'comment' )
		{
			$count = $this->DB->buildAndFetch( 
												array( 
														'select'	=> 'count(*) as count',
														'from'		=> array( 'topis' => 't' ),
														'where'		=> $where,
														'add_join'	=> array(
																				array(
                        																'from'   => array( 'c_groups' => 'g' ),
                        																'where'  => "g.g_forum=t.forum_id",
                        																'type'   => 'inner',
                        															),
																				)
													)	
											);
		}
		else
		{
			$count = $this->DB->buildAndFetch( 
												array( 
														'select'	=> 'count(*) as count',
														'from'		=> array( 'c_groups' => 'g' ),
														'where'		=> $where,
														'add_join' => array(
                        														array(
                        																'from'   => array( 'forums' => 'f' ),
                        																'where'  => "f.id=g.g_forum",
                        																'type'   => 'inner',
                        															),
                        														array(
                        																'from'   => array( 'topics' => 't' ),
                        																'where'  => "t.tid=f.last_id",
                        																'type'   => 'inner',
                        															),
                    														)
													)	
											);
		}

		/* Fetch the data */
		$imgIds = array();
		
		if ( $count['count'] )
		{
			if( IPSSearchRegistry::get('application.searchInKey') == 'comment' )
			{
				$this->DB->build( array( 
											'select'	=> 't.tid as id',
											'from'		=> array( 'topics' => 't' ),
										 	'where'		=> $where,
										 	'order'		=> 't.last_post DESC',
										 	'limit'		=> array( $start, $perPage ),
										 	'add_join'	=> array(
																	array(
            																'from'   => array( 'c_groups' => 'g' ),
            																'where'  => "g.g_forum=t.forum_id",
            																'type'   => 'inner',
            															),
																	) 
								)	);
			}
			else
			{
				$this->DB->build( array( 
											'select'	=> 'g.g_id as id',
											'from'		=> array( 'c_groups' => 'g' ),
										 	'where'		=> $where,
										 	'order'		=> 't.last_post DESC',
										 	'limit'		=> array( $start, $perPage ),
										 	'add_join'	=> array(
																	array(
            																'from'   => array( 'forums' => 'f' ),
            																'where'  => "f.id=g.g_forum",
            																'type'   => 'inner',
            															),
            														array(
            																'from'   => array( 'topics' => 't' ),
            																'where'  => "t.tid=f.last_id",
            																'type'   => 'inner',
            															),
																	) 
								)	);
			}
			$this->DB->execute();

			while( $row = $this->DB->fetch() )
			{
				$imgIds[] = $row['id'];
			}
		}

		/* Return it */
		return array( 'count' => $count['count'], 'resultSet' => $imgIds );
	}
	
	/**
	 * Builds the where portion of a search string
	 *
	 * @access	private
	 * @param	string	$search_term		The string to use in the search
	 * @param	bool	$content_title_only	Search only title records
	 * @return	string
	 */
	private function _buildWhereStatement( $search_term, $content_title_only=false, $type='topics' )
	{
		/* INI */
		$where_clause	= array();
		$searchInCats	= array();
		
		if( $search_term )
		{
			$search_term	= trim($search_term);
			
			if( $type == 'topics' )
			{
				$where_clause[] = "t.title LIKE '%{$search_term}%'";
			}
			else
			{
				$where_clause[] = "(g.g_name LIKE '%{$search_term}%' OR g.g_desc LIKE '%{$search_term}%')";
			}
		}
		
		/* Exclude some items */
		if( !$this->memberData['g_is_supmod'] )
		{
			if( $type == 'topics' )
			{
				$where_clause[] = 't.approved=1 AND t.tdelete_time=0';	
			}
			
			/* Approved only */
			$where_clause[]	= 'g.g_approval=1';	
		}
		
		/* Date Restrict */
		if( $this->search_begin_timestamp && $this->search_end_timestamp )
		{
			$where_clause[] = $this->DB->buildBetween( "t.last_post", $this->search_begin_timestamp, $this->search_end_timestamp );
		}
		else
		{
			if( $this->search_begin_timestamp )
			{
				$where_clause[] = "t.last_post > {$this->search_begin_timestamp}";
			}
			
			if( $this->search_end_timestamp )
			{
				$where_clause[] = "t.last_post < {$this->search_end_timestamp}";
			}
		}
		
		/* Add in AND where conditions */
		if( isset( $this->whereConditions['AND'] ) && count( $this->whereConditions['AND'] ) )
		{
			$where_clause = array_merge( $where_clause, $this->whereConditions['AND'] );
		}
		
		/* ADD in OR where conditions */
		if( isset( $this->whereConditions['OR'] ) && count( $this->whereConditions['OR'] ) )
		{
			$where_clause[] = '( ' . implode( ' OR ', $this->whereConditions['OR'] ) . ' )';
		}
		
		/* Build and return the string */
		return implode( " AND ", $where_clause );
	}
	
	/**
	 * Remap standard columns (Apps can override )
	 *
	 * @access	public
	 * @param	string	$column		sql table column for this condition
	 * @return	string				column
	 * @return	void
	 */
	public function remapColumn( $column )
	{
		$column = $column == 'member_id' ? 'g.member_id' : $column;

		return $column;
	}
		
	/**
	 * Returns an array used in the searchplugin's setCondition method
	 *
	 * @access	public
	 * @param	array 	$data	Array of forums to view
	 * @return	array 	Array with column, operator, and value keys, for use in the setCondition call
	 **/
	public function buildFilterSQL( $data )
	{
		/* INIT */
		$return		= array();
		$searchIn	= $this->request['search_app_filters']['application']['searchInKey'];

		/* Set up some defaults */
		IPSSearchRegistry::set( 'opt.noPostPreview'  , false );
		IPSSearchRegistry::set( 'opt.onlySearchPosts', false );
		
		IPSSearchRegistry::set( 'application.searchInKey', in_array( $searchIn, array( 'comment', 'conetnt' ) ) ? $searchIn : 'content' );
		
		return array();
	}

	/**
	 * Can handle boolean searching
	 *
	 * @access	public
	 * @return	boolean
	 */
	public function isBoolean()
	{
		return false;
	}
}

Plik ten jest używany do wyszukiwania treści w bazie danych. Dokładny opis pliku oraz dalszą część artykułu można przeczytać w publikacji Własna wyszukiwarka treści .

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

*

HTML tags are not allowed.