| Current Path : /home/w/u/e/wuectly/www/03cbe/ |
| Current File : /home/w/u/e/wuectly/www/03cbe/com_finder.zip |
PK ��!]�;�5J J filters/default.phpnu &1i� <?php
/**
* @package Joomla.Administrator
* @subpackage Template.hathor
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
$user = JFactory::getUser();
$userId = $user->get('id');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
JText::script('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT');
JFactory::getDocument()->addScriptDeclaration("
Joomla.submitbutton = function(pressbutton)
{
if (pressbutton == 'filters.delete')
{
if (confirm(Joomla.JText._('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT')))
{
Joomla.submitform(pressbutton);
}
else
{
return false;
}
}
Joomla.submitform(pressbutton);
}
");
?>
<form action="<?php echo JRoute::_('index.php?option=com_finder&view=filters');?>" method="post" name="adminForm" id="adminForm">
<?php if (!empty( $this->sidebar)) : ?>
<div id="j-sidebar-container" class="span2">
<?php echo $this->sidebar; ?>
</div>
<div id="j-main-container" class="span10">
<?php else : ?>
<div id="j-main-container">
<?php endif;?>
<fieldset id="filter-bar">
<legend class="element-invisible"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_FILTERS')); ?></legend>
<div class="filter-search">
<label class="filter-search-lbl" for="filter_search"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_FILTERS')); ?></label>
<input type="text" name="filter_search" id="filter_search" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" title="<?php echo JText::_('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
<button type="submit" class="btn"><?php echo JText::_('JSEARCH_FILTER_SUBMIT'); ?></button>
<button type="button" onclick="document.getElementById('filter_search').value='';this.form.submit();"><?php echo JText::_('JSEARCH_FILTER_CLEAR'); ?></button>
</div>
<div class="filter-select">
<label class="selectlabel" for="filter_state"><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'); ?></label>
<select name="filter_state" id="filter_state">
<option value=""><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE');?></option>
<?php echo JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state'));?>
</select>
<button type="submit" id="filter-go">
<?php echo JText::_('JSUBMIT'); ?></button>
</div>
</fieldset>
<div class="clr"> </div>
<table class="adminlist">
<thead>
<tr>
<th class="checkmark-col">
<input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)" />
</th>
<th class="title">
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th class="nowrap state-col">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
</th>
<th class="title created-by-col">
<?php echo JHtml::_('grid.sort', 'JGRID_HEADING_CREATED_BY', 'a.created_by_alias', $listDirn, $listOrder); ?>
</th>
<th class="title date-col">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_FILTER_TIMESTAMP', 'a.created', $listDirn, $listOrder); ?>
</th>
<th class="nowrap width-5">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_FILTER_MAP_COUNT', 'a.map_count', $listDirn, $listOrder); ?>
</th>
<th class="nowrap id-col">
<?php echo JHtml::_('grid.sort', 'JGRID_HEADING_ID', 'a.filter_id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody>
<?php if (count($this->items) == 0) : ?>
<tr class="row0">
<td class="center" colspan="7">
<?php
if ($this->total == 0):
echo JText::_('COM_FINDER_NO_FILTERS');
?>
<a href="<?php echo JRoute::_('index.php?option=com_finder&task=filter.add'); ?>" title="<?php echo JText::_('COM_FINDER_CREATE_FILTER'); ?>">
<?php echo JText::_('COM_FINDER_CREATE_FILTER'); ?>
</a>
<?php
else:
echo JText::_('COM_FINDER_NO_RESULTS');
endif;
?>
</td>
</tr>
<?php endif; ?>
<?php foreach ($this->items as $i => $item) :
$canCreate = $user->authorise('core.create', 'com_finder');
$canEdit = $user->authorise('core.edit', 'com_finder');
$canCheckin = $user->authorise('core.manage', 'com_checkin') || $filter->checked_out == $user->get('id') || $filter->checked_out == 0;
$canChange = $user->authorise('core.edit.state', 'com_finder') && $canCheckin;
?>
<tr class="row<?php echo $i % 2; ?>">
<th class="center">
<?php echo JHtml::_('grid.id', $i, $item->filter_id); ?>
</th>
<td>
<?php if ($item->checked_out)
{
echo JHtml::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'filters.', $canCheckin);
} ?>
<?php if ($canEdit) { ?>
<a href="<?php echo JRoute::_('index.php?option=com_finder&task=filter.edit&filter_id=' . (int) $item->filter_id); ?>">
<?php echo $this->escape($item->title); ?></a>
<?php } else {
echo $this->escape($item->title);
} ?>
</td>
<td class="center nowrap">
<?php echo JHtml::_('jgrid.published', $item->state, $i, 'filters.', $canChange); ?>
</td>
<td class="center nowrap">
<?php echo $item->created_by_alias ?: $item->user_name; ?>
</td>
<td class="center nowrap">
<?php echo JHtml::_('date', $item->created, JText::_('DATE_FORMAT_LC4')); ?>
</td>
<td class="center nowrap">
<?php echo $item->map_count; ?>
</td>
<td class="center">
<?php echo (int) $item->filter_id; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php echo $this->pagination->getListFooter(); ?>
<input type="hidden" name="task" value="" />
<input type="hidden" name="boxchecked" value="0" />
<input type="hidden" name="filter_order" value="<?php echo $listOrder; ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $listDirn; ?>" />
<?php echo JHtml::_('form.token'); ?>
</div>
</form>
PK ��!] �qDt t index/default.phpnu &1i� <?php
/**
* @package Joomla.Administrator
* @subpackage Template.hathor
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
JHtml::_('bootstrap.tooltip');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$lang = JFactory::getLanguage();
JText::script('COM_FINDER_INDEX_CONFIRM_PURGE_PROMPT');
JText::script('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT');
JFactory::getDocument()->addScriptDeclaration("
Joomla.submitbutton = function(pressbutton)
{
if (pressbutton == 'index.purge')
{
if (confirm(Joomla.JText._('COM_FINDER_INDEX_CONFIRM_PURGE_PROMPT')))
{
Joomla.submitform(pressbutton);
}
else
{
return false;
}
}
if (pressbutton == 'index.delete')
{
if (confirm(Joomla.JText._('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT')))
{
Joomla.submitform(pressbutton);
}
else
{
return false;
}
}
Joomla.submitform(pressbutton);
}
");
?>
<form action="<?php echo JRoute::_('index.php?option=com_finder&view=index');?>" method="post" name="adminForm" id="adminForm">
<?php if (!empty( $this->sidebar)) : ?>
<div id="j-sidebar-container" class="span2">
<?php echo $this->sidebar; ?>
</div>
<div id="j-main-container" class="span10">
<?php else : ?>
<div id="j-main-container">
<?php endif;?>
<fieldset id="filter-bar">
<legend class="element-invisible"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_ITEMS')); ?></legend>
<div class="filter-search">
<label class="filter-search-lbl" for="filter_search"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_ITEMS')); ?></label>
<input type="text" name="filter_search" id="filter_search" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" title="<?php echo JText::_('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
<button type="submit" class="btn"><?php echo JText::_('JSEARCH_FILTER_SUBMIT'); ?></button>
<button type="button" onclick="document.getElementById('filter_search').value='';this.form.submit();"><?php echo JText::_('JSEARCH_FILTER_CLEAR'); ?></button>
</div>
<div class="filter-select">
<label class="selectlabel" for="filter_type"><?php echo JText::_('COM_FINDER_INDEX_TYPE_FILTER'); ?></label>
<select name="filter_type" id="filter_type">
<option value=""><?php echo JText::_('COM_FINDER_INDEX_TYPE_FILTER'); ?></option>
<?php echo JHtml::_('select.options', JHtml::_('finder.typeslist'), 'value', 'text', $this->state->get('filter.type'));?>
</select>
<label class="selectlabel" for="filter_state"><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'); ?></label>
<select name="filter_state" id="filter_state">
<option value=""><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE');?></option>
<?php echo JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state'));?>
</select>
<button type="submit" id="filter-go">
<?php echo JText::_('JSUBMIT'); ?></button>
</div>
</fieldset>
<div class="clr"> </div>
<table class="adminlist">
<thead>
<tr>
<th class="checkmark-col">
<input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)" />
</th>
<th class="title">
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'l.title', $listDirn, $listOrder); ?>
</th>
<th class="nowrap state-col">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'l.published', $listDirn, $listOrder); ?>
</th>
<th class="nowrap width-5">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_INDEX_HEADING_INDEX_TYPE', 'l.type_id', $listDirn, $listOrder); ?>
</th>
<th class="nowrap width-20">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_INDEX_HEADING_LINK_URL', 'l.url', $listDirn, $listOrder); ?>
</th>
<th class="title date-col">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_INDEX_HEADING_INDEX_DATE', 'l.indexdate', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody>
<?php if (count($this->items) == 0) : ?>
<tr class="row0">
<td align="center" colspan="7">
<?php
if ($this->total == 0)
{
echo JText::_('COM_FINDER_INDEX_NO_DATA') . ' ' . JText::_('COM_FINDER_INDEX_TIP');
} else {
echo JText::_('COM_FINDER_INDEX_NO_CONTENT');
}
?>
</td>
</tr>
<?php endif; ?>
<?php $canChange = JFactory::getUser()->authorise('core.manage', 'com_finder'); ?>
<?php foreach ($this->items as $i => $item) : ?>
<tr class="row<?php echo $i % 2; ?>">
<th class="center">
<?php echo JHtml::_('grid.id', $i, $item->link_id); ?>
</th>
<td class="pull-left break-word">
<?php if ((int) $item->publish_start_date or (int) $item->publish_end_date or (int) $item->start_date or (int) $item->end_date) : ?>
<img src="<?php echo JUri::root();?>/media/system/images/calendar.png" style="border:1px;float:right" class="hasTooltip" title="<?php echo JHtml::_('tooltipText', JText::sprintf('COM_FINDER_INDEX_DATE_INFO', $item->publish_start_date, $item->publish_end_date, $item->start_date, $item->end_date), '', 0); ?>" />
<?php endif; ?>
<?php echo $this->escape($item->title); ?>
</td>
<td class="center nowrap">
<?php echo JHtml::_('jgrid.published', $item->published, $i, 'index.', $canChange, 'cb'); ?>
</td>
<td class="center nowrap">
<?php
$key = FinderHelperLanguage::branchSingular($item->t_title);
echo $lang->hasKey($key) ? JText::_($key) : $item->t_title;
?>
</td>
<td class="nowrap">
<?php
if (strlen($item->url) > 80)
{
echo substr($item->url, 0, 70) . '...';
} else {
echo $item->url;
}
?>
</td>
<td class="center nowrap">
<?php echo JHtml::_('date', $item->indexdate, JText::_('DATE_FORMAT_LC4')); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php echo $this->pagination->getListFooter(); ?>
<input type="hidden" name="task" value="display" />
<input type="hidden" name="boxchecked" value="0" />
<input type="hidden" name="filter_order" value="<?php echo $listOrder; ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $listDirn; ?>" />
<?php echo JHtml::_('form.token'); ?>
</div>
</form>
PK ��!]��tyV V maps/default.phpnu &1i� <?php
/**
* @package Joomla.Administrator
* @subpackage Template.hathor
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
JHtml::_('behavior.multiselect');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$lang = JFactory::getLanguage();
JText::script('COM_FINDER_MAPS_CONFIRM_DELETE_PROMPT');
JFactory::getDocument()->addScriptDeclaration("
Joomla.submitbutton = function(pressbutton)
{
if (pressbutton == 'map.delete')
{
if (confirm(Joomla.JText._('COM_FINDER_MAPS_CONFIRM_DELETE_PROMPT')))
{
Joomla.submitform(pressbutton);
}
else
{
return false;
}
}
Joomla.submitform(pressbutton);
}
");
?>
<form action="<?php echo JRoute::_('index.php?option=com_finder&view=maps');?>" method="post" name="adminForm" id="adminForm">
<?php if (!empty( $this->sidebar)) : ?>
<div id="j-sidebar-container" class="span2">
<?php echo $this->sidebar; ?>
</div>
<div id="j-main-container" class="span10">
<?php else : ?>
<div id="j-main-container">
<?php endif;?>
<fieldset id="filter-bar">
<legend class="element-invisible"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_MAPS')); ?></legend>
<div class="filter-search">
<label class="filter-search-lbl" for="filter_search"><?php echo JText::sprintf('COM_FINDER_SEARCH_LABEL', JText::_('COM_FINDER_MAPS')); ?></label>
<input type="text" name="filter_search" id="filter_search" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" title="<?php echo JText::_('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
<button type="submit" class="btn"><?php echo JText::_('JSEARCH_FILTER_SUBMIT'); ?></button>
<button type="button" onclick="document.getElementById('filter_search').value='';this.form.submit();"><?php echo JText::_('JSEARCH_FILTER_CLEAR'); ?></button>
</div>
<div class="filter-select">
<label class="selectlabel" for="filter_branch"><?php echo JText::sprintf('COM_FINDER_FILTER_BY', JText::_('COM_FINDER_MAPS')); ?></label>
<select name="filter_branch" id="filter_branch">
<?php echo JHtml::_('select.options', JHtml::_('finder.mapslist'), 'value', 'text', $this->state->get('filter.branch'));?>
</select>
<label class="selectlabel" for="filter_state"><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'); ?></label>
<select name="filter_state" id="filter_state">
<option value=""><?php echo JText::_('COM_FINDER_INDEX_FILTER_BY_STATE');?></option>
<?php echo JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state')); ?>
</select>
<button type="submit" id="filter-go">
<?php echo JText::_('JSUBMIT'); ?>
</button>
</div>
</fieldset>
<div class="clr"> </div>
<table class="adminlist">
<thead>
<tr>
<th class="checkmark-col">
<input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)" />
</th>
<th class="title">
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th class="nowrap state-col">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
</th>
<th width="1%" class="nowrap center">
<?php echo JText::_('COM_FINDER_HEADING_NODES'); ?>
</th>
</tr>
</thead>
<tbody>
<?php if (count($this->items) == 0) : ?>
<tr class="row0">
<td class="center" colspan="5">
<?php echo JText::_('COM_FINDER_MAPS_NO_CONTENT'); ?>
</td>
</tr>
<?php endif; ?>
<?php $canChange = JFactory::getUser()->authorise('core.manage', 'com_finder'); ?>
<?php foreach ($this->items as $i => $item) :?>
<tr class="row<?php echo $i % 2; ?>">
<th class="center">
<?php echo JHtml::_('grid.id', $i, $item->id); ?>
</th>
<td>
<?php if ((int) $item->num_children === 0) : ?>
<span class="gi">—</span>
<?php endif; ?>
<?php
$key = FinderHelperLanguage::branchSingular($item->title);
$title = $lang->hasKey($key) ? JText::_($key) : $item->title;
echo $this->escape(($title == '*') ? JText::_('JALL_LANGUAGE') : $title);
?>
</td>
<td class="center">
<?php echo JHtml::_('jgrid.published', $item->state, $i, 'maps.', $canChange, 'cb'); ?>
</td>
<td class="center btns">
<?php if ((int) $item->num_children === 0) : ?>
<span class="badge <?php if ($item->num_nodes > 0) echo 'badge-info'; ?>"><?php echo $item->num_nodes; ?></span>
<?php else : ?>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php echo $this->pagination->getListFooter(); ?>
<input type="hidden" name="task" value="" />
<input type="hidden" name="boxchecked" value="0" />
<input type="hidden" name="filter_order" value="<?php echo $listOrder; ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $listDirn; ?>" />
<?php echo JHtml::_('form.token'); ?>
</div>
</form>
PK �"]+��;
;
search/default_form.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
if ($this->params->get('show_advanced', 1) || $this->params->get('show_autosuggest', 1))
{
JHtml::_('jquery.framework');
$script = "
jQuery(function() {";
if ($this->params->get('show_advanced', 1))
{
/*
* This segment of code disables select boxes that have no value when the
* form is submitted so that the URL doesn't get blown up with null values.
*/
$script .= "
jQuery('#finder-search').on('submit', function(e){
e.stopPropagation();
// Disable select boxes with no value selected.
jQuery('#advancedSearch').find('select').each(function(index, el) {
var el = jQuery(el);
if(!el.val()){
el.attr('disabled', 'disabled');
}
});
});";
}
/*
* This segment of code sets up the autocompleter.
*/
if ($this->params->get('show_autosuggest', 1))
{
JHtml::_('script', 'jui/jquery.autocomplete.min.js', array('version' => 'auto', 'relative' => true));
$script .= "
var suggest = jQuery('#q').autocomplete({
serviceUrl: '" . JRoute::_('index.php?option=com_finder&task=suggestions.suggest&format=json&tmpl=component') . "',
paramName: 'q',
minChars: 1,
maxHeight: 400,
width: 300,
zIndex: 9999,
deferRequestBy: 500
});";
}
$script .= "
});";
JFactory::getDocument()->addScriptDeclaration($script);
}
?>
<form id="finder-search" action="<?php echo JRoute::_($this->query->toURI()); ?>" method="get" class="form-inline">
<?php echo $this->getFields(); ?>
<?php
/*
* DISABLED UNTIL WEIRD VALUES CAN BE TRACKED DOWN.
*/
if (false && $this->state->get('list.ordering') !== 'relevance_dsc'): ?>
<input type="hidden" name="o" value="<?php echo $this->escape($this->state->get('list.ordering')); ?>" />
<?php endif; ?>
<fieldset class="word control-group">
<label for="q">
<?php echo JText::_('COM_FINDER_SEARCH_TERMS'); ?>
</label>
<input type="text" name="q" id="q" size="30" value="<?php echo $this->escape($this->query->input); ?>" class="inputbox" />
<?php if ($this->escape($this->query->input) != '' || $this->params->get('allow_empty_search')):?>
<button id="smartsearch-btn" name="Search" type="submit" class="button"><i class="icon-search"></i><?php echo JText::_('JSEARCH_FILTER_SUBMIT');?></button>
<?php else: ?>
<button id="smartsearch-btn" name="Search" type="submit" class="btn disabled"><?php echo JText::_('JSEARCH_FILTER_SUBMIT');?></button>
<?php endif; ?>
<?php if ($this->params->get('show_advanced', 1)): ?>
<a href="#advancedSearch" data-toggle="collapse" class="btn"><i class="icon-list"></i><?php echo JText::_('COM_FINDER_ADVANCED_SEARCH_TOGGLE'); ?></a>
<?php endif ?>
</fieldset>
<?php if ($this->params->get('show_advanced', 1)): ?>
<div id="advancedSearch" class="collapse<?php if ($this->params->get('expand_advanced', 0)) echo ' in'; ?>">
<?php if ($this->params->get('show_advanced_tips', 1)): ?>
<div class="advanced-search-tip">
<?php echo JText::_('COM_FINDER_ADVANCED_TIPS'); ?>
</div>
<?php endif; ?>
<div id="finder-filter-window">
<?php echo JHtml::_('filter.select', $this->query, $this->params); ?>
</div>
</div>
<?php endif; ?>
</form>
PK �0"]���j� � controller.phpnu &1i� <?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Base controller class for Finder.
*
* @since 2.5
*/
class FinderController extends JControllerLegacy
{
/**
* The default view.
*
* @var string
* @since 2.5
*/
protected $default_view = 'index';
/**
* Method to display a view.
*
* @param boolean $cachable If true, the view output will be cached
* @param array $urlparams An array of safe URL parameters and their variable types, for valid values see {@link JFilterInput::clean()}.
*
* @return FinderController A JControllerLegacy object to support chaining.
*
* @since 2.5
*/
public function display($cachable = false, $urlparams = array())
{
JLoader::register('FinderHelper', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/finder.php');
$view = $this->input->get('view', 'index', 'word');
$layout = $this->input->get('layout', 'index', 'word');
$filterId = $this->input->get('filter_id', null, 'int');
// Check for edit form.
if ($view === 'filter' && $layout === 'edit' && !$this->checkEditId('com_finder.edit.filter', $filterId))
{
// Somehow the person just went to the form - we don't allow that.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $filterId));
$this->setMessage($this->getError(), 'error');
$this->setRedirect(JRoute::_('index.php?option=com_finder&view=filters', false));
return false;
}
return parent::display();
}
}
PK �0"]!f� helpers/route.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Finder route helper class.
*
* @since 2.5
*/
class FinderHelperRoute
{
/**
* Method to get the route for a search page.
*
* @param integer $f The search filter id. [optional]
* @param string $q The search query string. [optional]
*
* @return string The search route.
*
* @since 2.5
*/
public static function getSearchRoute($f = null, $q = null)
{
// Get the menu item id.
$query = array('view' => 'search', 'q' => $q, 'f' => $f);
$item = self::getItemid($query);
// Get the base route.
$uri = clone JUri::getInstance('index.php?option=com_finder&view=search');
// Add the pre-defined search filter if present.
if ($f !== null)
{
$uri->setVar('f', $f);
}
// Add the search query string if present.
if ($q !== null)
{
$uri->setVar('q', $q);
}
// Add the menu item id if present.
if ($item !== null)
{
$uri->setVar('Itemid', $item);
}
return $uri->toString(array('path', 'query'));
}
/**
* Method to get the route for an advanced search page.
*
* @param integer $f The search filter id. [optional]
* @param string $q The search query string. [optional]
*
* @return string The advanced search route.
*
* @since 2.5
*/
public static function getAdvancedRoute($f = null, $q = null)
{
// Get the menu item id.
$query = array('view' => 'advanced', 'q' => $q, 'f' => $f);
$item = self::getItemid($query);
// Get the base route.
$uri = clone JUri::getInstance('index.php?option=com_finder&view=advanced');
// Add the pre-defined search filter if present.
if ($q !== null)
{
$uri->setVar('f', $f);
}
// Add the search query string if present.
if ($q !== null)
{
$uri->setVar('q', $q);
}
// Add the menu item id if present.
if ($item !== null)
{
$uri->setVar('Itemid', $item);
}
return $uri->toString(array('path', 'query'));
}
/**
* Method to get the most appropriate menu item for the route based on the
* supplied query needles.
*
* @param array $query An array of URL parameters.
*
* @return mixed An integer on success, null otherwise.
*
* @since 2.5
*/
public static function getItemid($query)
{
static $items, $active;
// Get the menu items for com_finder.
if (!$items || !$active)
{
$app = JFactory::getApplication('site');
$com = JComponentHelper::getComponent('com_finder');
$menu = $app->getMenu();
$active = $menu->getActive();
$items = $menu->getItems('component_id', $com->id);
$items = is_array($items) ? $items : array();
}
// Try to match the active view and filter.
if ($active && @$active->query['view'] == @$query['view'] && @$active->query['f'] == @$query['f'])
{
return $active->id;
}
// Try to match the view, query, and filter.
foreach ($items as $item)
{
if (@$item->query['view'] == @$query['view'] && @$item->query['q'] == @$query['q'] && @$item->query['f'] == @$query['f'])
{
return $item->id;
}
}
// Try to match the view and filter.
foreach ($items as $item)
{
if (@$item->query['view'] == @$query['view'] && @$item->query['f'] == @$query['f'])
{
return $item->id;
}
}
// Try to match the view.
foreach ($items as $item)
{
if (@$item->query['view'] == @$query['view'])
{
return $item->id;
}
}
return null;
}
}
PK �0"]X�1�7 �7 helpers/html/filter.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/language.php');
/**
* Filter HTML Behaviors for Finder.
*
* @since 2.5
*/
abstract class JHtmlFilter
{
/**
* Method to generate filters using the slider widget and decorated
* with the FinderFilter JavaScript behaviors.
*
* @param array $options An array of configuration options. [optional]
*
* @return mixed A rendered HTML widget on success, null otherwise.
*
* @since 2.5
*/
public static function slider($options = array())
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
$html = '';
$filter = null;
// Get the configuration options.
$filterId = array_key_exists('filter_id', $options) ? $options['filter_id'] : null;
$activeNodes = array_key_exists('selected_nodes', $options) ? $options['selected_nodes'] : array();
$classSuffix = array_key_exists('class_suffix', $options) ? $options['class_suffix'] : '';
// Load the predefined filter if specified.
if (!empty($filterId))
{
$query->select('f.data, f.params')
->from($db->quoteName('#__finder_filters') . ' AS f')
->where('f.filter_id = ' . (int) $filterId);
// Load the filter data.
$db->setQuery($query);
try
{
$filter = $db->loadObject();
}
catch (RuntimeException $e)
{
return null;
}
// Initialize the filter parameters.
if ($filter)
{
$filter->params = new Registry($filter->params);
}
}
// Build the query to get the branch data and the number of child nodes.
$query->clear()
->select('t.*, count(c.id) AS children')
->from($db->quoteName('#__finder_taxonomy') . ' AS t')
->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id')
->where('t.parent_id = 1')
->where('t.state = 1')
->where('t.access IN (' . $groups . ')')
->group('t.id, t.parent_id, t.state, t.access, t.ordering, t.title, c.parent_id')
->order('t.ordering, t.title');
// Limit the branch children to a predefined filter.
if ($filter)
{
$query->where('c.id IN(' . $filter->data . ')');
}
// Load the branches.
$db->setQuery($query);
try
{
$branches = $db->loadObjectList('id');
}
catch (RuntimeException $e)
{
return null;
}
// Check that we have at least one branch.
if (count($branches) === 0)
{
return null;
}
$branch_keys = array_keys($branches);
$html .= JHtml::_('bootstrap.startAccordion', 'accordion', array('parent' => true, 'active' => 'accordion-' . $branch_keys[0])
);
// Load plugin language files.
FinderHelperLanguage::loadPluginLanguage();
// Iterate through the branches and build the branch groups.
foreach ($branches as $bk => $bv)
{
// If the multi-lang plugin is enabled then drop the language branch.
if ($bv->title === 'Language' && JLanguageMultilang::isEnabled())
{
continue;
}
// Build the query to get the child nodes for this branch.
$query->clear()
->select('t.*')
->from($db->quoteName('#__finder_taxonomy') . ' AS t')
->where('t.parent_id = ' . (int) $bk)
->where('t.state = 1')
->where('t.access IN (' . $groups . ')')
->order('t.ordering, t.title');
// Self-join to get the parent title.
$query->select('e.title AS parent_title')
->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id'));
// Load the branches.
$db->setQuery($query);
try
{
$nodes = $db->loadObjectList('id');
}
catch (RuntimeException $e)
{
return null;
}
// Translate node titles if possible.
$lang = JFactory::getLanguage();
foreach ($nodes as $nk => $nv)
{
if (trim($nv->parent_title, '**') === 'Language')
{
$title = FinderHelperLanguage::branchLanguageTitle($nv->title);
}
else
{
$key = FinderHelperLanguage::branchPlural($nv->title);
$title = $lang->hasKey($key) ? JText::_($key) : $nv->title;
}
$nodes[$nk]->title = $title;
}
// Adding slides
$html .= JHtml::_('bootstrap.addSlide',
'accordion',
JText::sprintf('COM_FINDER_FILTER_BRANCH_LABEL',
JText::_(FinderHelperLanguage::branchSingular($bv->title)) . ' - ' . count($nodes)
),
'accordion-' . $bk
);
// Populate the toggle button.
$html .= '<button class="btn jform-rightbtn" type="button" onclick="jQuery(\'[id="tax-'
. $bk . '"]\').each(function(){this.click();});"><span class="icon-checkbox-partial"></span> '
. JText::_('JGLOBAL_SELECTION_INVERT') . '</button><hr/>';
// Populate the group with nodes.
foreach ($nodes as $nk => $nv)
{
// Determine if the node should be checked.
$checked = in_array($nk, $activeNodes) ? ' checked="checked"' : '';
// Build a node.
$html .= '<div class="control-group">';
$html .= '<div class="controls">';
$html .= '<label class="checkbox">';
$html .= '<input type="checkbox" class="selector filter-node' . $classSuffix . '" value="' . $nk . '" name="t[]" id="tax-'
. $bk . '"' . $checked . ' />';
$html .= $nv->title;
$html .= '</label>';
$html .= '</div>';
$html .= '</div>';
}
$html .= JHtml::_('bootstrap.endSlide');
}
$html .= JHtml::_('bootstrap.endAccordion');
return $html;
}
/**
* Method to generate filters using select box dropdown controls.
*
* @param FinderIndexerQuery $idxQuery A FinderIndexerQuery object.
* @param array $options An array of options.
*
* @return mixed A rendered HTML widget on success, null otherwise.
*
* @since 2.5
*/
public static function select($idxQuery, $options)
{
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
$filter = null;
// Get the configuration options.
$classSuffix = $options->get('class_suffix', null);
$showDates = $options->get('show_date_filters', false);
// Try to load the results from cache.
$cache = JFactory::getCache('com_finder', '');
$cacheId = 'filter_select_' . serialize(array($idxQuery->filter, $options, $groups, JFactory::getLanguage()->getTag()));
// Check the cached results.
if ($cache->contains($cacheId))
{
$branches = $cache->get($cacheId);
}
else
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Load the predefined filter if specified.
if (!empty($idxQuery->filter))
{
$query->select('f.data, ' . $db->quoteName('f.params'))
->from($db->quoteName('#__finder_filters') . ' AS f')
->where('f.filter_id = ' . (int) $idxQuery->filter);
// Load the filter data.
$db->setQuery($query);
try
{
$filter = $db->loadObject();
}
catch (RuntimeException $e)
{
return null;
}
// Initialize the filter parameters.
if ($filter)
{
$filter->params = new Registry($filter->params);
}
}
// Build the query to get the branch data and the number of child nodes.
$query->clear()
->select('t.*, count(c.id) AS children')
->from($db->quoteName('#__finder_taxonomy') . ' AS t')
->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id')
->where('t.parent_id = 1')
->where('t.state = 1')
->where('t.access IN (' . $groups . ')')
->where('c.state = 1')
->where('c.access IN (' . $groups . ')')
->group($db->quoteName('t.id'))
->order('t.ordering, t.title');
// Limit the branch children to a predefined filter.
if (!empty($filter->data))
{
$query->where('c.id IN(' . $filter->data . ')');
}
// Load the branches.
$db->setQuery($query);
try
{
$branches = $db->loadObjectList('id');
}
catch (RuntimeException $e)
{
return null;
}
// Check that we have at least one branch.
if (count($branches) === 0)
{
return null;
}
// Iterate through the branches and build the branch groups.
foreach ($branches as $bk => $bv)
{
// If the multi-lang plugin is enabled then drop the language branch.
if ($bv->title === 'Language' && JLanguageMultilang::isEnabled())
{
continue;
}
// Build the query to get the child nodes for this branch.
$query->clear()
->select('t.*')
->from($db->quoteName('#__finder_taxonomy') . ' AS t')
->where('t.parent_id = ' . (int) $bk)
->where('t.state = 1')
->where('t.access IN (' . $groups . ')')
->order('t.ordering, t.title');
// Self-join to get the parent title.
$query->select('e.title AS parent_title')
->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id'));
// Limit the nodes to a predefined filter.
if (!empty($filter->data))
{
$query->where('t.id IN(' . $filter->data . ')');
}
// Load the branches.
$db->setQuery($query);
try
{
$branches[$bk]->nodes = $db->loadObjectList('id');
}
catch (RuntimeException $e)
{
return null;
}
// Translate branch nodes if possible.
$language = JFactory::getLanguage();
foreach ($branches[$bk]->nodes as $node_id => $node)
{
if (trim($node->parent_title, '**') === 'Language')
{
$title = FinderHelperLanguage::branchLanguageTitle($node->title);
}
else
{
$key = FinderHelperLanguage::branchPlural($node->title);
$title = $language->hasKey($key) ? JText::_($key) : $node->title;
}
$branches[$bk]->nodes[$node_id]->title = $title;
}
// Add the Search All option to the branch.
array_unshift($branches[$bk]->nodes, array('id' => null, 'title' => JText::_('COM_FINDER_FILTER_SELECT_ALL_LABEL')));
}
// Store the data in cache.
$cache->store($branches, $cacheId);
}
$html = '';
// Add the dates if enabled.
if ($showDates)
{
$html .= JHtml::_('filter.dates', $idxQuery, $options);
}
$html .= '<div class="filter-branch' . $classSuffix . ' control-group clearfix">';
// Iterate through all branches and build code.
foreach ($branches as $bk => $bv)
{
// If the multi-lang plugin is enabled then drop the language branch.
if ($bv->title === 'Language' && JLanguageMultilang::isEnabled())
{
continue;
}
$active = null;
// Check if the branch is in the filter.
if (array_key_exists($bv->title, $idxQuery->filters))
{
// Get the request filters.
$temp = JFactory::getApplication()->input->request->get('t', array(), 'array');
// Search for active nodes in the branch and get the active node.
$active = array_intersect($temp, $idxQuery->filters[$bv->title]);
$active = count($active) === 1 ? array_shift($active) : null;
}
// Build a node.
$html .= '<div class="controls finder-selects">';
$html .= '<label for="tax-' . JFilterOutput::stringURLSafe($bv->title) . '" class="control-label">';
$html .= JText::sprintf('COM_FINDER_FILTER_BRANCH_LABEL', JText::_(FinderHelperLanguage::branchSingular($bv->title)));
$html .= '</label>';
$html .= '<br />';
$html .= JHtml::_(
'select.genericlist',
$branches[$bk]->nodes, 't[]', 'class="inputbox advancedSelect"', 'id', 'title', $active,
'tax-' . JFilterOutput::stringURLSafe($bv->title)
);
$html .= '</div>';
}
$html .= '</div>';
return $html;
}
/**
* Method to generate fields for filtering dates
*
* @param FinderIndexerQuery $idxQuery A FinderIndexerQuery object.
* @param array $options An array of options.
*
* @return mixed A rendered HTML widget on success, null otherwise.
*
* @since 2.5
*/
public static function dates($idxQuery, $options)
{
$html = '';
// Get the configuration options.
$classSuffix = $options->get('class_suffix', null);
$loadMedia = $options->get('load_media', true);
$showDates = $options->get('show_date_filters', false);
if (!empty($showDates))
{
// Build the date operators options.
$operators = array();
$operators[] = JHtml::_('select.option', 'before', JText::_('COM_FINDER_FILTER_DATE_BEFORE'));
$operators[] = JHtml::_('select.option', 'exact', JText::_('COM_FINDER_FILTER_DATE_EXACTLY'));
$operators[] = JHtml::_('select.option', 'after', JText::_('COM_FINDER_FILTER_DATE_AFTER'));
// Load the CSS/JS resources.
if ($loadMedia)
{
JHtml::_('stylesheet', 'com_finder/dates.css', array('version' => 'auto', 'relative' => true));
}
// Open the widget.
$html .= '<ul id="finder-filter-select-dates">';
// Start date filter.
$attribs['class'] = 'input-medium';
$html .= '<li class="filter-date' . $classSuffix . '">';
$html .= '<label for="filter_date1" class="hasTooltip" title ="' . JText::_('COM_FINDER_FILTER_DATE1_DESC') . '">';
$html .= JText::_('COM_FINDER_FILTER_DATE1');
$html .= '</label>';
$html .= '<br />';
$html .= JHtml::_(
'select.genericlist',
$operators, 'w1', 'class="inputbox filter-date-operator advancedSelect"', 'value', 'text', $idxQuery->when1, 'finder-filter-w1'
);
$html .= JHtml::_('calendar', $idxQuery->date1, 'd1', 'filter_date1', '%Y-%m-%d', $attribs);
$html .= '</li>';
// End date filter.
$html .= '<li class="filter-date' . $classSuffix . '">';
$html .= '<label for="filter_date2" class="hasTooltip" title ="' . JText::_('COM_FINDER_FILTER_DATE2_DESC') . '">';
$html .= JText::_('COM_FINDER_FILTER_DATE2');
$html .= '</label>';
$html .= '<br />';
$html .= JHtml::_(
'select.genericlist',
$operators, 'w2', 'class="inputbox filter-date-operator advancedSelect"', 'value', 'text', $idxQuery->when2, 'finder-filter-w2'
);
$html .= JHtml::_('calendar', $idxQuery->date2, 'd2', 'filter_date2', '%Y-%m-%d', $attribs);
$html .= '</li>';
// Close the widget.
$html .= '</ul>';
}
return $html;
}
}
PK �0"]�ش�� � helpers/html/query.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Query HTML behavior class for Finder.
*
* @since 2.5
*/
abstract class JHtmlQuery
{
/**
* Method to get the explained (human-readable) search query.
*
* @param FinderIndexerQuery $query A FinderIndexerQuery object to explain.
*
* @return mixed String if there is data to explain, null otherwise.
*
* @since 2.5
*/
public static function explained(FinderIndexerQuery $query)
{
$parts = array();
// Process the required tokens.
foreach ($query->included as $token)
{
if ($token->required && (!isset($token->derived) || $token->derived == false))
{
$parts[] = '<span class="query-required">' . JText::sprintf('COM_FINDER_QUERY_TOKEN_REQUIRED', $token->term) . '</span>';
}
}
// Process the optional tokens.
foreach ($query->included as $token)
{
if (!$token->required && (!isset($token->derived) || $token->derived == false))
{
$parts[] = '<span class="query-optional">' . JText::sprintf('COM_FINDER_QUERY_TOKEN_OPTIONAL', $token->term) . '</span>';
}
}
// Process the excluded tokens.
foreach ($query->excluded as $token)
{
if (!isset($token->derived) || $token->derived === false)
{
$parts[] = '<span class="query-excluded">' . JText::sprintf('COM_FINDER_QUERY_TOKEN_EXCLUDED', $token->term) . '</span>';
}
}
// Process the start date.
if ($query->date1)
{
$date = JFactory::getDate($query->date1)->format(JText::_('DATE_FORMAT_LC'));
$datecondition = JText::_('COM_FINDER_QUERY_DATE_CONDITION_' . strtoupper($query->when1));
$parts[] = '<span class="query-start-date">' . JText::sprintf('COM_FINDER_QUERY_START_DATE', $datecondition, $date) . '</span>';
}
// Process the end date.
if ($query->date2)
{
$date = JFactory::getDate($query->date2)->format(JText::_('DATE_FORMAT_LC'));
$datecondition = JText::_('COM_FINDER_QUERY_DATE_CONDITION_' . strtoupper($query->when2));
$parts[] = '<span class="query-end-date">' . JText::sprintf('COM_FINDER_QUERY_END_DATE', $datecondition, $date) . '</span>';
}
// Process the taxonomy filters.
if (!empty($query->filters))
{
// Get the filters in the request.
$t = JFactory::getApplication()->input->request->get('t', array(), 'array');
// Process the taxonomy branches.
foreach ($query->filters as $branch => $nodes)
{
// Process the taxonomy nodes.
$lang = JFactory::getLanguage();
foreach ($nodes as $title => $id)
{
// Translate the title for Types
$key = FinderHelperLanguage::branchPlural($title);
if ($lang->hasKey($key))
{
$title = JText::_($key);
}
// Don't include the node if it is not in the request.
if (!in_array($id, $t))
{
continue;
}
// Add the node to the explanation.
$parts[] = '<span class="query-taxonomy">'
. JText::sprintf('COM_FINDER_QUERY_TAXONOMY_NODE', $title, JText::_(FinderHelperLanguage::branchSingular($branch)))
. '</span>';
}
}
}
// Build the interpreted query.
return count($parts) ? JText::sprintf('COM_FINDER_QUERY_TOKEN_INTERPRETED', implode(JText::_('COM_FINDER_QUERY_TOKEN_GLUE'), $parts)) : null;
}
/**
* Method to get the suggested search query.
*
* @param FinderIndexerQuery $query A FinderIndexerQuery object.
*
* @return mixed String if there is a suggestion, false otherwise.
*
* @since 2.5
*/
public static function suggested(FinderIndexerQuery $query)
{
$suggested = false;
// Check if the query input is empty.
if (empty($query->input))
{
return $suggested;
}
// Check if there were any ignored or included keywords.
if (count($query->ignored) || count($query->included))
{
$suggested = $query->input;
// Replace the ignored keyword suggestions.
foreach (array_reverse($query->ignored) as $token)
{
if (isset($token->suggestion))
{
$suggested = str_ireplace($token->term, $token->suggestion, $suggested);
}
}
// Replace the included keyword suggestions.
foreach (array_reverse($query->included) as $token)
{
if (isset($token->suggestion))
{
$suggested = str_ireplace($token->term, $token->suggestion, $suggested);
}
}
// Check if we made any changes.
if ($suggested == $query->input)
{
$suggested = false;
}
}
return $suggested;
}
}
PK �0"]
9P�� � models/suggestions.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\String\StringHelper;
define('FINDER_PATH_INDEXER', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer');
JLoader::register('FinderIndexerHelper', FINDER_PATH_INDEXER . '/helper.php');
/**
* Suggestions model class for the Finder package.
*
* @since 2.5
*/
class FinderModelSuggestions extends JModelList
{
/**
* Context string for the model type.
*
* @var string
* @since 2.5
*/
protected $context = 'com_finder.suggestions';
/**
* Method to get an array of data items.
*
* @return array An array of data items.
*
* @since 2.5
*/
public function getItems()
{
// Get the items.
$items = parent::getItems();
// Convert them to a simple array.
foreach ($items as $k => $v)
{
$items[$k] = $v->term;
}
return $items;
}
/**
* Method to build a database query to load the list data.
*
* @return JDatabaseQuery A database query
*
* @since 2.5
*/
protected function getListQuery()
{
$user = JFactory::getUser();
$groups = \Joomla\Utilities\ArrayHelper::toInteger($user->getAuthorisedViewLevels());
// Create a new query object.
$db = $this->getDbo();
$termIdQuery = $db->getQuery(true);
$termQuery = $db->getQuery(true);
// Limit term count to a reasonable number of results to reduce main query join size
$termIdQuery->select('ti.term_id')
->from($db->quoteName('#__finder_terms', 'ti'))
->where('ti.term LIKE ' . $db->quote($db->escape(StringHelper::strtolower($this->getState('input')), true) . '%', false))
->where('ti.common = 0')
->where('ti.language IN (' . $db->quote($this->getState('language')) . ', ' . $db->quote('*') . ')')
->order('ti.links DESC')
->order('ti.weight DESC');
$termIds = $db->setQuery($termIdQuery, 0, 100)->loadColumn();
// Early return on term mismatch
if (!count($termIds))
{
return $termIdQuery;
}
$termIdString = implode(',', $termIds);
// Select required fields
$termQuery->select('DISTINCT(t.term)')
->select('t.links')
->select('t.weight')
->from($db->quoteName('#__finder_terms') . ' AS t')
->where('t.term_id IN (' . $termIdString . ')')
->order('t.links DESC')
->order('t.weight DESC');
// Determine the relevant mapping table suffix by inverting the logic from drivers
$mappingTableSuffix = StringHelper::substr(md5(StringHelper::substr(StringHelper::strtolower($this->getState('input')), 0, 1)), 0, 1);
// Join mapping table for term <-> link relation
$mappingTable = $db->quoteName('#__finder_links_terms' . $mappingTableSuffix);
$termQuery->join('INNER', $mappingTable . ' AS tm ON tm.term_id = t.term_id');
// Join links table
$termQuery->join('INNER', $db->quoteName('#__finder_links') . ' AS l ON (tm.link_id = l.link_id)')
->where('l.access IN (' . implode(',', $groups) . ')')
->where('l.state = 1')
->where('l.published = 1');
return $termQuery;
}
/**
* Method to get a store id based on model the configuration state.
*
* This is necessary because the model is used by the component and
* different modules that might need different sets of data or different
* ordering requirements.
*
* @param string $id An identifier string to generate the store id. [optional]
*
* @return string A store id.
*
* @since 2.5
*/
protected function getStoreId($id = '')
{
// Add the search query state.
$id .= ':' . $this->getState('input');
$id .= ':' . $this->getState('language');
// Add the list state.
$id .= ':' . $this->getState('list.start');
$id .= ':' . $this->getState('list.limit');
return parent::getStoreId($id);
}
/**
* Method to auto-populate the model state. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 2.5
*/
protected function populateState($ordering = null, $direction = null)
{
// Get the configuration options.
$app = JFactory::getApplication();
$input = $app->input;
$params = JComponentHelper::getParams('com_finder');
$user = JFactory::getUser();
// Get the query input.
$this->setState('input', $input->request->get('q', '', 'string'));
// Set the query language
if (JLanguageMultilang::isEnabled())
{
$lang = JFactory::getLanguage()->getTag();
}
else
{
$lang = FinderIndexerHelper::getDefaultLanguage();
}
$lang = FinderIndexerHelper::getPrimaryLanguage($lang);
$this->setState('language', $lang);
// Load the list state.
$this->setState('list.start', 0);
$this->setState('list.limit', 10);
// Load the parameters.
$this->setState('params', $params);
// Load the user state.
$this->setState('user.id', (int) $user->get('id'));
}
}
PK �0"]Lf6܍� �� models/search.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\String\StringHelper;
use Joomla\Utilities\ArrayHelper;
// Register dependent classes.
define('FINDER_PATH_INDEXER', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer');
JLoader::register('FinderIndexerHelper', FINDER_PATH_INDEXER . '/helper.php');
JLoader::register('FinderIndexerQuery', FINDER_PATH_INDEXER . '/query.php');
JLoader::register('FinderIndexerResult', FINDER_PATH_INDEXER . '/result.php');
JLoader::register('FinderIndexerStemmer', FINDER_PATH_INDEXER . '/stemmer.php');
/**
* Search model class for the Finder package.
*
* @since 2.5
*/
class FinderModelSearch extends JModelList
{
/**
* Context string for the model type
*
* @var string
* @since 2.5
*/
protected $context = 'com_finder.search';
/**
* The query object is an instance of FinderIndexerQuery which contains and
* models the entire search query including the text input; static and
* dynamic taxonomy filters; date filters; etc.
*
* @var FinderIndexerQuery
* @since 2.5
*/
protected $query;
/**
* An array of all excluded terms ids.
*
* @var array
* @since 2.5
*/
protected $excludedTerms = array();
/**
* An array of all included terms ids.
*
* @var array
* @since 2.5
*/
protected $includedTerms = array();
/**
* An array of all required terms ids.
*
* @var array
* @since 2.5
*/
protected $requiredTerms = array();
/**
* Method to get the results of the query.
*
* @return array An array of FinderIndexerResult objects.
*
* @since 2.5
* @throws Exception on database error.
*/
public function getResults()
{
// Check if the search query is valid.
if (empty($this->query->search))
{
return null;
}
// Check if we should return results.
if (empty($this->includedTerms) && (empty($this->query->filters) || !$this->query->empty))
{
return null;
}
// Get the store id.
$store = $this->getStoreId('getResults');
// Use the cached data if possible.
if ($this->retrieve($store))
{
return $this->retrieve($store);
}
// Get the row data.
$items = $this->getResultsData();
// Check the data.
if (empty($items))
{
return null;
}
// Create the query to get the search results.
$db = $this->getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('link_id') . ', ' . $db->quoteName('object'))
->from($db->quoteName('#__finder_links'))
->where($db->quoteName('link_id') . ' IN (' . implode(',', array_keys($items)) . ')');
// Load the results from the database.
$db->setQuery($query);
$rows = $db->loadObjectList('link_id');
// Set up our results container.
$results = $items;
// Convert the rows to result objects.
foreach ($rows as $rk => $row)
{
// Build the result object.
if (is_resource($row->object))
{
$object = pg_unescape_bytea(stream_get_contents($row->object));
$result = unserialize(str_replace("''", "'", $object));
}
else
{
$result = unserialize($row->object);
}
$result->weight = $results[$rk];
$result->link_id = $rk;
// Add the result back to the stack.
$results[$rk] = $result;
}
// Switch to a non-associative array.
$results = array_values($results);
// Push the results into cache.
$this->store($store, $results);
// Return the results.
return $this->retrieve($store);
}
/**
* Method to get the total number of results.
*
* @return integer The total number of results.
*
* @since 2.5
* @throws Exception on database error.
*/
public function getTotal()
{
// Check if the search query is valid.
if (empty($this->query->search))
{
return null;
}
// Check if we should return results.
if (empty($this->includedTerms) && (empty($this->query->filters) || !$this->query->empty))
{
return null;
}
// Get the store id.
$store = $this->getStoreId('getTotal');
// Use the cached data if possible.
if ($this->retrieve($store))
{
return $this->retrieve($store);
}
// Get the results total.
$total = $this->getResultsTotal();
// Push the total into cache.
$this->store($store, $total);
// Return the total.
return $this->retrieve($store);
}
/**
* Method to get the query object.
*
* @return FinderIndexerQuery A query object.
*
* @since 2.5
*/
public function getQuery()
{
// Return the query object.
return $this->query;
}
/**
* Method to build a database query to load the list data.
*
* @return JDatabaseQuery A database query.
*
* @since 2.5
*/
protected function getListQuery()
{
// Get the store id.
$store = $this->getStoreId('getListQuery');
// Use the cached data if possible.
if ($this->retrieve($store, false))
{
return clone $this->retrieve($store, false);
}
// Set variables
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
// Create a new query object.
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('l.link_id')
->from($db->quoteName('#__finder_links') . ' AS l')
->where('l.access IN (' . $groups . ')')
->where('l.state = 1')
->where('l.published = 1');
// Get the null date and the current date, minus seconds.
$nullDate = $db->quote($db->getNullDate());
$nowDate = $db->quote(substr_replace(JFactory::getDate()->toSql(), '00', -2));
// Add the publish up and publish down filters.
$query->where('(l.publish_start_date = ' . $nullDate . ' OR l.publish_start_date <= ' . $nowDate . ')')
->where('(l.publish_end_date = ' . $nullDate . ' OR l.publish_end_date >= ' . $nowDate . ')');
/*
* Add the taxonomy filters to the query. We have to join the taxonomy
* map table for each group so that we can use AND clauses across
* groups. Within each group there can be an array of values that will
* use OR clauses.
*/
if (!empty($this->query->filters))
{
// Convert the associative array to a numerically indexed array.
$groups = array_values($this->query->filters);
// Iterate through each taxonomy group and add the join and where.
for ($i = 0, $c = count($groups); $i < $c; $i++)
{
// We use the offset because each join needs a unique alias.
$query->join('INNER', $db->quoteName('#__finder_taxonomy_map') . ' AS t' . $i . ' ON t' . $i . '.link_id = l.link_id')
->where('t' . $i . '.node_id IN (' . implode(',', $groups[$i]) . ')');
}
}
// Add the start date filter to the query.
if (!empty($this->query->date1))
{
// Escape the date.
$date1 = $db->quote($this->query->date1);
// Add the appropriate WHERE condition.
if ($this->query->when1 === 'before')
{
$query->where($db->quoteName('l.start_date') . ' <= ' . $date1);
}
elseif ($this->query->when1 === 'after')
{
$query->where($db->quoteName('l.start_date') . ' >= ' . $date1);
}
else
{
$query->where($db->quoteName('l.start_date') . ' = ' . $date1);
}
}
// Add the end date filter to the query.
if (!empty($this->query->date2))
{
// Escape the date.
$date2 = $db->quote($this->query->date2);
// Add the appropriate WHERE condition.
if ($this->query->when2 === 'before')
{
$query->where($db->quoteName('l.start_date') . ' <= ' . $date2);
}
elseif ($this->query->when2 === 'after')
{
$query->where($db->quoteName('l.start_date') . ' >= ' . $date2);
}
else
{
$query->where($db->quoteName('l.start_date') . ' = ' . $date2);
}
}
// Filter by language
if ($this->getState('filter.language'))
{
$query->where('l.language IN (' . $db->quote(JFactory::getLanguage()->getTag()) . ', ' . $db->quote('*') . ')');
}
// Push the data into cache.
$this->store($store, $query, false);
// Return a copy of the query object.
return clone $this->retrieve($store, false);
}
/**
* Method to get the total number of results for the search query.
*
* @return integer The results total.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getResultsTotal()
{
// Get the store id.
$store = $this->getStoreId('getResultsTotal', false);
// Use the cached data if possible.
if ($this->retrieve($store))
{
return $this->retrieve($store);
}
// Get the base query and add the ordering information.
$base = $this->getListQuery();
$base->select('0 AS ordering');
// Get the maximum number of results.
$limit = (int) $this->getState('match.limit');
/*
* If there are no optional or required search terms in the query,
* we can get the result total in one relatively simple database query.
*/
if (empty($this->includedTerms))
{
// Adjust the query to join on the appropriate mapping table.
$query = clone $base;
$query->clear('select')
->select('COUNT(DISTINCT l.link_id)');
// Get the total from the database.
$this->_db->setQuery($query);
$total = $this->_db->loadResult();
// Push the total into cache.
$this->store($store, min($total, $limit));
// Return the total.
return $this->retrieve($store);
}
/*
* If there are optional or required search terms in the query, the
* process of getting the result total is more complicated.
*/
$start = 0;
$items = array();
$sorted = array();
$maps = array();
$excluded = $this->getExcludedLinkIds();
/*
* Iterate through the included search terms and group them by mapping
* table suffix. This ensures that we never have to do more than 16
* queries to get a batch. This may seem like a lot but it is rarely
* anywhere near 16 because of the improved mapping algorithm.
*/
foreach ($this->includedTerms as $token => $ids)
{
// Get the mapping table suffix.
$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)), 0, 1);
// Initialize the mapping group.
if (!array_key_exists($suffix, $maps))
{
$maps[$suffix] = array();
}
// Add the terms to the mapping group.
$maps[$suffix] = array_merge($maps[$suffix], $ids);
}
/*
* When the query contains search terms we need to find and process the
* result total iteratively using a do-while loop.
*/
do
{
// Create a container for the fetched results.
$results = array();
$more = false;
/*
* Iterate through the mapping groups and load the total from each
* mapping table.
*/
foreach ($maps as $suffix => $ids)
{
// Create a storage key for this set.
$setId = $this->getStoreId('getResultsTotal:' . serialize(array_values($ids)) . ':' . $start . ':' . $limit);
// Use the cached data if possible.
if ($this->retrieve($setId))
{
$temp = $this->retrieve($setId);
}
// Load the data from the database.
else
{
// Adjust the query to join on the appropriate mapping table.
$query = clone $base;
$query->join('INNER', '#__finder_links_terms' . $suffix . ' AS m ON m.link_id = l.link_id')
->where('m.term_id IN (' . implode(',', $ids) . ')');
// Load the results from the database.
$this->_db->setQuery($query, $start, $limit);
$temp = $this->_db->loadObjectList();
// Set the more flag to true if any of the sets equal the limit.
$more = count($temp) === $limit;
// We loaded the data unkeyed but we need it to be keyed for later.
$junk = $temp;
$temp = array();
// Convert to an associative array.
for ($i = 0, $c = count($junk); $i < $c; $i++)
{
$temp[$junk[$i]->link_id] = $junk[$i];
}
// Store this set in cache.
$this->store($setId, $temp);
}
// Merge the results.
$results = array_merge($results, $temp);
}
// Check if there are any excluded terms to deal with.
if (count($excluded))
{
// Remove any results that match excluded terms.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
if (in_array($results[$i]->link_id, $excluded))
{
unset($results[$i]);
}
}
// Reset the array keys.
$results = array_values($results);
}
// Iterate through the set to extract the unique items.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
if (!isset($sorted[$results[$i]->link_id]))
{
$sorted[$results[$i]->link_id] = $results[$i]->ordering;
}
}
/*
* If the query contains just optional search terms and we have
* enough items for the page, we can stop here.
*/
if (empty($this->requiredTerms))
{
// If we need more items and they're available, make another pass.
if ($more && count($sorted) < $limit)
{
// Increment the batch starting point and continue.
$start += $limit;
continue;
}
// Push the total into cache.
$this->store($store, min(count($sorted), $limit));
// Return the total.
return $this->retrieve($store);
}
/*
* The query contains required search terms so we have to iterate
* over the items and remove any items that do not match all of the
* required search terms. This is one of the most expensive steps
* because a required token could theoretically eliminate all of
* current terms which means we would have to loop through all of
* the possibilities.
*/
foreach ($this->requiredTerms as $token => $required)
{
// Create a storage key for this set.
$setId = $this->getStoreId('getResultsTotal:required:' . serialize(array_values($required)) . ':' . $start . ':' . $limit);
// Use the cached data if possible.
if ($this->retrieve($setId))
{
$reqTemp = $this->retrieve($setId);
}
// Check if the token was matched.
elseif (empty($required))
{
return null;
}
// Load the data from the database.
else
{
// Setup containers in case we have to make multiple passes.
$reqStart = 0;
$reqTemp = array();
do
{
// Get the map table suffix.
$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)), 0, 1);
// Adjust the query to join on the appropriate mapping table.
$query = clone $base;
$query->join('INNER', '#__finder_links_terms' . $suffix . ' AS m ON m.link_id = l.link_id')
->where('m.term_id IN (' . implode(',', $required) . ')');
// Load the results from the database.
$this->_db->setQuery($query, $reqStart, $limit);
$temp = $this->_db->loadObjectList('link_id');
// Set the required token more flag to true if the set equal the limit.
$reqMore = count($temp) === $limit;
// Merge the matching set for this token.
$reqTemp += $temp;
// Increment the term offset.
$reqStart += $limit;
}
while ($reqMore === true);
// Store this set in cache.
$this->store($setId, $reqTemp);
}
// Remove any items that do not match the required term.
$sorted = array_intersect_key($sorted, $reqTemp);
}
// If we need more items and they're available, make another pass.
if ($more && count($sorted) < $limit)
{
// Increment the batch starting point.
$start += $limit;
// Merge the found items.
$items += $sorted;
continue;
}
// Otherwise, end the loop.
{
// Merge the found items.
$items += $sorted;
$more = false;
}
// End do-while loop.
}
while ($more === true);
// Set the total.
$total = count($items);
$total = min($total, $limit);
// Push the total into cache.
$this->store($store, $total);
// Return the total.
return $this->retrieve($store);
}
/**
* Method to get the results for the search query.
*
* @return array An array of result data objects.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getResultsData()
{
// Get the store id.
$store = $this->getStoreId('getResultsData', false);
// Use the cached data if possible.
if ($this->retrieve($store))
{
return $this->retrieve($store);
}
// Get the result ordering and direction.
$ordering = $this->getState('list.ordering', 'l.start_date');
$direction = $this->getState('list.direction', 'DESC');
// Get the base query and add the ordering information.
$base = $this->getListQuery();
$base->select($this->_db->escape($ordering) . ' AS ordering');
$base->order($this->_db->escape($ordering) . ' ' . $this->_db->escape($direction));
/*
* If there are no optional or required search terms in the query, we
* can get the results in one relatively simple database query.
*/
if (empty($this->includedTerms))
{
// Get the results from the database.
$this->_db->setQuery($base, (int) $this->getState('list.start'), (int) $this->getState('list.limit'));
$return = $this->_db->loadObjectList('link_id');
// Get a new store id because this data is page specific.
$store = $this->getStoreId('getResultsData', true);
// Push the results into cache.
$this->store($store, $return);
// Return the results.
return $this->retrieve($store);
}
/*
* If there are optional or required search terms in the query, the
* process of getting the results is more complicated.
*/
$start = 0;
$limit = (int) $this->getState('match.limit');
$items = array();
$sorted = array();
$maps = array();
$excluded = $this->getExcludedLinkIds();
/*
* Iterate through the included search terms and group them by mapping
* table suffix. This ensures that we never have to do more than 16
* queries to get a batch. This may seem like a lot but it is rarely
* anywhere near 16 because of the improved mapping algorithm.
*/
foreach ($this->includedTerms as $token => $ids)
{
// Get the mapping table suffix.
$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)), 0, 1);
// Initialize the mapping group.
if (!array_key_exists($suffix, $maps))
{
$maps[$suffix] = array();
}
// Add the terms to the mapping group.
$maps[$suffix] = array_merge($maps[$suffix], $ids);
}
/*
* When the query contains search terms we need to find and process the
* results iteratively using a do-while loop.
*/
do
{
// Create a container for the fetched results.
$results = array();
$more = false;
/*
* Iterate through the mapping groups and load the results from each
* mapping table.
*/
foreach ($maps as $suffix => $ids)
{
// Create a storage key for this set.
$setId = $this->getStoreId('getResultsData:' . serialize(array_values($ids)) . ':' . $start . ':' . $limit);
// Use the cached data if possible.
if ($this->retrieve($setId))
{
$temp = $this->retrieve($setId);
}
// Load the data from the database.
else
{
// Adjust the query to join on the appropriate mapping table.
$query = clone $base;
$query->join('INNER', $this->_db->quoteName('#__finder_links_terms' . $suffix) . ' AS m ON m.link_id = l.link_id')
->where('m.term_id IN (' . implode(',', $ids) . ')');
// Load the results from the database.
$this->_db->setQuery($query, $start, $limit);
$temp = $this->_db->loadObjectList('link_id');
// Store this set in cache.
$this->store($setId, $temp);
// The data is keyed by link_id to ease caching, we don't need it till later.
$temp = array_values($temp);
}
// Set the more flag to true if any of the sets equal the limit.
$more = count($temp) === $limit;
// Merge the results.
$results = array_merge($results, $temp);
}
// Check if there are any excluded terms to deal with.
if (count($excluded))
{
// Remove any results that match excluded terms.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
if (in_array($results[$i]->link_id, $excluded))
{
unset($results[$i]);
}
}
// Reset the array keys.
$results = array_values($results);
}
/*
* If we are ordering by relevance we have to add up the relevance
* scores that are contained in the ordering field.
*/
if ($ordering === 'm.weight')
{
// Iterate through the set to extract the unique items.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
// Add the total weights for all included search terms.
if (isset($sorted[$results[$i]->link_id]))
{
$sorted[$results[$i]->link_id] += (float) $results[$i]->ordering;
}
else
{
$sorted[$results[$i]->link_id] = (float) $results[$i]->ordering;
}
}
}
/*
* If we are ordering by start date we have to add convert the
* dates to unix timestamps.
*/
elseif ($ordering === 'l.start_date')
{
// Iterate through the set to extract the unique items.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
if (!isset($sorted[$results[$i]->link_id]))
{
$sorted[$results[$i]->link_id] = strtotime($results[$i]->ordering);
}
}
}
/*
* If we are not ordering by relevance or date, we just have to add
* the unique items to the set.
*/
else
{
// Iterate through the set to extract the unique items.
for ($i = 0, $c = count($results); $i < $c; $i++)
{
if (!isset($sorted[$results[$i]->link_id]))
{
$sorted[$results[$i]->link_id] = $results[$i]->ordering;
}
}
}
// Sort the results.
natcasesort($items);
if ($direction === 'DESC')
{
$items = array_reverse($items, true);
}
/*
* If the query contains just optional search terms and we have
* enough items for the page, we can stop here.
*/
if (empty($this->requiredTerms))
{
// If we need more items and they're available, make another pass.
if ($more && count($sorted) < ($this->getState('list.start') + $this->getState('list.limit')))
{
// Increment the batch starting point and continue.
$start += $limit;
continue;
}
// Push the results into cache.
$this->store($store, $sorted);
// Return the requested set.
return array_slice($this->retrieve($store), (int) $this->getState('list.start'), (int) $this->getState('list.limit'), true);
}
/*
* The query contains required search terms so we have to iterate
* over the items and remove any items that do not match all of the
* required search terms. This is one of the most expensive steps
* because a required token could theoretically eliminate all of
* current terms which means we would have to loop through all of
* the possibilities.
*/
foreach ($this->requiredTerms as $token => $required)
{
// Create a storage key for this set.
$setId = $this->getStoreId('getResultsData:required:' . serialize(array_values($required)) . ':' . $start . ':' . $limit);
// Use the cached data if possible.
if ($this->retrieve($setId))
{
$reqTemp = $this->retrieve($setId);
}
// Check if the token was matched.
elseif (empty($required))
{
return null;
}
// Load the data from the database.
else
{
// Setup containers in case we have to make multiple passes.
$reqStart = 0;
$reqTemp = array();
do
{
// Get the map table suffix.
$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)), 0, 1);
// Adjust the query to join on the appropriate mapping table.
$query = clone $base;
$query->join('INNER', $this->_db->quoteName('#__finder_links_terms' . $suffix) . ' AS m ON m.link_id = l.link_id')
->where('m.term_id IN (' . implode(',', $required) . ')');
// Load the results from the database.
$this->_db->setQuery($query, $reqStart, $limit);
$temp = $this->_db->loadObjectList('link_id');
// Set the required token more flag to true if the set equal the limit.
$reqMore = count($temp) === $limit;
// Merge the matching set for this token.
$reqTemp += $temp;
// Increment the term offset.
$reqStart += $limit;
}
while ($reqMore === true);
// Store this set in cache.
$this->store($setId, $reqTemp);
}
// Remove any items that do not match the required term.
$sorted = array_intersect_key($sorted, $reqTemp);
}
// If we need more items and they're available, make another pass.
if ($more && count($sorted) < ($this->getState('list.start') + $this->getState('list.limit')))
{
// Increment the batch starting point.
$start += $limit;
// Merge the found items.
$items = array_merge($items, $sorted);
continue;
}
// Otherwise, end the loop.
else
{
// Set the found items.
$items = $sorted;
$more = false;
}
// End do-while loop.
}
while ($more === true);
// Push the results into cache.
$this->store($store, $items);
// Return the requested set.
return array_slice($this->retrieve($store), (int) $this->getState('list.start'), (int) $this->getState('list.limit'), true);
}
/**
* Method to get an array of link ids that match excluded terms.
*
* @return array An array of links ids.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getExcludedLinkIds()
{
// Check if the search query has excluded terms.
if (empty($this->excludedTerms))
{
return array();
}
// Get the store id.
$store = $this->getStoreId('getExcludedLinkIds', false);
// Use the cached data if possible.
if ($this->retrieve($store))
{
return $this->retrieve($store);
}
// Initialize containers.
$links = array();
$maps = array();
/*
* Iterate through the excluded search terms and group them by mapping
* table suffix. This ensures that we never have to do more than 16
* queries to get a batch. This may seem like a lot but it is rarely
* anywhere near 16 because of the improved mapping algorithm.
*/
foreach ($this->excludedTerms as $token => $id)
{
// Get the mapping table suffix.
$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)), 0, 1);
// Initialize the mapping group.
if (!array_key_exists($suffix, $maps))
{
$maps[$suffix] = array();
}
// Add the terms to the mapping group.
$maps[$suffix][] = (int) $id;
}
/*
* Iterate through the mapping groups and load the excluded links ids
* from each mapping table.
*/
// Create a new query object.
$db = $this->getDbo();
$query = $db->getQuery(true);
foreach ($maps as $suffix => $ids)
{
// Create the query to get the links ids.
$query->clear()
->select('link_id')
->from($db->quoteName('#__finder_links_terms' . $suffix))
->where($db->quoteName('term_id') . ' IN (' . implode(',', $ids) . ')')
->group($db->quoteName('link_id'));
// Load the link ids from the database.
$db->setQuery($query);
$temp = $db->loadColumn();
// Merge the link ids.
$links = array_merge($links, $temp);
}
// Sanitize the link ids.
$links = array_unique($links);
$links = ArrayHelper::toInteger($links);
// Push the link ids into cache.
$this->store($store, $links);
return $links;
}
/**
* Method to get a store id based on model the configuration state.
*
* This is necessary because the model is used by the component and
* different modules that might need different sets of data or different
* ordering requirements.
*
* @param string $id An identifier string to generate the store id. [optional]
* @param boolean $page True to store the data paged, false to store all data. [optional]
*
* @return string A store id.
*
* @since 2.5
*/
protected function getStoreId($id = '', $page = true)
{
// Get the query object.
$query = $this->getQuery();
// Add the search query state.
$id .= ':' . $query->input;
$id .= ':' . $query->language;
$id .= ':' . $query->filter;
$id .= ':' . serialize($query->filters);
$id .= ':' . $query->date1;
$id .= ':' . $query->date2;
$id .= ':' . $query->when1;
$id .= ':' . $query->when2;
if ($page)
{
// Add the list state for page specific data.
$id .= ':' . $this->getState('list.start');
$id .= ':' . $this->getState('list.limit');
$id .= ':' . $this->getState('list.ordering');
$id .= ':' . $this->getState('list.direction');
}
return parent::getStoreId($id);
}
/**
* Method to auto-populate the model state. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field. [optional]
* @param string $direction An optional direction. [optional]
*
* @return void
*
* @since 2.5
*/
protected function populateState($ordering = null, $direction = null)
{
// Get the configuration options.
$app = JFactory::getApplication();
$input = $app->input;
$params = $app->getParams();
$user = JFactory::getUser();
$this->setState('filter.language', JLanguageMultilang::isEnabled());
// Setup the stemmer.
if ($params->get('stem', 1) && $params->get('stemmer', 'porter_en'))
{
FinderIndexerHelper::$stemmer = FinderIndexerStemmer::getInstance($params->get('stemmer', 'porter_en'));
}
$request = $input->request;
$options = array();
// Get the empty query setting.
$options['empty'] = $params->get('allow_empty_query', 0);
// Get the static taxonomy filters.
$options['filter'] = $request->getInt('f', $params->get('f', ''));
// Get the dynamic taxonomy filters.
$options['filters'] = $request->get('t', $params->get('t', array()), '', 'array');
// Get the query string.
$options['input'] = $request->getString('q', $params->get('q', ''));
// Get the query language.
$options['language'] = $request->getCmd('l', $params->get('l', ''));
// Get the start date and start date modifier filters.
$options['date1'] = $request->getString('d1', $params->get('d1', ''));
$options['when1'] = $request->getString('w1', $params->get('w1', ''));
// Get the end date and end date modifier filters.
$options['date2'] = $request->getString('d2', $params->get('d2', ''));
$options['when2'] = $request->getString('w2', $params->get('w2', ''));
// Load the query object.
$this->query = new FinderIndexerQuery($options);
// Load the query token data.
$this->excludedTerms = $this->query->getExcludedTermIds();
$this->includedTerms = $this->query->getIncludedTermIds();
$this->requiredTerms = $this->query->getRequiredTermIds();
// Load the list state.
$this->setState('list.start', $input->get('limitstart', 0, 'uint'));
$this->setState('list.limit', $input->get('limit', $app->get('list_limit', 20), 'uint'));
/**
* Load the sort ordering.
* Currently this is 'hard' coded via menu item parameter but may not satisfy a users need.
* More flexibility was way more user friendly. So we allow the user to pass a custom value
* from the pool of fields that are indexed like the 'title' field.
* Also, we allow this parameter to be passed in either case (lower/upper).
*/
$order = $input->getWord('filter_order', $params->get('sort_order', 'relevance'));
$order = StringHelper::strtolower($order);
switch ($order)
{
case 'date':
$this->setState('list.ordering', 'l.start_date');
break;
case 'price':
$this->setState('list.ordering', 'l.list_price');
break;
case ($order === 'relevance' && !empty($this->includedTerms)) :
$this->setState('list.ordering', 'm.weight');
break;
// Custom field that is indexed and might be required for ordering
case 'title':
$this->setState('list.ordering', 'l.title');
break;
default:
$this->setState('list.ordering', 'l.link_id');
break;
}
/**
* Load the sort direction.
* Currently this is 'hard' coded via menu item parameter but may not satisfy a users need.
* More flexibility was way more user friendly. So we allow to be inverted.
* Also, we allow this parameter to be passed in either case (lower/upper).
*/
$dirn = $input->getWord('filter_order_Dir', $params->get('sort_direction', 'desc'));
$dirn = StringHelper::strtolower($dirn);
switch ($dirn)
{
case 'asc':
$this->setState('list.direction', 'ASC');
break;
default:
case 'desc':
$this->setState('list.direction', 'DESC');
break;
}
// Set the match limit.
$this->setState('match.limit', 1000);
// Load the parameters.
$this->setState('params', $params);
// Load the user state.
$this->setState('user.id', (int) $user->get('id'));
$this->setState('user.groups', $user->getAuthorisedViewLevels());
}
/**
* Method to retrieve data from cache.
*
* @param string $id The cache store id.
* @param boolean $persistent Flag to enable the use of external cache. [optional]
*
* @return mixed The cached data if found, null otherwise.
*
* @since 2.5
*/
protected function retrieve($id, $persistent = true)
{
$data = null;
// Use the internal cache if possible.
if (isset($this->cache[$id]))
{
return $this->cache[$id];
}
// Use the external cache if data is persistent.
if ($persistent)
{
$data = JFactory::getCache($this->context, 'output')->get($id);
$data = $data ? unserialize($data) : null;
}
// Store the data in internal cache.
if ($data)
{
$this->cache[$id] = $data;
}
return $data;
}
/**
* Method to store data in cache.
*
* @param string $id The cache store id.
* @param mixed $data The data to cache.
* @param boolean $persistent Flag to enable the use of external cache. [optional]
*
* @return boolean True on success, false on failure.
*
* @since 2.5
*/
protected function store($id, $data, $persistent = true)
{
// Store the data in internal cache.
$this->cache[$id] = $data;
// Store the data in external cache if data is persistent.
if ($persistent)
{
return JFactory::getCache($this->context, 'output')->store(serialize($data), $id);
}
return true;
}
}
PK �0"]��� � controllers/suggestions.json.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Suggestions JSON controller for Finder.
*
* @since 2.5
*/
class FinderControllerSuggestions extends JControllerLegacy
{
/**
* Method to find search query suggestions. Uses jQuery and autocompleter.js
*
* @return void
*
* @since 3.4
*/
public function suggest()
{
/** @var \Joomla\CMS\Application\CMSApplication $app */
$app = JFactory::getApplication();
$app->mimeType = 'application/json';
// Ensure caching is disabled as it depends on the query param in the model
$app->allowCache(false);
$suggestions = $this->getSuggestions();
// Send the response.
$app->setHeader('Content-Type', $app->mimeType . '; charset=' . $app->charSet);
$app->sendHeaders();
echo '{ "suggestions": ' . json_encode($suggestions) . ' }';
$app->close();
}
/**
* Method to find search query suggestions. Uses Mootools and autocompleter.js
*
* @param boolean $cachable If true, the view output will be cached
* @param array $urlparams An array of safe URL parameters and their variable types, for valid values see {@link JFilterInput::clean()}.
*
* @return void
*
* @since 2.5
* @deprecated 3.4
*/
public function display($cachable = false, $urlparams = false)
{
/** @var \Joomla\CMS\Application\CMSApplication $app */
$app = JFactory::getApplication();
$app->mimeType = 'application/json';
// Ensure caching is disabled as it depends on the query param in the model
$app->allowCache(false);
$suggestions = $this->getSuggestions();
// Send the response.
$app->setHeader('Content-Type', $app->mimeType . '; charset=' . $app->charSet);
$app->sendHeaders();
echo json_encode($suggestions);
$app->close();
}
/**
* Method to retrieve the data from the database
*
* @return array The suggested words
*
* @since 3.4
*/
protected function getSuggestions()
{
$return = array();
$params = JComponentHelper::getParams('com_finder');
if ($params->get('show_autosuggest', 1))
{
// Get the suggestions.
$model = $this->getModel('Suggestions', 'FinderModel');
$return = $model->getItems();
}
// Check the data.
if (empty($return))
{
$return = array();
}
return $return;
}
}
PK �0"]�&hp p
router.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Routing class from com_finder
*
* @since 3.3
*/
class FinderRouter extends JComponentRouterBase
{
/**
* Build the route for the com_finder component
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent URL.
*
* @since 3.3
*/
public function build(&$query)
{
$segments = array();
/*
* First, handle menu item routes first. When the menu system builds a
* route, it only provides the option and the menu item id. We don't have
* to do anything to these routes.
*/
if (count($query) === 2 && isset($query['Itemid'], $query['option']))
{
return $segments;
}
/*
* Next, handle a route with a supplied menu item id. All system generated
* routes should fall into this group. We can assume that the menu item id
* is the best possible match for the query but we need to go through and
* see which variables we can eliminate from the route query string because
* they are present in the menu item route already.
*/
if (!empty($query['Itemid']))
{
// Get the menu item.
$item = $this->menu->getItem($query['Itemid']);
// Check if the view matches.
if ($item && isset($item->query['view']) && isset($query['view']) && $item->query['view'] === $query['view'])
{
unset($query['view']);
}
// Check if the search query filter matches.
if ($item && isset($item->query['f']) && isset($query['f']) && $item->query['f'] === $query['f'])
{
unset($query['f']);
}
// Check if the search query string matches.
if ($item && isset($item->query['q']) && isset($query['q']) && $item->query['q'] === $query['q'])
{
unset($query['q']);
}
return $segments;
}
/*
* Lastly, handle a route with no menu item id. Fortunately, we only need
* to deal with the view as the other route variables are supposed to stay
* in the query string.
*/
if (isset($query['view']))
{
// Add the view to the segments.
$segments[] = $query['view'];
unset($query['view']);
}
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = str_replace(':', '-', $segments[$i]);
}
return $segments;
}
/**
* Parse the segments of a URL.
*
* @param array &$segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @since 3.3
*/
public function parse(&$segments)
{
$total = count($segments);
$vars = array();
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = preg_replace('/-/', ':', $segments[$i], 1);
}
// Check if the view segment is set and it equals search or advanced.
if (isset($segments[0]) && ($segments[0] === 'search' || $segments[0] === 'advanced'))
{
$vars['view'] = $segments[0];
}
return $vars;
}
}
/**
* Finder router functions
*
* These functions are proxys for the new router interface
* for old SEF extensions.
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent URL.
*
* @deprecated 4.0 Use Class based routers instead
*/
function FinderBuildRoute(&$query)
{
$router = new FinderRouter;
return $router->build($query);
}
/**
* Finder router functions
*
* These functions are proxys for the new router interface
* for old SEF extensions.
*
* @param array $segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @deprecated 4.0 Use Class based routers instead
*/
function FinderParseRoute($segments)
{
$router = new FinderRouter;
return $router->parse($segments);
}
PK �0"]g)4�" " views/search/tmpl/default.xmlnu &1i� <?xml version="1.0" encoding="utf-8"?>
<metadata>
<layout title="COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TITLE">
<help
key = "JHELP_MENUS_MENU_ITEM_FINDER_SEARCH"
/>
<message>
<![CDATA[COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TEXT]]>
</message>
</layout>
<fields name="request" addfieldpath="/administrator/components/com_finder/models/fields">
<fieldset name="request">
<field
name="q"
type="text"
label="COM_FINDER_SEARCH_SEARCH_QUERY_LABEL"
description="COM_FINDER_SEARCH_SEARCH_QUERY_DESC"
size="30"
/>
<field
name="f"
type="searchfilter"
label="COM_FINDER_SEARCH_FILTER_SEARCH_LABEL"
description="COM_FINDER_SEARCH_FILTER_SEARCH_DESC"
default=""
/>
</fieldset>
</fields>
<fields name="params" addfieldpath="/administrator/components/com_finder/models/fields">
<fieldset name="basic">
<field
name="show_date_filters"
type="list"
label="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_LABEL"
description="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="show_advanced"
type="list"
label="COM_FINDER_CONFIG_SHOW_ADVANCED_LABEL"
description="COM_FINDER_CONFIG_SHOW_ADVANCED_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="expand_advanced"
type="list"
label="COM_FINDER_CONFIG_EXPAND_ADVANCED_LABEL"
description="COM_FINDER_CONFIG_EXPAND_ADVANCED_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field type="spacer" />
<field
name="show_description"
type="list"
label="COM_FINDER_CONFIG_SHOW_DESCRIPTION_LABEL"
description="COM_FINDER_CONFIG_SHOW_DESCRIPTION_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="description_length"
type="number"
label="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_LABEL"
description="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_DESC"
default=""
size="5"
useglobal="true"
/>
<field
name="show_url"
type="list"
label="COM_FINDER_CONFIG_SHOW_URL_LABEL"
description="COM_FINDER_CONFIG_SHOW_URL_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field type="spacer" />
</fieldset>
<fieldset name="advanced">
<field
name="show_pagination_limit"
type="list"
label="JGLOBAL_DISPLAY_SELECT_LABEL"
description="JGLOBAL_DISPLAY_SELECT_DESC"
validate="options"
class="chzn-color"
>
<option value="">JGLOBAL_USE_GLOBAL</option>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="show_pagination"
type="list"
label="JGLOBAL_PAGINATION_LABEL"
description="JGLOBAL_PAGINATION_DESC"
validate="options"
class="chzn-color"
>
<option value="">JGLOBAL_USE_GLOBAL</option>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
<option value="2">JGLOBAL_AUTO</option>
</field>
<field
name="show_pagination_results"
type="list"
label="JGLOBAL_PAGINATION_RESULTS_LABEL"
description="JGLOBAL_PAGINATION_RESULTS_DESC"
validate="options"
class="chzn-color"
>
<option value="">JGLOBAL_USE_GLOBAL</option>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="allow_empty_query"
type="list"
label="COM_FINDER_ALLOW_EMPTY_QUERY_LABEL"
description="COM_FINDER_ALLOW_EMPTY_QUERY_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="show_suggested_query"
type="list"
label="COM_FINDER_CONFIG_SHOW_SUGGESTED_QUERY_LABEL"
description="COM_FINDER_CONFIG_SHOW_SUGGESTED_QUERY_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="show_explained_query"
type="list"
label="COM_FINDER_CONFIG_SHOW_EXPLAINED_QUERY_LABEL"
description="COM_FINDER_CONFIG_SHOW_EXPLAINED_QUERY_DESC"
default=""
useglobal="true"
class="chzn-color"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="sort_order"
type="list"
label="COM_FINDER_CONFIG_SORT_ORDER_LABEL"
description="COM_FINDER_CONFIG_SORT_ORDER_DESC"
default=""
useglobal="true"
>
<option value="relevance">COM_FINDER_CONFIG_SORT_OPTION_RELEVANCE</option>
<option value="date">COM_FINDER_CONFIG_SORT_OPTION_START_DATE</option>
<option value="price">COM_FINDER_CONFIG_SORT_OPTION_LIST_PRICE</option>
</field>
<field
name="sort_direction"
type="list"
label="COM_FINDER_CONFIG_SORT_DIRECTION_LABEL"
description="COM_FINDER_CONFIG_SORT_DIRECTION_DESC"
default=""
useglobal="true"
>
<option value="desc">COM_FINDER_CONFIG_SORT_OPTION_DESCENDING</option>
<option value="asc">COM_FINDER_CONFIG_SORT_OPTION_ASCENDING</option>
</field>
</fieldset>
<fieldset name="integration">
<field
name="show_feed_link"
type="list"
label="JGLOBAL_SHOW_FEED_LINK_LABEL"
description="JGLOBAL_SHOW_FEED_LINK_DESC"
validate="options"
class="chzn-color"
>
<option value="">JGLOBAL_USE_GLOBAL</option>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
</fieldset>
</fields>
</metadata>
PK �0"]�7� � views/search/tmpl/default.phpnu &1i� <?php
/**
* @package Joomla.Site
* @subpackage com_finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
JHtml::_('behavior.core');
JHtml::_('formbehavior.chosen');
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::_('stylesheet', 'com_finder/finder.css', array('version' => 'auto', 'relative' => true));
?>
<div class="finder<?php echo $this->pageclass_sfx; ?>">
<?php if ($this->params->get('show_page_heading')) : ?>
<h1>
<?php if ($this->escape($this->params->get('page_heading'))) : ?>
<?php echo $this->escape($this->params->get('page_heading')); ?>
<?php else : ?>
<?php echo $this->escape($this->params->get('page_title')); ?>
<?php endif; ?>
</h1>
<?php endif; ?>
<?php if ($this->params->get('show_search_form', 1)) : ?>
<div id="search-form">
<?php echo $this->loadTemplate('form'); ?>
</div>
<?php endif; ?>
<?php // Load the search results layout if we are performing a search. ?>
<?php if ($this->query->search === true) : ?>
<div id="search-results">
<?php echo $this->loadTemplate('results'); ?>
</div>
<?php endif; ?>
</div>
PK �0"]���
�
"