first commit

This commit is contained in:
alazhar
2020-01-02 22:20:31 +07:00
commit 10eb3340ad
5753 changed files with 631345 additions and 0 deletions

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<access component="com_finder">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" description="JACTION_ADMIN_COMPONENT_DESC" />
<action name="core.manage" title="JACTION_MANAGE" description="JACTION_MANAGE_COMPONENT_DESC" />
<action name="core.create" title="JACTION_CREATE" description="JACTION_CREATE_COMPONENT_DESC" />
<action name="core.delete" title="JACTION_DELETE" description="JACTION_DELETE_COMPONENT_DESC" />
<action name="core.edit" title="JACTION_EDIT" description="JACTION_EDIT_COMPONENT_DESC" />
<action name="core.edit.state" title="JACTION_EDITSTATE" description="JACTION_EDITSTATE_COMPONENT_DESC" />
</section>
</access>

View File

@ -0,0 +1,256 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<fieldset
name="search"
label="COM_FINDER_FIELDSET_SEARCH_OPTIONS_LABEL"
description="COM_FINDER_FIELDSET_SEARCH_OPTIONS_DESCRIPTION" >
<field
name="enabled"
type="radio"
class="btn-group"
default="0"
label="COM_FINDER_CONFIG_GATHER_SEARCH_STATISTICS_LABEL"
description="COM_FINDER_CONFIG_GATHER_SEARCH_STATISTICS_DESCRIPTION">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="show_description"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_SHOW_DESCRIPTION_LABEL"
description="COM_FINDER_CONFIG_SHOW_DESCRIPTION_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="description_length"
type="text"
size="5"
default="255"
filter="integer"
label="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_LABEL"
description="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_DESCRIPTION" />
<field name="allow_empty_query"
type="radio"
class="btn-group"
default="0"
label="COM_FINDER_CONFIG_ALLOW_EMPTY_QUERY_LABEL"
description="COM_FINDER_CONFIG_ALLOW_EMPTY_QUERY_DESCRIPTION">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="show_url"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_SHOW_URL_LABEL"
description="COM_FINDER_CONFIG_SHOW_URL_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="show_autosuggest"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_SHOW_AUTOSUGGEST_LABEL"
description="COM_FINDER_CONFIG_SHOW_AUTOSUGGEST_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="show_advanced"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_SHOW_ADVANCED_LABEL"
description="COM_FINDER_CONFIG_SHOW_ADVANCED_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field name="show_advanced_tips"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_SHOW_ADVANCED_TIPS_LABEL"
description="COM_FINDER_CONFIG_SHOW_ADVANCED_TIPS_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="expand_advanced"
type="radio"
class="btn-group"
default="0"
label="COM_FINDER_CONFIG_EXPAND_ADVANCED_LABEL"
description="COM_FINDER_CONFIG_EXPAND_ADVANCED_DESCRIPTION">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="show_date_filters"
type="radio"
class="btn-group"
default="0"
label="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_LABEL"
description="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_DESCRIPTION">
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field name="sort_order"
type="list"
default="relevance"
validate="options"
label="COM_FINDER_CONFIG_SORT_ORDER_LABEL"
description="COM_FINDER_CONFIG_SORT_ORDER_DESC">
<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"
default="desc"
validate="options"
label="COM_FINDER_CONFIG_SORT_DIRECTION_LABEL"
description="COM_FINDER_CONFIG_SORT_DIRECTION_DESC">
<option value="desc">COM_FINDER_CONFIG_SORT_OPTION_DESCENDING</option>
<option value="asc">COM_FINDER_CONFIG_SORT_OPTION_ASCENDING</option>
</field>
<field
name="highlight_terms"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_HILIGHT_CONTENT_SEARCH_TERMS_LABEL"
description="COM_FINDER_CONFIG_HILIGHT_CONTENT_SEARCH_TERMS_DESCRIPTION">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="opensearch_name"
type="text"
label="COM_FINDER_CONFIG_FIELD_OPENSEARCH_NAME_LABEL"
description="COM_FINDER_CONFIG_FIELD_OPENSEARCH_NAME_DESCRIPTION"
/>
<field
name="opensearch_description"
type="textarea"
label="COM_FINDER_CONFIG_FIELD_OPENSEARCH_DESCRIPTON_LABEL"
description="COM_FINDER_CONFIG_FIELD_OPENSEARCH_DESCRIPTON_DESCRIPTION"
cols="30" rows="2"
/>
</fieldset>
<fieldset
name="index"
label="COM_FINDER_FIELDSET_INDEX_OPTIONS_LABEL"
description="COM_FINDER_FIELDSET_INDEX_OPTIONS_DESCRIPTION" >
<field
name="batch_size"
type="list"
default="50"
label="COM_FINDER_CONFIG_BATCH_SIZE_LABEL"
description="COM_FINDER_CONFIG_BATCH_SIZE_DESCRIPTION"
validate="options" >
<option value="5">J5</option>
<option value="10">J10</option>
<option value="25">J25</option>
<option value="50">J50</option>
<option value="75">J75</option>
<option value="100">J100</option>
<option value="150">J150</option>
<option value="200">J200</option>
<option value="250">J250</option>
<option value="300">J300</option>
</field>
<field
name="memory_table_limit"
type="text"
size="10"
default="30000"
label="COM_FINDER_CONFIG_MEMORY_TABLE_LIMIT_LABEL"
description="COM_FINDER_CONFIG_MEMORY_TABLE_LIMIT_DESCRIPTION"
filter="integer" />
<field
name="title_multiplier"
type="text"
size="5"
default="1.7"
label="COM_FINDER_CONFIG_TITLE_MULTIPLIER_LABEL"
description="COM_FINDER_CONFIG_TITLE_MULTIPLIER_DESCRIPTION" />
<field
name="text_multiplier"
type="text"
size="5"
default="0.7"
label="COM_FINDER_CONFIG_TEXT_MULTIPLIER_LABEL"
description="COM_FINDER_CONFIG_TEXT_MULTIPLIER_DESCRIPTION" />
<field
name="meta_multiplier"
type="text"
size="5"
default="1.2"
label="COM_FINDER_CONFIG_META_MULTIPLIER_LABEL"
description="COM_FINDER_CONFIG_META_MULTIPLIER_DESCRIPTION" />
<field
name="path_multiplier"
type="text"
size="5"
default="2.0"
label="COM_FINDER_CONFIG_PATH_MULTIPLIER_LABEL"
description="COM_FINDER_CONFIG_PATH_MULTIPLIER_DESCRIPTION" />
<field
name="misc_multiplier"
type="text"
size="5"
default="0.3"
label="COM_FINDER_CONFIG_MISC_MULTIPLIER_LABEL"
description="COM_FINDER_CONFIG_MISC_MULTIPLIER_DESCRIPTION" />
<field
name="stem"
type="radio"
class="btn-group"
default="1"
label="COM_FINDER_CONFIG_STEMMER_ENABLE_LABEL"
description="COM_FINDER_CONFIG_STEMMER_ENABLE_DESCRIPTION" >
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="stemmer"
type="list"
default="snowball"
label="COM_FINDER_CONFIG_STEMMER_LABEL"
description="COM_FINDER_CONFIG_STEMMER_DESCRIPTION" >
<option value="porter_en">COM_FINDER_CONFIG_STEMMER_PORTER_EN</option>
<option value="fr">COM_FINDER_CONFIG_STEMMER_FR</option>
<option value="snowball">COM_FINDER_CONFIG_STEMMER_SNOWBALL</option>
</field>
<field
name="enable_logging"
type="radio"
class="btn-group"
default="0"
label="COM_FINDER_CONFIG_ENABLE_LOGGING_LABEL"
description="COM_FINDER_CONFIG_ENABLE_LOGGING_DESCRIPTION">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
</fieldset>
<fieldset
name="permissions"
label="JCONFIG_PERMISSIONS_LABEL"
description="JCONFIG_PERMISSIONS_DESC" >
<field
name="rules"
type="rules"
label="JCONFIG_PERMISSIONS_LABEL"
class="inputbox"
filter="rules"
validate="rules"
component="com_finder"
section="component" />
</fieldset>
</config>

View File

@ -0,0 +1,60 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Base controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderController extends JControllerLegacy
{
/**
* @var string The default view.
* @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 JController A JController object to support chaining.
*
* @since 2.5
*/
public function display($cachable = false, $urlparams = array())
{
include_once JPATH_COMPONENT . '/helpers/finder.php';
$view = $this->input->get('view', 'index', 'word');
$layout = $this->input->get('layout', 'index', 'word');
$f_id = $this->input->get('filter_id', null, 'int');
// Check for edit form.
if ($view == 'filter' && $layout == 'edit' && !$this->checkEditId('com_finder.edit.filter', $f_id))
{
// Somehow the person just went to the form - we don't allow that.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $f_id));
$this->setMessage($this->getError(), 'error');
$this->setRedirect(JRoute::_('index.php?option=com_finder&view=filters', false));
return false;
}
parent::display();
return $this;
}
}

View File

@ -0,0 +1,241 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Indexer controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderControllerFilter extends JControllerForm
{
/**
* Method to save a record.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
*
* @return boolean True if successful, false otherwise.
*
* @since 2.5
*/
public function save($key = null, $urlVar = null)
{
// Check for request forgeries.
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
$app = JFactory::getApplication();
$input = $app->input;
$lang = JFactory::getLanguage();
$model = $this->getModel();
$table = $model->getTable();
$data = $input->post->get('jform', array(), 'array');
$checkin = property_exists($table, 'checked_out');
$context = "$this->option.edit.$this->context";
$task = $this->getTask();
// Determine the name of the primary key for the data.
if (empty($key))
{
$key = $table->getKeyName();
}
// To avoid data collisions the urlVar may be different from the primary key.
if (empty($urlVar))
{
$urlVar = $key;
}
$recordId = $input->get($urlVar, '', 'int');
if (!$this->checkEditId($context, $recordId))
{
// Somehow the person just went to the form and tried to save it. We don't allow that.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId));
$this->setMessage($this->getError(), 'error');
$this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false));
return false;
}
// Populate the row id from the session.
$data[$key] = $recordId;
// The save2copy task needs to be handled slightly differently.
if ($task == 'save2copy')
{
// Check-in the original row.
if ($checkin && $model->checkin($data[$key]) === false)
{
// Check-in failed. Go back to the item and display a notice.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
$this->setMessage($this->getError(), 'error');
$this->setRedirect('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $urlVar));
return false;
}
// Reset the ID and then treat the request as for Apply.
$data[$key] = 0;
$task = 'apply';
}
// Access check.
if (!$this->allowSave($data, $key))
{
$this->setError(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
$this->setMessage($this->getError(), 'error');
$this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false));
return false;
}
// Validate the posted data.
// Sometimes the form needs some posted data, such as for plugins and modules.
$form = $model->getForm($data, false);
if (!$form)
{
$app->enqueueMessage($model->getError(), 'error');
return false;
}
// Test whether the data is valid.
$validData = $model->validate($form, $data);
// Check for validation errors.
if ($validData === false)
{
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++)
{
if (($errors[$i]) instanceof Exception)
{
$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
}
else
{
$app->enqueueMessage($errors[$i], 'warning');
}
}
// Save the data in the session.
$app->setUserState($context . '.data', $data);
// Redirect back to the edit screen.
$this->setRedirect(
JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false)
);
return false;
}
// Get and sanitize the filter data.
$validData['data'] = $input->post->get('t', array(), 'array');
$validData['data'] = array_unique($validData['data']);
JArrayHelper::toInteger($validData['data']);
// Remove any values of zero.
if (array_search(0, $validData['data'], true))
{
unset($validData['data'][array_search(0, $validData['data'], true)]);
}
// Attempt to save the data.
if (!$model->save($validData))
{
// Save the data in the session.
$app->setUserState($context . '.data', $validData);
// Redirect back to the edit screen.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
$this->setMessage($this->getError(), 'error');
$this->setRedirect(
JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false)
);
return false;
}
// Save succeeded, so check-in the record.
if ($checkin && $model->checkin($validData[$key]) === false)
{
// Save the data in the session.
$app->setUserState($context . '.data', $validData);
// Check-in failed, so go back to the record and display a notice.
$this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
$this->setMessage($this->getError(), 'error');
$this->setRedirect('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key));
return false;
}
$this->setMessage(
JText::_(
($lang->hasKey($this->text_prefix . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS')
? $this->text_prefix : 'JLIB_APPLICATION') . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS'
)
);
// Redirect the user and adjust session state based on the chosen task.
switch ($task)
{
case 'apply':
// Set the record data in the session.
$recordId = $model->getState($this->context . '.id');
$this->holdEditId($context, $recordId);
$app->setUserState($context . '.data', null);
$model->checkout($recordId);
// Redirect back to the edit screen.
$this->setRedirect(
JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false)
);
break;
case 'save2new':
// Clear the record id and data from the session.
$this->releaseEditId($context, $recordId);
$app->setUserState($context . '.data', null);
// Redirect back to the edit screen.
$this->setRedirect(
JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend(null, $key), false)
);
break;
default:
// Clear the record id and data from the session.
$this->releaseEditId($context, $recordId);
$app->setUserState($context . '.data', null);
// Redirect to the list screen.
$this->setRedirect(
JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false)
);
break;
}
// Invoke the postSave method to allow for the child class to access the model.
$this->postSaveHook($model, $validData);
return true;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filters controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderControllerFilters extends JControllerAdmin
{
/**
* Method to get a model object, loading it if required.
*
* @param string $name The model name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $config Configuration array for model. Optional.
*
* @return object The model.
*
* @since 2.5
*/
public function getModel($name = 'Filter', $prefix = 'FinderModel', $config = array('ignore_request' => true))
{
$model = parent::getModel($name, $prefix, $config);
return $model;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,70 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Index controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderControllerIndex extends JControllerAdmin
{
/**
* Method to get a model object, loading it if required.
*
* @param string $name The model name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $config Configuration array for model. Optional.
*
* @return object The model.
*
* @since 2.5
*/
public function getModel($name = 'Index', $prefix = 'FinderModel', $config = array('ignore_request' => true))
{
$model = parent::getModel($name, $prefix, $config);
return $model;
}
/**
* Method to purge all indexed links from the database.
*
* @return boolean True on success.
*
* @since 2.5
*/
public function purge()
{
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// Remove the script time limit.
@set_time_limit(0);
$model = $this->getModel('Index', 'FinderModel');
// Attempt to purge the index.
$return = $model->purge();
if (!$return)
{
$message = JText::_('COM_FINDER_INDEX_PURGE_FAILED', $model->getError());
$this->setRedirect('index.php?option=com_finder&view=index', $message);
return false;
}
else
{
$message = JText::_('COM_FINDER_INDEX_PURGE_SUCCESS');
$this->setRedirect('index.php?option=com_finder&view=index', $message);
return true;
}
}
}

View File

@ -0,0 +1,384 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
// Register dependent classes.
JLoader::register('FinderIndexer', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/indexer/indexer.php');
/**
* Indexer controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderControllerIndexer extends JControllerLegacy
{
/**
* Method to start the indexer.
*
* @return void
*
* @since 2.5
*/
public function start()
{
static $log;
$params = JComponentHelper::getParams('com_finder');
if ($params->get('enable_logging', '0'))
{
if ($log == null)
{
$options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}';
$options['text_file'] = 'indexer.php';
$log = JLog::addLogger($options);
}
}
// Log the start
JLog::add('Starting the indexer', JLog::INFO);
// We don't want this form to be cached.
header('Pragma: no-cache');
header('Cache-Control: no-cache');
header('Expires: -1');
// Check for a valid token. If invalid, send a 403 with the error message.
JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403));
// Put in a buffer to silence noise.
ob_start();
// Reset the indexer state.
FinderIndexer::resetState();
// Import the finder plugins.
JPluginHelper::importPlugin('finder');
// Add the indexer language to JS
JText::script('COM_FINDER_AN_ERROR_HAS_OCCURRED');
JText::script('COM_FINDER_NO_ERROR_RETURNED');
// Start the indexer.
try
{
// Trigger the onStartIndex event.
JEventDispatcher::getInstance()->trigger('onStartIndex');
// Get the indexer state.
$state = FinderIndexer::getState();
$state->start = 1;
// Send the response.
$this->sendResponse($state);
}
// Catch an exception and return the response.
catch (Exception $e)
{
$this->sendResponse($e);
}
}
/**
* Method to run the next batch of content through the indexer.
*
* @return void
*
* @since 2.5
*/
public function batch()
{
static $log;
$params = JComponentHelper::getParams('com_finder');
if ($params->get('enable_logging', '0'))
{
if ($log == null)
{
$options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}';
$options['text_file'] = 'indexer.php';
$log = JLog::addLogger($options);
}
}
// Log the start
JLog::add('Starting the indexer batch process', JLog::INFO);
// We don't want this form to be cached.
header('Pragma: no-cache');
header('Cache-Control: no-cache');
header('Expires: -1');
// Check for a valid token. If invalid, send a 403 with the error message.
JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403));
// Put in a buffer to silence noise.
ob_start();
// Remove the script time limit.
@set_time_limit(0);
// Get the indexer state.
$state = FinderIndexer::getState();
// Reset the batch offset.
$state->batchOffset = 0;
// Update the indexer state.
FinderIndexer::setState($state);
// Import the finder plugins.
JPluginHelper::importPlugin('finder');
/*
* We are going to swap out the raw document object with an HTML document
* in order to work around some plugins that don't do proper environment
* checks before trying to use HTML document functions.
*/
$raw = clone(JFactory::getDocument());
$lang = JFactory::getLanguage();
// Get the document properties.
$attributes = array (
'charset' => 'utf-8',
'lineend' => 'unix',
'tab' => ' ',
'language' => $lang->getTag(),
'direction' => $lang->isRTL() ? 'rtl' : 'ltr'
);
// Get the HTML document.
$html = JDocument::getInstance('html', $attributes);
$doc = JFactory::getDocument();
// Swap the documents.
$doc = $html;
// Get the admin application.
$admin = clone(JFactory::getApplication());
// Get the site app.
include_once JPATH_SITE . '/includes/application.php';
$site = JApplication::getInstance('site');
// Swap the app.
$app = JFactory::getApplication();
$app = $site;
// Start the indexer.
try
{
// Trigger the onBeforeIndex event.
JEventDispatcher::getInstance()->trigger('onBeforeIndex');
// Trigger the onBuildIndex event.
JEventDispatcher::getInstance()->trigger('onBuildIndex');
// Get the indexer state.
$state = FinderIndexer::getState();
$state->start = 0;
$state->complete = 0;
// Swap the documents back.
$doc = $raw;
// Swap the applications back.
$app = $admin;
// Send the response.
$this->sendResponse($state);
}
// Catch an exception and return the response.
catch (Exception $e)
{
// Swap the documents back.
$doc = $raw;
// Send the response.
$this->sendResponse($e);
}
}
/**
* Method to optimize the index and perform any necessary cleanup.
*
* @return void
*
* @since 2.5
*/
public function optimize()
{
// We don't want this form to be cached.
header('Pragma: no-cache');
header('Cache-Control: no-cache');
header('Expires: -1');
// Check for a valid token. If invalid, send a 403 with the error message.
JSession::checkToken('request') or $this->sendResponse(new Exception(JText::_('JINVALID_TOKEN'), 403));
// Put in a buffer to silence noise.
ob_start();
// Import the finder plugins.
JPluginHelper::importPlugin('finder');
try
{
// Optimize the index
FinderIndexer::getInstance()->optimize();
// Get the indexer state.
$state = FinderIndexer::getState();
$state->start = 0;
$state->complete = 1;
// Send the response.
$this->sendResponse($state);
}
// Catch an exception and return the response.
catch (Exception $e)
{
$this->sendResponse($e);
}
}
/**
* Method to handle a send a JSON response. The body parameter
* can be a Exception object for when an error has occurred or
* a JObject for a good response.
*
* @param mixed $data JObject on success, Exception on error. [optional]
*
* @return void
*
* @since 2.5
*/
public static function sendResponse($data = null)
{
static $log;
$params = JComponentHelper::getParams('com_finder');
if ($params->get('enable_logging', '0'))
{
if ($log == null)
{
$options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}';
$options['text_file'] = 'indexer.php';
$log = JLog::addLogger($options);
}
}
// Send the assigned error code if we are catching an exception.
if ($data instanceof Exception)
{
JLog::add($data->getMessage(), JLog::ERROR);
JResponse::setHeader('status', $data->getCode());
JResponse::sendHeaders();
}
// Create the response object.
$response = new FinderIndexerResponse($data);
// Add the buffer.
$response->buffer = JDEBUG ? ob_get_contents() : ob_end_clean();
// Send the JSON response.
echo json_encode($response);
// Close the application.
JFactory::getApplication()->close();
}
}
/**
* Finder Indexer JSON Response Class
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerResponse
{
/**
* Class Constructor
*
* @param mixed $state The processing state for the indexer
*
* @since 2.5
*/
public function __construct($state)
{
static $log;
$params = JComponentHelper::getParams('com_finder');
if ($params->get('enable_logging', '0'))
{
if ($log == null)
{
$options['format'] = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}';
$options['text_file'] = 'indexer.php';
$log = JLog::addLogger($options);
}
}
// The old token is invalid so send a new one.
$this->token = JFactory::getSession()->getFormToken();
// Check if we are dealing with an error.
if ($state instanceof Exception)
{
// Log the error
JLog::add($state->getMessage(), JLog::ERROR);
// Prepare the error response.
$this->error = true;
$this->header = JText::_('COM_FINDER_INDEXER_HEADER_ERROR');
$this->message = $state->getMessage();
}
else
{
// Prepare the response data.
$this->batchSize = (int) $state->batchSize;
$this->batchOffset = (int) $state->batchOffset;
$this->totalItems = (int) $state->totalItems;
$this->startTime = $state->startTime;
$this->endTime = JFactory::getDate()->toSQL();
$this->start = !empty($state->start) ? (int) $state->start : 0;
$this->complete = !empty($state->complete) ? (int) $state->complete : 0;
// Set the appropriate messages.
if ($this->totalItems <= 0 && $this->complete)
{
$this->header = JText::_('COM_FINDER_INDEXER_HEADER_COMPLETE');
$this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_COMPLETE');
}
elseif ($this->totalItems <= 0)
{
$this->header = JText::_('COM_FINDER_INDEXER_HEADER_OPTIMIZE');
$this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_OPTIMIZE');
}
else
{
$this->header = JText::_('COM_FINDER_INDEXER_HEADER_RUNNING');
$this->message = JText::_('COM_FINDER_INDEXER_MESSAGE_RUNNING');
}
}
}
}
// Register the error handler.
JError::setErrorHandling(E_ALL, 'callback', array('FinderControllerIndexer', 'sendResponse'));

View File

@ -0,0 +1,37 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Maps controller class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderControllerMaps extends JControllerAdmin
{
/**
* Method to get a model object, loading it if required.
*
* @param string $name The model name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $config Configuration array for model. Optional.
*
* @return object The model.
*
* @since 1.6
*/
public function getModel($name = 'Maps', $prefix = 'FinderModel', $config = array('ignore_request' => true))
{
$model = parent::getModel($name, $prefix, $config);
return $model;
}
}

View File

@ -0,0 +1,19 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
if (!JFactory::getUser()->authorise('core.manage', 'com_finder'))
{
return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
}
$controller = JControllerLegacy::getInstance('Finder');
$controller->execute(JFactory::getApplication()->input->get('task'));
$controller->redirect();

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.1" method="upgrade">
<name>com_finder</name>
<author>Joomla! Project</author>
<copyright>(C) 2005 - 2013 Open Source Matters. All rights reserved.</copyright>
<creationDate>August 2011</creationDate>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>COM_FINDER_XML_DESCRIPTION</description>
<menu link="option=com_finder">COM_FINDER</menu>
<files folder="site">
<filename>controller.php</filename>
<filename>index.html</filename>
<filename>finder.php</filename>
<filename>router.php</filename>
<folder>controllers</folder>
<folder>helpers</folder>
<folder>models</folder>
<folder>views</folder>
</files>
<media destination="com_finder" folder="media">
<folder>js</folder>
<folder>images</folder>
<folder>css</folder>
<filename>index.html</filename>
</media>
<install>
<sql>
<file charset="utf8" driver="mysql">sql/install.mysql.sql</file>
<file charset="utf8" driver="postgresql">sql/install.postgresql.sql</file>
</sql>
</install>
<uninstall>
<sql>
<file charset="utf8" driver="mysql">sql/uninstall.mysql.sql</file>
<file charset="utf8" driver="postgresql">sql/uninstall.postgresql.sql</file>
</sql>
</uninstall>
<languages folder="site">
<language tag="en-GB">language/en-GB.com_finder.ini</language>
</languages>
<administration>
<files folder="admin">
<filename>access.xml</filename>
<filename>config.xml</filename>
<filename>controller.php</filename>
<filename>finder.php</filename>
<filename>index.html</filename>
<folder>controllers</folder>
<folder>helpers</folder>
<folder>models</folder>
<folder>sql</folder>
<folder>tables</folder>
<folder>views</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB.com_finder.ini</language>
<language tag="en-GB">language/en-GB.com_finder.sys.ini</language>
</languages>
<menu img="class:finder" link="option=com_finder">COM_FINDER</menu>
</administration>
</extension>

View File

@ -0,0 +1,77 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Helper class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderHelper
{
/**
* @var string The extension name.
* @since 2.5
*/
public static $extension = 'com_finder';
/**
* Configure the Linkbar.
*
* @param string $vName The name of the active view.
*
* @return void
*
* @since 2.5
*/
public static function addSubmenu($vName)
{
JHtmlSidebar::addEntry(
JText::_('COM_FINDER_SUBMENU_INDEX'),
'index.php?option=com_finder&view=index',
$vName == 'index'
);
JHtmlSidebar::addEntry(
JText::_('COM_FINDER_SUBMENU_MAPS'),
'index.php?option=com_finder&view=maps',
$vName == 'maps'
);
JHtmlSidebar::addEntry(
JText::_('COM_FINDER_SUBMENU_FILTERS'),
'index.php?option=com_finder&view=filters',
$vName == 'filters'
);
}
/**
* Gets a list of the actions that can be performed.
*
* @return JObject A JObject containing the allowed actions.
*
* @since 2.5
*/
public static function getActions()
{
$user = JFactory::getUser();
$result = new JObject;
$assetName = 'com_finder';
$actions = JAccess::getActions($assetName, 'component');
foreach ($actions as $action)
{
$result->set($action->name, $user->authorise($action->name, $assetName));
}
return $result;
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/language.php');
/**
* HTML behavior class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
abstract class JHtmlFinder
{
/**
* Creates a list of types to filter on.
*
* @return array An array containing the types that can be selected.
*
* @since 2.5
*/
public static function typeslist()
{
$lang = JFactory::getLanguage();
// Load the finder types.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('DISTINCT t.title AS text, t.id AS value')
->from($db->quoteName('#__finder_types') . ' AS t')
->join('LEFT', $db->quoteName('#__finder_links') . ' AS l ON l.type_id = t.id')
->order('t.title ASC');
$db->setQuery($query);
try
{
$rows = $db->loadObjectList();
}
catch (RuntimeException $e)
{
return;
}
// Compile the options.
$options = array();
foreach ($rows as $row)
{
$key = $lang->hasKey(FinderHelperLanguage::branchPlural($row->text))
? FinderHelperLanguage::branchPlural($row->text) : $row->text;
$string = JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_($key));
$options[] = JHtml::_('select.option', $row->value, $string);
}
return $options;
}
/**
* Creates a list of maps.
*
* @return array An array containing the maps that can be selected.
*
* @since 2.5
*/
public static function mapslist()
{
$lang = JFactory::getLanguage();
// Load the finder types.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('title AS text, id AS value')
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' = 1')
->order('ordering, title ASC');
$db->setQuery($query);
try
{
$rows = $db->loadObjectList();
}
catch (RuntimeException $e)
{
return;
}
// Compile the options.
$options = array();
$options[] = JHtml::_('select.option', '1', JText::_('COM_FINDER_MAPS_BRANCHES'));
foreach ($rows as $row)
{
$key = $lang->hasKey(FinderHelperLanguage::branchPlural($row->text))
? FinderHelperLanguage::branchPlural($row->text) : $row->text;
$string = JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_($key));
$options[] = JHtml::_('select.option', $row->value, $string);
}
return $options;
}
/**
* Creates a list of published states.
*
* @return array An array containing the states that can be selected.
*
* @since 2.5
*/
public static function statelist()
{
$options = array();
$options[] = JHtml::_('select.option', '1', JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_('JPUBLISHED')));
$options[] = JHtml::_('select.option', '0', JText::sprintf('COM_FINDER_ITEM_X_ONLY', JText::_('JUNPUBLISHED')));
return $options;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,930 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexer', __DIR__ . '/indexer.php');
JLoader::register('FinderIndexerHelper', __DIR__ . '/helper.php');
JLoader::register('FinderIndexerResult', __DIR__ . '/result.php');
JLoader::register('FinderIndexerTaxonomy', __DIR__ . '/taxonomy.php');
/**
* Prototype adapter class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
abstract class FinderIndexerAdapter extends JPlugin
{
/**
* The context is somewhat arbitrary but it must be unique or there will be
* conflicts when managing plugin/indexer state. A good best practice is to
* use the plugin name suffix as the context. For example, if the plugin is
* named 'plgFinderContent', the context could be 'Content'.
*
* @var string
* @since 2.5
*/
protected $context;
/**
* The extension name.
*
* @var string
* @since 2.5
*/
protected $extension;
/**
* The sublayout to use when rendering the results.
*
* @var string
* @since 2.5
*/
protected $layout;
/**
* The mime type of the content the adapter indexes.
*
* @var string
* @since 2.5
*/
protected $mime;
/**
* The access level of an item before save.
*
* @var integer
* @since 2.5
*/
protected $old_access;
/**
* The access level of a category before save.
*
* @var integer
* @since 2.5
*/
protected $old_cataccess;
/**
* The type of content the adapter indexes.
*
* @var string
* @since 2.5
*/
protected $type_title;
/**
* The type id of the content.
*
* @var integer
* @since 2.5
*/
protected $type_id;
/**
* The database object.
*
* @var object
* @since 2.5
*/
protected $db;
/**
* The table name.
*
* @var string
* @since 2.5
*/
protected $table;
/**
* The indexer object.
*
* @var FinderIndexer
* @since 3.0
*/
protected $indexer;
/**
* The field the published state is stored in.
*
* @var string
* @since 2.5
*/
protected $state_field = 'state';
/**
* Method to instantiate the indexer adapter.
*
* @param object &$subject The object to observe.
* @param array $config An array that holds the plugin configuration.
*
* @since 2.5
*/
public function __construct(&$subject, $config)
{
// Get the database object.
$this->db = JFactory::getDbo();
// Call the parent constructor.
parent::__construct($subject, $config);
// Get the type id.
$this->type_id = $this->getTypeId();
// Add the content type if it doesn't exist and is set.
if (empty($this->type_id) && !empty($this->type_title))
{
$this->type_id = FinderIndexerHelper::addContentType($this->type_title, $this->mime);
}
// Check for a layout override.
if ($this->params->get('layout'))
{
$this->layout = $this->params->get('layout');
}
// Get the indexer object
$this->indexer = FinderIndexer::getInstance();
}
/**
* Method to get the adapter state and push it into the indexer.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on error.
*/
public function onStartIndex()
{
// Get the indexer state.
$iState = FinderIndexer::getState();
// Get the number of content items.
$total = (int) $this->getContentCount();
// Add the content count to the total number of items.
$iState->totalItems += $total;
// Populate the indexer state information for the adapter.
$iState->pluginState[$this->context]['total'] = $total;
$iState->pluginState[$this->context]['offset'] = 0;
// Set the indexer state.
FinderIndexer::setState($iState);
}
/**
* Method to prepare for the indexer to be run. This method will often
* be used to include dependencies and things of that nature.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on error.
*/
public function onBeforeIndex()
{
// Get the indexer and adapter state.
$iState = FinderIndexer::getState();
$aState = $iState->pluginState[$this->context];
// Check the progress of the indexer and the adapter.
if ($iState->batchOffset == $iState->batchSize || $aState['offset'] == $aState['total'])
{
return true;
}
// Run the setup method.
return $this->setup();
}
/**
* Method to index a batch of content items. This method can be called by
* the indexer many times throughout the indexing process depending on how
* much content is available for indexing. It is important to track the
* progress correctly so we can display it to the user.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on error.
*/
public function onBuildIndex()
{
// Get the indexer and adapter state.
$iState = FinderIndexer::getState();
$aState = $iState->pluginState[$this->context];
// Check the progress of the indexer and the adapter.
if ($iState->batchOffset == $iState->batchSize || $aState['offset'] == $aState['total'])
{
return true;
}
// Get the batch offset and size.
$offset = (int) $aState['offset'];
$limit = (int) ($iState->batchSize - $iState->batchOffset);
// Get the content items to index.
$items = $this->getItems($offset, $limit);
// Iterate through the items and index them.
for ($i = 0, $n = count($items); $i < $n; $i++)
{
// Index the item.
$this->index($items[$i]);
// Adjust the offsets.
$offset++;
$iState->batchOffset++;
$iState->totalItems--;
}
// Update the indexer state.
$aState['offset'] = $offset;
$iState->pluginState[$this->context] = $aState;
FinderIndexer::setState($iState);
return true;
}
/**
* Method to change the value of a content item's property in the links
* table. This is used to synchronize published and access states that
* are changed when not editing an item directly.
*
* @param string $id The ID of the item to change.
* @param string $property The property that is being changed.
* @param integer $value The new value of that property.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function change($id, $property, $value)
{
// Check for a property we know how to handle.
if ($property !== 'state' && $property !== 'access')
{
return true;
}
// Get the url for the content id.
$item = $this->db->quote($this->getUrl($id, $this->extension, $this->layout));
// Update the content items.
$query = $this->db->getQuery(true)
->update($this->db->quoteName('#__finder_links'))
->set($this->db->quoteName($property) . ' = ' . (int) $value)
->where($this->db->quoteName('url') . ' = ' . $item);
$this->db->setQuery($query);
$this->db->execute();
return true;
}
/**
* Method to index an item.
*
* @param FinderIndexerResult $item The item to index as a FinderIndexerResult object.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract protected function index(FinderIndexerResult $item);
/**
* Method to reindex an item.
*
* @param integer $id The ID of the item to reindex.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function reindex($id)
{
// Run the setup method.
$this->setup();
// Get the item.
$item = $this->getItem($id);
// Index the item.
$this->index($item);
}
/**
* Method to remove an item from the index.
*
* @param string $id The ID of the item to remove.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function remove($id)
{
// Get the item's URL
$url = $this->db->quote($this->getUrl($id, $this->extension, $this->layout));
// Get the link ids for the content items.
$query = $this->db->getQuery(true)
->select($this->db->quoteName('link_id'))
->from($this->db->quoteName('#__finder_links'))
->where($this->db->quoteName('url') . ' = ' . $url);
$this->db->setQuery($query);
$items = $this->db->loadColumn();
// Check the items.
if (empty($items))
{
return true;
}
// Remove the items.
foreach ($items as $item)
{
$this->indexer->remove($item);
}
return true;
}
/**
* Method to setup the adapter before indexing.
*
* @return boolean True on success, false on failure.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract protected function setup();
/**
* Method to update index data on category access level changes
*
* @param JTable $row A JTable object
*
* @return void
*
* @since 2.5
*/
protected function categoryAccessChange($row)
{
$query = clone($this->getStateQuery());
$query->where('c.id = ' . (int) $row->id);
// Get the access level.
$this->db->setQuery($query);
$items = $this->db->loadObjectList();
// Adjust the access level for each item within the category.
foreach ($items as $item)
{
// Set the access level.
$temp = max($item->access, $row->access);
// Update the item.
$this->change((int) $item->id, 'access', $temp);
// Reindex the item
$this->reindex($row->id);
}
}
/**
* Method to update index data on category access level changes
*
* @param array $pks A list of primary key ids of the content that has changed state.
* @param integer $value The value of the state that the content has been changed to.
*
* @return void
*
* @since 2.5
*/
protected function categoryStateChange($pks, $value)
{
/*
* The item's published state is tied to the category
* published state so we need to look up all published states
* before we change anything.
*/
foreach ($pks as $pk)
{
$query = clone($this->getStateQuery());
$query->where('c.id = ' . (int) $pk);
// Get the published states.
$this->db->setQuery($query);
$items = $this->db->loadObjectList();
// Adjust the state for each item within the category.
foreach ($items as $item)
{
// Translate the state.
$temp = $this->translateState($item->state, $value);
// Update the item.
$this->change($item->id, 'state', $temp);
// Reindex the item
$this->reindex($item->id);
}
}
}
/**
* Method to check the existing access level for categories
*
* @param JTable $row A JTable object
*
* @return void
*
* @since 2.5
*/
protected function checkCategoryAccess($row)
{
$query = $this->db->getQuery(true)
->select($this->db->quoteName('access'))
->from($this->db->quoteName('#__categories'))
->where($this->db->quoteName('id') . ' = ' . (int) $row->id);
$this->db->setQuery($query);
// Store the access level to determine if it changes
$this->old_cataccess = $this->db->loadResult();
}
/**
* Method to check the existing access level for items
*
* @param JTable $row A JTable object
*
* @return void
*
* @since 2.5
*/
protected function checkItemAccess($row)
{
$query = $this->db->getQuery(true)
->select($this->db->quoteName('access'))
->from($this->db->quoteName($this->table))
->where($this->db->quoteName('id') . ' = ' . (int) $row->id);
$this->db->setQuery($query);
// Store the access level to determine if it changes
$this->old_access = $this->db->loadResult();
}
/**
* Method to get the number of content items available to index.
*
* @return integer The number of content items available to index.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getContentCount()
{
$return = 0;
// Get the list query.
$query = $this->getListQuery();
// Check if the query is valid.
if (empty($query))
{
return $return;
}
// Tweak the SQL query to make the total lookup faster.
if ($query instanceof JDatabaseQuery)
{
$query = clone($query);
$query->clear('select')
->select('COUNT(*)')
->clear('order');
}
// Get the total number of content items to index.
$this->db->setQuery($query);
$return = (int) $this->db->loadResult();
return $return;
}
/**
* Method to get a content item to index.
*
* @param integer $id The id of the content item.
*
* @return FinderIndexerResult A FinderIndexerResult object.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getItem($id)
{
// Get the list query and add the extra WHERE clause.
$query = $this->getListQuery();
$query->where('a.id = ' . (int) $id);
// Get the item to index.
$this->db->setQuery($query);
$row = $this->db->loadAssoc();
// Convert the item to a result object.
$item = JArrayHelper::toObject($row, 'FinderIndexerResult');
// Set the item type.
$item->type_id = $this->type_id;
// Set the item layout.
$item->layout = $this->layout;
return $item;
}
/**
* Method to get a list of content items to index.
*
* @param integer $offset The list offset.
* @param integer $limit The list limit.
* @param JDatabaseQuery $query A JDatabaseQuery object. [optional]
*
* @return array An array of FinderIndexerResult objects.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getItems($offset, $limit, $query = null)
{
$items = array();
// Get the content items to index.
$this->db->setQuery($this->getListQuery($query), $offset, $limit);
$rows = $this->db->loadAssocList();
// Convert the items to result objects.
foreach ($rows as $row)
{
// Convert the item to a result object.
$item = JArrayHelper::toObject($row, 'FinderIndexerResult');
// Set the item type.
$item->type_id = $this->type_id;
// Set the mime type.
$item->mime = $this->mime;
// Set the item layout.
$item->layout = $this->layout;
// Set the extension if present
if (isset($row->extension))
{
$item->extension = $row->extension;
}
// Add the item to the stack.
$items[] = $item;
}
return $items;
}
/**
* Method to get the SQL query used to retrieve the list of content items.
*
* @param mixed $query A JDatabaseQuery object. [optional]
*
* @return JDatabaseQuery A database object.
*
* @since 2.5
*/
protected function getListQuery($query = null)
{
// Check if we can use the supplied SQL query.
$query = $query instanceof JDatabaseQuery ? $query : $this->db->getQuery(true);
return $query;
}
/**
* Method to get the plugin type
*
* @param integer $id The plugin ID
*
* @return string The plugin type
*
* @since 2.5
*/
protected function getPluginType($id)
{
// Prepare the query
$query = $this->db->getQuery(true)
->select($this->db->quoteName('element'))
->from($this->db->quoteName('#__extensions'))
->where($this->db->quoteName('extension_id') . ' = ' . (int) $id);
$this->db->setQuery($query);
$type = $this->db->loadResult();
return $type;
}
/**
* Method to get a SQL query to load the published and access states for
* an article and category.
*
* @return JDatabaseQuery A database object.
*
* @since 2.5
*/
protected function getStateQuery()
{
$query = $this->db->getQuery(true);
// Item ID
$query->select('a.id');
// Item and category published state
$query->select('a.' . $this->state_field . ' AS state, c.published AS cat_state');
// Item and category access levels
$query->select('a.access, c.access AS cat_access')
->from($this->table . ' AS a')
->join('LEFT', '#__categories AS c ON c.id = a.catid');
return $query;
}
/**
* Method to get the query clause for getting items to update by time.
*
* @param string $time The modified timestamp.
*
* @return JDatabaseQuery A database object.
*
* @since 2.5
*/
protected function getUpdateQueryByTime($time)
{
// Build an SQL query based on the modified time.
$query = $this->db->getQuery(true)
->where('a.modified >= ' . $this->db->quote($time));
return $query;
}
/**
* Method to get the query clause for getting items to update by id.
*
* @param array $ids The ids to load.
*
* @return JDatabaseQuery A database object.
*
* @since 2.5
*/
protected function getUpdateQueryByIds($ids)
{
// Build an SQL query based on the item ids.
$query = $this->db->getQuery(true)
->where('a.id IN(' . implode(',', $ids) . ')');
return $query;
}
/**
* Method to get the type id for the adapter content.
*
* @return integer The numeric type id for the content.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getTypeId()
{
// Get the type id from the database.
$query = $this->db->getQuery(true)
->select($this->db->quoteName('id'))
->from($this->db->quoteName('#__finder_types'))
->where($this->db->quoteName('title') . ' = ' . $this->db->quote($this->type_title));
$this->db->setQuery($query);
$result = (int) $this->db->loadResult();
return $result;
}
/**
* Method to get the URL for the item. The URL is how we look up the link
* in the Finder index.
*
* @param integer $id The id of the item.
* @param string $extension The extension the category is in.
* @param string $view The view for the URL.
*
* @return string The URL of the item.
*
* @since 2.5
*/
protected function getURL($id, $extension, $view)
{
return 'index.php?option=' . $extension . '&view=' . $view . '&id=' . $id;
}
/**
* Method to get the page title of any menu item that is linked to the
* content item, if it exists and is set.
*
* @param string $url The url of the item.
*
* @return mixed The title on success, null if not found.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function getItemMenuTitle($url)
{
$return = null;
// Set variables
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
// Build a query to get the menu params.
$query = $this->db->getQuery(true)
->select($this->db->quoteName('params'))
->from($this->db->quoteName('#__menu'))
->where($this->db->quoteName('link') . ' = ' . $this->db->quote($url))
->where($this->db->quoteName('published') . ' = 1')
->where($this->db->quoteName('access') . ' IN (' . $groups . ')');
// Get the menu params from the database.
$this->db->setQuery($query);
$params = $this->db->loadResult();
// Check the results.
if (empty($params))
{
return $return;
}
// Instantiate the params.
$params = json_decode($params);
// Get the page title if it is set.
if ($params->page_title)
{
$return = $params->page_title;
}
return $return;
}
/**
* Method to update index data on access level changes
*
* @param JTable $row A JTable object
*
* @return void
*
* @since 2.5
*/
protected function itemAccessChange($row)
{
$query = clone($this->getStateQuery());
$query->where('a.id = ' . (int) $row->id);
// Get the access level.
$this->db->setQuery($query);
$item = $this->db->loadObject();
// Set the access level.
$temp = max($row->access, $item->cat_access);
// Update the item.
$this->change((int) $row->id, 'access', $temp);
}
/**
* Method to update index data on published state changes
*
* @param array $pks A list of primary key ids of the content that has changed state.
* @param integer $value The value of the state that the content has been changed to.
*
* @return void
*
* @since 2.5
*/
protected function itemStateChange($pks, $value)
{
/*
* The item's published state is tied to the category
* published state so we need to look up all published states
* before we change anything.
*/
foreach ($pks as $pk)
{
$query = clone($this->getStateQuery());
$query->where('a.id = ' . (int) $pk);
// Get the published states.
$this->db->setQuery($query);
$item = $this->db->loadObject();
// Translate the state.
$temp = $this->translateState($value, $item->cat_state);
// Update the item.
$this->change($pk, 'state', $temp);
// Reindex the item
$this->reindex($pk);
}
}
/**
* Method to update index data when a plugin is disabled
*
* @param array $pks A list of primary key ids of the content that has changed state.
*
* @return void
*
* @since 2.5
*/
protected function pluginDisable($pks)
{
// Since multiple plugins may be disabled at a time, we need to check first
// that we're handling the appropriate one for the context
foreach ($pks as $pk)
{
if ($this->getPluginType($pk) == strtolower($this->context))
{
// Get all of the items to unindex them
$query = clone($this->getStateQuery());
$this->db->setQuery($query);
$items = $this->db->loadColumn();
// Remove each item
foreach ($items as $item)
{
$this->remove($item);
}
}
}
}
/**
* Method to translate the native content states into states that the
* indexer can use.
*
* @param integer $item The item state.
* @param integer $category The category state. [optional]
*
* @return integer The translated indexer state.
*
* @since 2.5
*/
protected function translateState($item, $category = null)
{
// If category is present, factor in its states as well
if ($category !== null)
{
if ($category == 0)
{
$item = 0;
}
}
// Translate the state
switch ($item)
{
// Published and archived items only should return a published state
case 1;
case 2:
return 1;
// All other states should return a unpublished state
default:
case 0:
return 0;
}
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,663 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
jimport('joomla.filesystem.file');
/**
* Indexer class supporting MySQL(i) for the Finder indexer package.
*
* The indexer class provides the core functionality of the Finder
* search engine. It is responsible for adding and updating the
* content links table; extracting and scoring tokens; and maintaining
* all referential information for the content.
*
* Note: All exceptions thrown from within this class should be caught
* by the controller.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 3.0
*/
class FinderIndexerDriverMysql extends FinderIndexer
{
/**
* Method to index a content item.
*
* @param FinderIndexerResult $item The content item to index.
* @param string $format The format of the content. [optional]
*
* @return integer The ID of the record in the links table.
*
* @since 3.0
* @throws Exception on database error.
*/
public function index($item, $format = 'html')
{
// Mark beforeIndexing in the profiler.
static::$profiler ? static::$profiler->mark('beforeIndexing') : null;
$db = JFactory::getDbo();
$nd = $db->getNullDate();
// Check if the item is in the database.
$query = $db->getQuery(true)
->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum'))
->from($db->quoteName('#__finder_links'))
->where($db->quoteName('url') . ' = ' . $db->quote($item->url));
// Load the item from the database.
$db->setQuery($query);
$link = $db->loadObject();
// Get the indexer state.
$state = static::getState();
// Get the signatures of the item.
$curSig = static::getSignature($item);
$oldSig = isset($link->md5sum) ? $link->md5sum : null;
// Get the other item information.
$linkId = empty($link->link_id) ? null : $link->link_id;
$isNew = empty($link->link_id) ? true : false;
// Check the signatures. If they match, the item is up to date.
if (!$isNew && $curSig == $oldSig)
{
return $linkId;
}
/*
* If the link already exists, flush all the term maps for the item.
* Maps are stored in 16 tables so we need to iterate through and flush
* each table one at a time.
*/
if (!$isNew)
{
for ($i = 0; $i <= 15; $i++)
{
// Flush the maps for the link.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
}
// Mark afterUnmapping in the profiler.
static::$profiler ? static::$profiler->mark('afterUnmapping') : null;
// Perform cleanup on the item data.
$item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd;
$item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd;
$item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd;
$item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd;
// Prepare the item description.
$item->description = FinderIndexerHelper::parse($item->summary);
/*
* Now, we need to enter the item into the links table. If the item
* already exists in the database, we need to use an UPDATE query.
* Otherwise, we need to use an INSERT to get the link id back.
*/
if ($isNew)
{
$columnsArray = array(
$db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'),
$db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'),
$db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'),
$db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'),
$db->quoteName('sale_price')
);
// Insert the link.
$query->clear()
->insert($db->quoteName('#__finder_links'))
->columns($columnsArray)
->values(
$db->quote($item->url) . ', '
. $db->quote($item->route) . ', '
. $db->quote($item->title) . ', '
. $db->quote($item->description) . ', '
. $query->currentTimestamp() . ', '
. '1, '
. (int) $item->state . ', '
. (int) $item->access . ', '
. $db->quote($item->language) . ', '
. (int) $item->type_id . ', '
. $db->quote(serialize($item)) . ', '
. $db->quote($item->publish_start_date) . ', '
. $db->quote($item->publish_end_date) . ', '
. $db->quote($item->start_date) . ', '
. $db->quote($item->end_date) . ', '
. (double) ($item->list_price ? $item->list_price : 0) . ', '
. (double) ($item->sale_price ? $item->sale_price : 0)
);
$db->setQuery($query);
$db->execute();
// Get the link id.
$linkId = (int) $db->insertid();
}
else
{
// Update the link.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('route') . ' = ' . $db->quote($item->route))
->set($db->quoteName('title') . ' = ' . $db->quote($item->title))
->set($db->quoteName('description') . ' = ' . $db->quote($item->description))
->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp())
->set($db->quoteName('state') . ' = ' . (int) $item->state)
->set($db->quoteName('access') . ' = ' . (int) $item->access)
->set($db->quoteName('language') . ' = ' . $db->quote($item->language))
->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id)
->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item)))
->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date))
->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date))
->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date))
->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date))
->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0))
->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0))
->where('link_id = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Set up the variables we will need during processing.
$count = 0;
// Mark afterLinking in the profiler.
static::$profiler ? static::$profiler->mark('afterLinking') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
/*
* Process the item's content. The items can customize their
* processing instructions to define extra properties to process
* or rearrange how properties are weighted.
*/
foreach ($item->getInstructions() as $group => $properties)
{
// Iterate through the properties of the group.
foreach ($properties as $property)
{
// Check if the property exists in the item.
if (empty($item->$property))
{
continue;
}
// Tokenize the property.
if (is_array($item->$property))
{
// Tokenize an array of content and add it to the database.
foreach ($item->$property as $ip)
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$ip = JFile::stripExt($ip);
$ip = str_replace('/', ' ', $ip);
$ip = str_replace('-', ' ', $ip);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($ip, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
else
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$item->$property = JFile::stripExt($item->$property);
$item->$property = str_replace('/', ' ', $item->$property);
$item->$property = str_replace('-', ' ', $item->$property);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($item->$property, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
}
/*
* Process the item's taxonomy. The items can customize their
* taxonomy mappings to define extra properties to map.
*/
foreach ($item->getTaxonomy() as $branch => $nodes)
{
// Iterate through the nodes and map them to the branch.
foreach ($nodes as $node)
{
// Add the node to the tree.
$nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access);
// Add the link => node map.
FinderIndexerTaxonomy::addMap($linkId, $nodeId);
// Tokenize the node title and add them to the database.
$count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format);
}
}
// Mark afterProcessing in the profiler.
static::$profiler ? static::$profiler->mark('afterProcessing') : null;
/*
* At this point, all of the item's content has been parsed, tokenized
* and inserted into the #__finder_tokens table. Now, we need to
* aggregate all the data into that table into a more usable form. The
* aggregated data will be inserted into #__finder_tokens_aggregate
* table.
*/
$query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') .
' (' . $db->quoteName('term_id') .
', ' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('term_weight') .
', ' . $db->quoteName('context') .
', ' . $db->quoteName('context_weight') .
', ' . $db->quoteName('language') . ')' .
' SELECT' .
' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, ' .
' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' .
' FROM (' .
' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' .
' WHERE t1.context = %d' .
' ) AS t1' .
' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' .
' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' .
' WHERE t2.context = %d' .
' GROUP BY t1.term' .
' ORDER BY t1.term DESC';
// Iterate through the contexts and aggregate the tokens per context.
foreach ($state->weights as $context => $multiplier)
{
// Run the query to aggregate the tokens for this context..
$db->setQuery(sprintf($query, $multiplier, $context, $context));
$db->execute();
}
// Mark afterAggregating in the profiler.
static::$profiler ? static::$profiler->mark('afterAggregating') : null;
/*
* When we pulled down all of the aggregate data, we did a LEFT JOIN
* over the terms table to try to find all the term ids that
* already exist for our tokens. If any of the rows in the aggregate
* table have a term of 0, then no term record exists for that
* term so we need to add it to the terms table.
*/
$db->setQuery(
'INSERT IGNORE INTO ' . $db->quoteName('#__finder_terms') .
' (' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('weight') .
', ' . $db->quoteName('soundex') .
', ' . $db->quoteName('language') . ')' .
' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' .
' WHERE ta.term_id = 0' .
' GROUP BY ta.term'
);
$db->execute();
/*
* Now, we just inserted a bunch of new records into the terms table
* so we need to go back and update the aggregate table with all the
* new term ids.
*/
$query = $db->getQuery(true)
->update($db->quoteName('#__finder_tokens_aggregate') . ' AS ta')
->join('INNER', $db->quoteName('#__finder_terms') . ' AS t ON t.term = ta.term')
->set('ta.term_id = t.term_id')
->where('ta.term_id = 0');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* After we've made sure that all of the terms are in the terms table
* and the aggregate table has the correct term ids, we need to update
* the links counter for each term by one.
*/
$query->clear()
->update($db->quoteName('#__finder_terms') . ' AS t')
->join('INNER', $db->quoteName('#__finder_tokens_aggregate') . ' AS ta ON ta.term_id = t.term_id')
->set('t.' . $db->quoteName('links') . ' = t.links + 1');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* Before we can insert all of the mapping rows, we have to figure out
* which mapping table the rows need to be inserted into. The mapping
* table for each term is based on the first character of the md5 of
* the first character of the term. In php, it would be expressed as
* substr(md5(substr($token, 0, 1)), 0, 1)
*/
$query->clear()
->update($db->quoteName('#__finder_tokens_aggregate'))
->set($db->quoteName('map_suffix') . ' = SUBSTR(MD5(SUBSTR(' . $db->quoteName('term') . ', 1, 1)), 1, 1)');
$db->setQuery($query);
$db->execute();
/*
* At this point, the aggregate table contains a record for each
* term in each context. So, we're going to pull down all of that
* data while grouping the records by term and add all of the
* sub-totals together to arrive at the final total for each token for
* this link. Then, we insert all of that data into the appropriate
* mapping table.
*/
for ($i = 0; $i <= 15; $i++)
{
// Get the mapping table suffix.
$suffix = dechex($i);
/*
* We have to run this query 16 times, one for each link => term
* mapping table.
*/
$db->setQuery(
'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) .
' (' . $db->quoteName('link_id') .
', ' . $db->quoteName('term_id') .
', ' . $db->quoteName('weight') . ')' .
' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' .
' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') .
' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) .
' GROUP BY ' . $db->quoteName('term') .
' ORDER BY ' . $db->quoteName('term') . ' DESC'
);
$db->execute();
}
// Mark afterMapping in the profiler.
static::$profiler ? static::$profiler->mark('afterMapping') : null;
// Update the signature.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig))
->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId));
$db->setQuery($query);
$db->execute();
// Mark afterSigning in the profiler.
static::$profiler ? static::$profiler->mark('afterSigning') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
// Toggle the token tables back to memory tables.
$this->toggleTables(true);
// Mark afterTruncating in the profiler.
static::$profiler ? static::$profiler->mark('afterTruncating') : null;
return $linkId;
}
/**
* Method to remove a link from the index.
*
* @param integer $linkId The id of the link.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
public function remove($linkId)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Update the link counts and remove the mapping records.
for ($i = 0; $i <= 15; $i++)
{
// Update the link counts for the terms.
$query->update($db->quoteName('#__finder_terms') . ' AS t')
->join('INNER', $db->quoteName('#__finder_links_terms' . dechex($i)) . ' AS m ON m.term_id = t.term_id')
->set('t.links = t.links - 1')
->where('m.link_id = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove all records from the mapping tables.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Delete all orphaned terms.
$query->clear()
->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Delete the link from the index.
$query->clear()
->delete($db->quoteName('#__finder_links'))
->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
return true;
}
/**
* Method to optimize the index. We use this method to remove unused terms
* and any other optimizations that might be necessary.
*
* @return boolean True on success.
*
* @since 3.0
* @throws Exception on database error.
*/
public function optimize()
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Delete all orphaned terms.
$query->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Optimize the links table.
$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links'));
$db->execute();
for ($i = 0; $i <= 15; $i++)
{
// Optimize the terms mapping table.
$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms' . dechex($i)));
$db->execute();
}
// Optimize the terms mapping table.
$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms'));
$db->execute();
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
// Optimize the taxonomy mapping table.
$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_taxonomy_map'));
$db->execute();
return true;
}
/**
* Method to add a set of tokens to the database.
*
* @param mixed $tokens An array or single FinderIndexerToken object.
* @param mixed $context The context of the tokens. See context constants. [optional]
*
* @return integer The number of tokens inserted into the database.
*
* @since 3.0
* @throws Exception on database error.
*/
protected function addTokensToDB($tokens, $context = '')
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Force tokens to an array.
$tokens = is_array($tokens) ? $tokens : array($tokens);
// Count the number of token values.
$values = 0;
// Insert the tokens into the database.
$query->insert($db->quoteName('#__finder_tokens'))
->columns(
array(
$db->quoteName('term'),
$db->quoteName('stem'),
$db->quoteName('common'),
$db->quoteName('phrase'),
$db->quoteName('weight'),
$db->quoteName('context'),
$db->quoteName('language')
)
);
// Iterate through the tokens to create SQL value sets.
foreach ($tokens as $token)
{
$query->values(
$db->quote($token->term) . ', '
. $db->quote($token->stem) . ', '
. (int) $token->common . ', '
. (int) $token->phrase . ', '
. (float) $token->weight . ', '
. (int) $context . ', '
. $db->quote($token->language)
);
$values++;
}
$db->setQuery($query);
$db->execute();
return $values;
}
/**
* Method to switch the token tables from Memory tables to MyISAM tables
* when they are close to running out of memory.
*
* @param boolean $memory Flag to control how they should be toggled.
*
* @return boolean True on success.
*
* @since 3.0
* @throws Exception on database error.
*/
protected function toggleTables($memory)
{
static $state;
// Get the database adapter.
$db = JFactory::getDbo();
// Check if we are setting the tables to the Memory engine.
if ($memory === true && $state !== true)
{
// Set the tokens table to Memory.
$db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MEMORY');
$db->execute();
// Set the tokens aggregate table to Memory.
$db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MEMORY');
$db->execute();
// Set the internal state.
$state = $memory;
}
// We must be setting the tables to the MyISAM engine.
elseif ($memory === false && $state !== false)
{
// Set the tokens table to MyISAM.
$db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MYISAM');
$db->execute();
// Set the tokens aggregate table to MyISAM.
$db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MYISAM');
$db->execute();
// Set the internal state.
$state = $memory;
}
return true;
}
}

View File

@ -0,0 +1,634 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
jimport('joomla.filesystem.file');
/**
* Indexer class supporting PostgreSQL for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 3.0
*/
class FinderIndexerDriverPostgresql extends FinderIndexer
{
/**
* Method to index a content item.
*
* @param FinderIndexerResult $item The content item to index.
* @param string $format The format of the content. [optional]
*
* @return integer The ID of the record in the links table.
*
* @since 3.0
* @throws Exception on database error.
*/
public function index($item, $format = 'html')
{
// Mark beforeIndexing in the profiler.
static::$profiler ? static::$profiler->mark('beforeIndexing') : null;
$db = JFactory::getDbo();
$nd = $db->getNullDate();
// Check if the item is in the database.
$query = $db->getQuery(true)
->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum'))
->from($db->quoteName('#__finder_links'))
->where($db->quoteName('url') . ' = ' . $db->quote($item->url));
// Load the item from the database.
$db->setQuery($query);
$link = $db->loadObject();
// Get the indexer state.
$state = static::getState();
// Get the signatures of the item.
$curSig = static::getSignature($item);
$oldSig = isset($link->md5sum) ? $link->md5sum : null;
// Get the other item information.
$linkId = empty($link->link_id) ? null : $link->link_id;
$isNew = empty($link->link_id) ? true : false;
// Check the signatures. If they match, the item is up to date.
if (!$isNew && $curSig == $oldSig)
{
return $linkId;
}
/*
* If the link already exists, flush all the term maps for the item.
* Maps are stored in 16 tables so we need to iterate through and flush
* each table one at a time.
*/
if (!$isNew)
{
for ($i = 0; $i <= 15; $i++)
{
// Flush the maps for the link.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
}
// Mark afterUnmapping in the profiler.
static::$profiler ? static::$profiler->mark('afterUnmapping') : null;
// Perform cleanup on the item data.
$item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd;
$item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd;
$item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd;
$item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd;
// Prepare the item description.
$item->description = FinderIndexerHelper::parse($item->summary);
/*
* Now, we need to enter the item into the links table. If the item
* already exists in the database, we need to use an UPDATE query.
* Otherwise, we need to use an INSERT to get the link id back.
*/
if ($isNew)
{
$columnsArray = array(
$db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'),
$db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'),
$db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'),
$db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'),
$db->quoteName('sale_price')
);
// Insert the link.
$query->clear()
->insert($db->quoteName('#__finder_links'))
->columns($columnsArray)
->values(
$db->quote($item->url) . ', '
. $db->quote($item->route) . ', '
. $db->quote($item->title) . ', '
. $db->quote($item->description) . ', '
. $query->currentTimestamp() . ', '
. '1, '
. (int) $item->state . ', '
. (int) $item->access . ', '
. $db->quote($item->language) . ', '
. (int) $item->type_id . ', '
. $db->quote(serialize($item)) . ', '
. $db->quote($item->publish_start_date) . ', '
. $db->quote($item->publish_end_date) . ', '
. $db->quote($item->start_date) . ', '
. $db->quote($item->end_date) . ', '
. (double) ($item->list_price ? $item->list_price : 0) . ', '
. (double) ($item->sale_price ? $item->sale_price : 0)
);
$db->setQuery($query);
$db->execute();
// Get the link id.
$linkId = (int) $db->insertid();
}
else
{
// Update the link.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('route') . ' = ' . $db->quote($item->route))
->set($db->quoteName('title') . ' = ' . $db->quote($item->title))
->set($db->quoteName('description') . ' = ' . $db->quote($item->description))
->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp())
->set($db->quoteName('state') . ' = ' . (int) $item->state)
->set($db->quoteName('access') . ' = ' . (int) $item->access)
->set($db->quoteName('language') . ' = ' . $db->quote($item->language))
->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id)
->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item)))
->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date))
->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date))
->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date))
->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date))
->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0))
->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0))
->where('link_id = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Set up the variables we will need during processing.
$count = 0;
// Mark afterLinking in the profiler.
static::$profiler ? static::$profiler->mark('afterLinking') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
/*
* Process the item's content. The items can customize their
* processing instructions to define extra properties to process
* or rearrange how properties are weighted.
*/
foreach ($item->getInstructions() as $group => $properties)
{
// Iterate through the properties of the group.
foreach ($properties as $property)
{
// Check if the property exists in the item.
if (empty($item->$property))
{
continue;
}
// Tokenize the property.
if (is_array($item->$property))
{
// Tokenize an array of content and add it to the database.
foreach ($item->$property as $ip)
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$ip = JFile::stripExt($ip);
$ip = str_replace('/', ' ', $ip);
$ip = str_replace('-', ' ', $ip);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($ip, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
else
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$item->$property = JFile::stripExt($item->$property);
$item->$property = str_replace('/', ' ', $item->$property);
$item->$property = str_replace('-', ' ', $item->$property);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($item->$property, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
}
/*
* Process the item's taxonomy. The items can customize their
* taxonomy mappings to define extra properties to map.
*/
foreach ($item->getTaxonomy() as $branch => $nodes)
{
// Iterate through the nodes and map them to the branch.
foreach ($nodes as $node)
{
// Add the node to the tree.
$nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access);
// Add the link => node map.
FinderIndexerTaxonomy::addMap($linkId, $nodeId);
// Tokenize the node title and add them to the database.
$count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format);
}
}
// Mark afterProcessing in the profiler.
static::$profiler ? static::$profiler->mark('afterProcessing') : null;
/*
* At this point, all of the item's content has been parsed, tokenized
* and inserted into the #__finder_tokens table. Now, we need to
* aggregate all the data into that table into a more usable form. The
* aggregated data will be inserted into #__finder_tokens_aggregate
* table.
*/
$query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') .
' (' . $db->quoteName('term_id') .
', ' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('term_weight') .
', ' . $db->quoteName('context') .
', ' . $db->quoteName('context_weight') .
', ' . $db->quoteName('language') . ')' .
' SELECT' .
' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context,' .
' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' .
' FROM (' .
' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' .
' WHERE t1.context = %d' .
' ) AS t1' .
' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' .
' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' .
' WHERE t2.context = %d' .
' GROUP BY t1.term, t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
' ORDER BY t1.term DESC';
// Iterate through the contexts and aggregate the tokens per context.
foreach ($state->weights as $context => $multiplier)
{
// Run the query to aggregate the tokens for this context..
$db->setQuery(sprintf($query, $multiplier, $context, $context));
$db->execute();
}
// Mark afterAggregating in the profiler.
static::$profiler ? static::$profiler->mark('afterAggregating') : null;
/*
* When we pulled down all of the aggregate data, we did a LEFT JOIN
* over the terms table to try to find all the term ids that
* already exist for our tokens. If any of the rows in the aggregate
* table have a term of 0, then no term record exists for that
* term so we need to add it to the terms table.
*/
/* Emulation of IGNORE INTO behaviour */
$db->setQuery(
' SELECT ta.term' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' .
' WHERE ta.term_id = 0'
);
if ($db->loadRow() == null)
{
$db->setQuery(
'INSERT INTO ' . $db->quoteName('#__finder_terms') .
' (' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('weight') .
', ' . $db->quoteName('soundex') .
', ' . $db->quoteName('language') . ')' .
' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' .
' WHERE ta.term_id = 0' .
' GROUP BY ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language'
);
$db->execute();
}
/*
* Now, we just inserted a bunch of new records into the terms table
* so we need to go back and update the aggregate table with all the
* new term ids.
*/
$query = $db->getQuery(true)
->update($db->quoteName('#__finder_tokens_aggregate') . ' AS ta')
->join('INNER', $db->quoteName('#__finder_terms') . ' AS t ON t.term = ta.term')
->set('ta.term_id = t.term_id')
->where('ta.term_id = 0');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* After we've made sure that all of the terms are in the terms table
* and the aggregate table has the correct term ids, we need to update
* the links counter for each term by one.
*/
$query->clear()
->update($db->quoteName('#__finder_terms') . ' AS t')
->join('INNER', $db->quoteName('#__finder_tokens_aggregate') . ' AS ta ON ta.term_id = t.term_id')
->set('t.' . $db->quoteName('links') . ' = t.links + 1');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* Before we can insert all of the mapping rows, we have to figure out
* which mapping table the rows need to be inserted into. The mapping
* table for each term is based on the first character of the md5 of
* the first character of the term. In php, it would be expressed as
* substr(md5(substr($token, 0, 1)), 0, 1)
*/
$query->clear()
->update($db->quoteName('#__finder_tokens_aggregate'))
->set($db->quoteName('map_suffix') . ' = SUBSTR(MD5(SUBSTR(' . $db->quoteName('term') . ', 1, 1)), 1, 1)');
$db->setQuery($query);
$db->execute();
/*
* At this point, the aggregate table contains a record for each
* term in each context. So, we're going to pull down all of that
* data while grouping the records by term and add all of the
* sub-totals together to arrive at the final total for each token for
* this link. Then, we insert all of that data into the appropriate
* mapping table.
*/
for ($i = 0; $i <= 15; $i++)
{
// Get the mapping table suffix.
$suffix = dechex($i);
/*
* We have to run this query 16 times, one for each link => term
* mapping table.
*/
$db->setQuery(
'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) .
' (' . $db->quoteName('link_id') .
', ' . $db->quoteName('term_id') .
', ' . $db->quoteName('weight') . ')' .
' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' .
' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') .
' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) .
' GROUP BY ' . $db->quoteName('term') .
' ORDER BY ' . $db->quoteName('term') . ' DESC'
);
$db->execute();
}
// Mark afterMapping in the profiler.
static::$profiler ? static::$profiler->mark('afterMapping') : null;
// Update the signature.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig))
->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId));
$db->setQuery($query);
$db->execute();
// Mark afterSigning in the profiler.
static::$profiler ? static::$profiler->mark('afterSigning') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
// Toggle the token tables back to memory tables.
$this->toggleTables(true);
// Mark afterTruncating in the profiler.
static::$profiler ? static::$profiler->mark('afterTruncating') : null;
return $linkId;
}
/**
* Method to remove a link from the index.
*
* @param integer $linkId The id of the link.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
public function remove($linkId)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Update the link counts and remove the mapping records.
for ($i = 0; $i <= 15; $i++)
{
// Update the link counts for the terms.
$query->update($db->quoteName('#__finder_terms') . ' AS t')
->join('INNER', $db->quoteName('#__finder_links_terms' . dechex($i)) . ' AS m ON m.term_id = t.term_id')
->set('t.links = t.links - 1')
->where('m.link_id = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove all records from the mapping tables.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Delete all orphaned terms.
$query->clear()
->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Delete the link from the index.
$query->clear()
->delete($db->quoteName('#__finder_links'))
->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
return true;
}
/**
* Method to optimize the index. We use this method to remove unused terms
* and any other optimizations that might be necessary.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
public function optimize()
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Delete all orphaned terms.
$query->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Optimize the links table.
$db->setQuery('VACUUM ' . $db->quoteName('#__finder_links'));
$db->execute();
$db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links'));
$db->execute();
for ($i = 0; $i <= 15; $i++)
{
// Optimize the terms mapping table.
$db->setQuery('VACUUM ' . $db->quoteName('#__finder_links_terms' . dechex($i)));
$db->execute();
$db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links_terms' . dechex($i)));
$db->execute();
}
// Optimize the terms mapping table.
$db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_links_terms'));
$db->execute();
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
// Optimize the taxonomy mapping table.
$db->setQuery('REINDEX TABLE ' . $db->quoteName('#__finder_taxonomy_map'));
$db->execute();
return true;
}
/**
* Method to add a set of tokens to the database.
*
* @param mixed $tokens An array or single FinderIndexerToken object.
* @param mixed $context The context of the tokens. See context constants. [optional]
*
* @return integer The number of tokens inserted into the database.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function addTokensToDB($tokens, $context = '')
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Force tokens to an array.
$tokens = is_array($tokens) ? $tokens : array($tokens);
// Count the number of token values.
$values = 0;
// Insert the tokens into the database.
$query->insert($db->quoteName('#__finder_tokens'))
->columns(
array(
$db->quoteName('term'),
$db->quoteName('stem'),
$db->quoteName('common'),
$db->quoteName('phrase'),
$db->quoteName('weight'),
$db->quoteName('context'),
$db->quoteName('language')
)
);
// Iterate through the tokens to create SQL value sets.
foreach ($tokens as $token)
{
$query->values(
$db->quote($token->term) . ', '
. $db->quote($token->stem) . ', '
. (int) $token->common . ', '
. (int) $token->phrase . ', '
. (float) $token->weight . ', '
. (int) $context . ', '
. $db->quote($token->language)
);
$values++;
}
$db->setQuery($query);
$db->execute();
return $values;
}
/**
* Method to switch the token tables from Memory tables to MyISAM tables
* when they are close to running out of memory.
*
* @param boolean $memory Flag to control how they should be toggled.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
protected function toggleTables($memory)
{
return true;
}
}

View File

@ -0,0 +1,630 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
jimport('joomla.filesystem.file');
/**
* Indexer class supporting SQL Server for the Finder indexer package.
*
* The indexer class provides the core functionality of the Finder
* search engine. It is responsible for adding and updating the
* content links table; extracting and scoring tokens; and maintaining
* all referential information for the content.
*
* Note: All exceptions thrown from within this class should be caught
* by the controller.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 3.1
*/
class FinderIndexerDriverSqlsrv extends FinderIndexer
{
/**
* Method to index a content item.
*
* @param FinderIndexerResult $item The content item to index.
* @param string $format The format of the content. [optional]
*
* @return integer The ID of the record in the links table.
*
* @since 3.1
* @throws Exception on database error.
*/
public function index($item, $format = 'html')
{
// Mark beforeIndexing in the profiler.
static::$profiler ? static::$profiler->mark('beforeIndexing') : null;
$db = JFactory::getDbo();
$nd = $db->getNullDate();
// Check if the item is in the database.
$query = $db->getQuery(true)
->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum'))
->from($db->quoteName('#__finder_links'))
->where($db->quoteName('url') . ' = ' . $db->quote($item->url));
// Load the item from the database.
$db->setQuery($query);
$link = $db->loadObject();
// Get the indexer state.
$state = static::getState();
// Get the signatures of the item.
$curSig = static::getSignature($item);
$oldSig = isset($link->md5sum) ? $link->md5sum : null;
// Get the other item information.
$linkId = empty($link->link_id) ? null : $link->link_id;
$isNew = empty($link->link_id) ? true : false;
// Check the signatures. If they match, the item is up to date.
if (!$isNew && $curSig == $oldSig)
{
return $linkId;
}
/*
* If the link already exists, flush all the term maps for the item.
* Maps are stored in 16 tables so we need to iterate through and flush
* each table one at a time.
*/
if (!$isNew)
{
for ($i = 0; $i <= 15; $i++)
{
// Flush the maps for the link.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
}
// Mark afterUnmapping in the profiler.
static::$profiler ? static::$profiler->mark('afterUnmapping') : null;
// Perform cleanup on the item data.
$item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd;
$item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd;
$item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd;
$item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd;
// Prepare the item description.
$item->description = FinderIndexerHelper::parse($item->summary);
/*
* Now, we need to enter the item into the links table. If the item
* already exists in the database, we need to use an UPDATE query.
* Otherwise, we need to use an INSERT to get the link id back.
*/
if ($isNew)
{
$columnsArray = array(
$db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'),
$db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'),
$db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'),
$db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'),
$db->quoteName('sale_price')
);
// Insert the link.
$query->clear()
->insert($db->quoteName('#__finder_links'))
->columns($columnsArray)
->values(
$db->quote($item->url) . ', '
. $db->quote($item->route) . ', '
. $db->quote($item->title) . ', '
. $db->quote($item->description) . ', '
. $query->currentTimestamp() . ', '
. '1, '
. (int) $item->state . ', '
. (int) $item->access . ', '
. $db->quote($item->language) . ', '
. (int) $item->type_id . ', '
. $db->quote(serialize($item)) . ', '
. $db->quote($item->publish_start_date) . ', '
. $db->quote($item->publish_end_date) . ', '
. $db->quote($item->start_date) . ', '
. $db->quote($item->end_date) . ', '
. (double) ($item->list_price ? $item->list_price : 0) . ', '
. (double) ($item->sale_price ? $item->sale_price : 0)
);
$db->setQuery($query);
$db->execute();
// Get the link id.
$linkId = (int) $db->insertid();
}
else
{
// Update the link.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('route') . ' = ' . $db->quote($item->route))
->set($db->quoteName('title') . ' = ' . $db->quote($item->title))
->set($db->quoteName('description') . ' = ' . $db->quote($item->description))
->set($db->quoteName('indexdate') . ' = ' . $query->currentTimestamp())
->set($db->quoteName('state') . ' = ' . (int) $item->state)
->set($db->quoteName('access') . ' = ' . (int) $item->access)
->set($db->quoteName('language') . ' = ' . $db->quote($item->language))
->set($db->quoteName('type_id') . ' = ' . (int) $item->type_id)
->set($db->quoteName('object') . ' = ' . $db->quote(serialize($item)))
->set($db->quoteName('publish_start_date') . ' = ' . $db->quote($item->publish_start_date))
->set($db->quoteName('publish_end_date') . ' = ' . $db->quote($item->publish_end_date))
->set($db->quoteName('start_date') . ' = ' . $db->quote($item->start_date))
->set($db->quoteName('end_date') . ' = ' . $db->quote($item->end_date))
->set($db->quoteName('list_price') . ' = ' . (double) ($item->list_price ? $item->list_price : 0))
->set($db->quoteName('sale_price') . ' = ' . (double) ($item->sale_price ? $item->sale_price : 0))
->where('link_id = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Set up the variables we will need during processing.
$count = 0;
// Mark afterLinking in the profiler.
static::$profiler ? static::$profiler->mark('afterLinking') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
/*
* Process the item's content. The items can customize their
* processing instructions to define extra properties to process
* or rearrange how properties are weighted.
*/
foreach ($item->getInstructions() as $group => $properties)
{
// Iterate through the properties of the group.
foreach ($properties as $property)
{
// Check if the property exists in the item.
if (empty($item->$property))
{
continue;
}
// Tokenize the property.
if (is_array($item->$property))
{
// Tokenize an array of content and add it to the database.
foreach ($item->$property as $ip)
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$ip = JFile::stripExt($ip);
$ip = str_replace('/', ' ', $ip);
$ip = str_replace('-', ' ', $ip);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($ip, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
else
{
/*
* If the group is path, we need to a few extra processing
* steps to strip the extension and convert slashes and dashes
* to spaces.
*/
if ($group === static::PATH_CONTEXT)
{
$item->$property = JFile::stripExt($item->$property);
$item->$property = str_replace('/', ' ', $item->$property);
$item->$property = str_replace('-', ' ', $item->$property);
}
// Tokenize a string of content and add it to the database.
$count += $this->tokenizeToDB($item->$property, $group, $item->language, $format);
// Check if we're approaching the memory limit of the token table.
if ($count > static::$state->options->get('memory_table_limit', 30000))
{
$this->toggleTables(false);
}
}
}
}
/*
* Process the item's taxonomy. The items can customize their
* taxonomy mappings to define extra properties to map.
*/
foreach ($item->getTaxonomy() as $branch => $nodes)
{
// Iterate through the nodes and map them to the branch.
foreach ($nodes as $node)
{
// Add the node to the tree.
$nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access);
// Add the link => node map.
FinderIndexerTaxonomy::addMap($linkId, $nodeId);
// Tokenize the node title and add them to the database.
$count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format);
}
}
// Mark afterProcessing in the profiler.
static::$profiler ? static::$profiler->mark('afterProcessing') : null;
/*
* At this point, all of the item's content has been parsed, tokenized
* and inserted into the #__finder_tokens table. Now, we need to
* aggregate all the data into that table into a more usable form. The
* aggregated data will be inserted into #__finder_tokens_aggregate
* table.
*/
$query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') .
' (' . $db->quoteName('term_id') .
', ' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('term_weight') .
', ' . $db->quoteName('context') .
', ' . $db->quoteName('context_weight') .
', ' . $db->quoteName('language') . ')' .
' SELECT' .
' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context,' .
' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' .
' FROM (' .
' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' .
' WHERE t1.context = %d' .
' ) AS t1' .
' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' .
' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' .
' WHERE t2.context = %d' .
' GROUP BY t1.term, t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
' ORDER BY t1.term DESC';
// Iterate through the contexts and aggregate the tokens per context.
foreach ($state->weights as $context => $multiplier)
{
// Run the query to aggregate the tokens for this context..
$db->setQuery(sprintf($query, $multiplier, $context, $context));
$db->execute();
}
// Mark afterAggregating in the profiler.
static::$profiler ? static::$profiler->mark('afterAggregating') : null;
/*
* When we pulled down all of the aggregate data, we did a LEFT JOIN
* over the terms table to try to find all the term ids that
* already exist for our tokens. If any of the rows in the aggregate
* table have a term of 0, then no term record exists for that
* term so we need to add it to the terms table.
*/
$db->setQuery(
'INSERT INTO ' . $db->quoteName('#__finder_terms') .
' (' . $db->quoteName('term') .
', ' . $db->quoteName('stem') .
', ' . $db->quoteName('common') .
', ' . $db->quoteName('phrase') .
', ' . $db->quoteName('weight') .
', ' . $db->quoteName('soundex') . ')' .
' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term)' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' .
' WHERE ta.term_id IS NULL' .
' GROUP BY ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight'
);
$db->execute();
/*
* Now, we just inserted a bunch of new records into the terms table
* so we need to go back and update the aggregate table with all the
* new term ids.
*/
$query = $db->getQuery(true)
->update('ta')
->set('ta.term_id = t.term_id from #__finder_tokens_aggregate AS ta INNER JOIN #__finder_terms AS t ON t.term = ta.term')
->where('ta.term_id IS NULL');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* After we've made sure that all of the terms are in the terms table
* and the aggregate table has the correct term ids, we need to update
* the links counter for each term by one.
*/
$query->clear()
->update('t')
->set('t.links = t.links + 1 FROM #__finder_terms AS t INNER JOIN #__finder_tokens_aggregate AS ta ON ta.term_id = t.term_id');
$db->setQuery($query);
$db->execute();
// Mark afterTerms in the profiler.
static::$profiler ? static::$profiler->mark('afterTerms') : null;
/*
* Before we can insert all of the mapping rows, we have to figure out
* which mapping table the rows need to be inserted into. The mapping
* table for each term is based on the first character of the md5 of
* the first character of the term. In php, it would be expressed as
* substr(md5(substr($token, 0, 1)), 0, 1)
*/
$query->clear()
->update($db->quoteName('#__finder_tokens_aggregate'))
->set($db->quoteName('map_suffix') . " = SUBSTRING(HASHBYTES('MD5', SUBSTRING(" . $db->quoteName('term') . ', 1, 1)), 1, 1)');
$db->setQuery($query);
$db->execute();
/*
* At this point, the aggregate table contains a record for each
* term in each context. So, we're going to pull down all of that
* data while grouping the records by term and add all of the
* sub-totals together to arrive at the final total for each token for
* this link. Then, we insert all of that data into the appropriate
* mapping table.
*/
for ($i = 0; $i <= 15; $i++)
{
// Get the mapping table suffix.
$suffix = dechex($i);
/*
* We have to run this query 16 times, one for each link => term
* mapping table.
*/
$db->setQuery(
'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) .
' (' . $db->quoteName('link_id') .
', ' . $db->quoteName('term_id') .
', ' . $db->quoteName('weight') . ')' .
' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' .
' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' .
' FROM ' . $db->quoteName('#__finder_tokens_aggregate') .
' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) .
' GROUP BY term, term_id' .
' ORDER BY ' . $db->quoteName('term') . ' DESC'
);
$db->execute();
}
// Mark afterMapping in the profiler.
static::$profiler ? static::$profiler->mark('afterMapping') : null;
// Update the signature.
$query->clear()
->update($db->quoteName('#__finder_links'))
->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig))
->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId));
$db->setQuery($query);
$db->execute();
// Mark afterSigning in the profiler.
static::$profiler ? static::$profiler->mark('afterSigning') : null;
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
// Toggle the token tables back to memory tables.
$this->toggleTables(true);
// Mark afterTruncating in the profiler.
static::$profiler ? static::$profiler->mark('afterTruncating') : null;
return $linkId;
}
/**
* Method to remove a link from the index.
*
* @param integer $linkId The id of the link.
*
* @return boolean True on success.
*
* @since 3.1
* @throws Exception on database error.
*/
public function remove($linkId)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Update the link counts and remove the mapping records.
for ($i = 0; $i <= 15; $i++)
{
// Update the link counts for the terms.
$query->update('t')
->set('t.links = t.links - 1 from #__finder_terms AS t INNER JOIN #__finder_links_terms' . dechex($i) . ' AS AS m ON m.term_id = t.term_id')
->where('m.link_id = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove all records from the mapping tables.
$query->clear()
->delete($db->quoteName('#__finder_links_terms' . dechex($i)))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
}
// Delete all orphaned terms.
$query->clear()
->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Delete the link from the index.
$query->clear()
->delete($db->quoteName('#__finder_links'))
->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId));
$db->setQuery($query);
$db->execute();
// Remove the taxonomy maps.
FinderIndexerTaxonomy::removeMaps($linkId);
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
return true;
}
/**
* Method to optimize the index. We use this method to remove unused terms
* and any other optimizations that might be necessary.
*
* @return boolean True on success.
*
* @since 3.1
* @throws Exception on database error.
*/
public function optimize()
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Delete all orphaned terms.
$query->delete($db->quoteName('#__finder_terms'))
->where($db->quoteName('links') . ' <= 0');
$db->setQuery($query);
$db->execute();
// Remove the orphaned taxonomy nodes.
FinderIndexerTaxonomy::removeOrphanNodes();
return true;
}
/**
* Method to add a set of tokens to the database.
*
* @param mixed $tokens An array or single FinderIndexerToken object.
* @param mixed $context The context of the tokens. See context constants. [optional]
*
* @return integer The number of tokens inserted into the database.
*
* @since 3.1
* @throws Exception on database error.
*/
protected function addTokensToDB($tokens, $context = '')
{
// Get the database object.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Force tokens to an array.
$tokens = is_array($tokens) ? $tokens : array($tokens);
// Count the number of token values.
$values = 0;
// Set some variables to count the iterations
$totalTokens = count($tokens);
$remaining = $totalTokens;
$iterations = 0;
$loop = true;
do
{
// Shift the token off the array
$token = array_shift($tokens);
$query->values(
$db->quote($token->term) . ', '
. $db->quote($token->stem) . ', '
. (int) $token->common . ', '
. (int) $token->phrase . ', '
. (float) $token->weight . ', '
. (int) $context . ', '
. $db->quote($token->language)
);
$values++;
$iterations++;
$remaining--;
// Run the query if we've reached 1000 iterations or there are no tokens remaining
if ($iterations == 1000 || $remaining == 0)
{
// Insert the tokens into the database.
$query->insert($db->quoteName('#__finder_tokens'))
->columns(
array(
$db->quoteName('term'),
$db->quoteName('stem'),
$db->quoteName('common'),
$db->quoteName('phrase'),
$db->quoteName('weight'),
$db->quoteName('context'),
$db->quoteName('language')
)
);
$db->setQuery($query);
$db->execute();
// Reset the query
$query->clear();
}
// If there's nothing remaining, we're done looping
if ($remaining == 0)
{
$loop = false;
}
}
while ($loop == true);
return $values;
}
/**
* Method to switch the token tables from Memory tables to MyISAM tables
* when they are close to running out of memory.
*
* @param boolean $memory Flag to control how they should be toggled.
*
* @return boolean True on success.
*
* @since 3.1
* @throws Exception on database error.
*/
protected function toggleTables($memory)
{
return true;
}
}

View File

@ -0,0 +1,506 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerParser', __DIR__ . '/parser.php');
JLoader::register('FinderIndexerStemmer', __DIR__ . '/stemmer.php');
JLoader::register('FinderIndexerToken', __DIR__ . '/token.php');
/**
* Helper class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerHelper
{
/**
* The token stemmer object. The stemmer is set by whatever class
* wishes to use it but it must be an instance of FinderIndexerStemmer.
*
* @var FinderIndexerStemmer
* @since 2.5
*/
public static $stemmer;
/**
* Method to parse input into plain text.
*
* @param string $input The raw input.
* @param string $format The format of the input. [optional]
*
* @return string The parsed input.
*
* @since 2.5
* @throws Exception on invalid parser.
*/
public static function parse($input, $format = 'html')
{
// Get a parser for the specified format and parse the input.
return FinderIndexerParser::getInstance($format)->parse($input);
}
/**
* Method to tokenize a text string.
*
* @param string $input The input to tokenize.
* @param string $lang The language of the input.
* @param boolean $phrase Flag to indicate whether input could be a phrase. [optional]
*
* @return array An array of FinderIndexerToken objects.
*
* @since 2.5
*/
public static function tokenize($input, $lang, $phrase = false)
{
static $cache;
$store = JString::strlen($input) < 128 ? md5($input . '::' . $lang . '::' . $phrase) : null;
// Check if the string has been tokenized already.
if ($store && isset($cache[$store]))
{
return $cache[$store];
}
$tokens = array();
$quotes = html_entity_decode('&#8216;&#8217;&#39;', ENT_QUOTES, 'UTF-8');
// Get the simple language key.
$lang = self::getPrimaryLanguage($lang);
/*
* Parsing the string input into terms is a multi-step process.
*
* Regexes:
* 1. Remove everything except letters, numbers, quotes, apostrophe, plus, dash, period, and comma.
* 2. Remove plus, dash, period, and comma characters located before letter characters.
* 3. Remove plus, dash, period, and comma characters located after other characters.
* 4. Remove plus, period, and comma characters enclosed in alphabetical characters. Ungreedy.
* 5. Remove orphaned apostrophe, plus, dash, period, and comma characters.
* 6. Remove orphaned quote characters.
* 7. Replace the assorted single quotation marks with the ASCII standard single quotation.
* 8. Remove multiple space characters and replaces with a single space.
*/
$input = JString::strtolower($input);
$input = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $input);
$input = preg_replace('#(^|\s)[+-.,]+([\pL\pM]+)#mui', ' $1', $input);
$input = preg_replace('#([\pL\pM\pN]+)[+-.,]+(\s|$)#mui', '$1 ', $input);
$input = preg_replace('#([\pL\pM]+)[+.,]+([\pL\pM]+)#muiU', '$1 $2', $input);
$input = preg_replace('#(^|\s)[\'+-.,]+(\s|$)#mui', ' ', $input);
$input = preg_replace('#(^|\s)[\p{Pi}\p{Pf}]+(\s|$)#mui', ' ', $input);
$input = preg_replace('#[' . $quotes . ']+#mui', '\'', $input);
$input = preg_replace('#\s+#mui', ' ', $input);
$input = JString::trim($input);
// Explode the normalized string to get the terms.
$terms = explode(' ', $input);
/*
* If we have Unicode support and are dealing with Chinese text, Chinese
* has to be handled specially because there are not necessarily any spaces
* between the "words". So, we have to test if the words belong to the Chinese
* character set and if so, explode them into single glyphs or "words".
*/
if ($lang === 'zh')
{
// Iterate through the terms and test if they contain Chinese.
for ($i = 0, $n = count($terms); $i < $n; $i++)
{
$charMatches = array();
$charCount = preg_match_all('#[\p{Han}]#mui', $terms[$i], $charMatches);
// Split apart any groups of Chinese characters.
for ($j = 0; $j < $charCount; $j++)
{
$tSplit = JString::str_ireplace($charMatches[0][$j], '', $terms[$i], false);
if (!empty($tSplit))
{
$terms[$i] = $tSplit;
}
else
{
unset($terms[$i]);
}
$terms[] = $charMatches[0][$j];
}
}
// Reset array keys.
$terms = array_values($terms);
}
/*
* If we have to handle the input as a phrase, that means we don't
* tokenize the individual terms and we do not create the two and three
* term combinations. The phrase must contain more than one word!
*/
if ($phrase === true && count($terms) > 1)
{
// Create tokens from the phrase.
$tokens[] = new FinderIndexerToken($terms, $lang);
}
else
{
// Create tokens from the terms.
for ($i = 0, $n = count($terms); $i < $n; $i++)
{
$tokens[] = new FinderIndexerToken($terms[$i], $lang);
}
// Create two and three word phrase tokens from the individual words.
for ($i = 0, $n = count($tokens); $i < $n; $i++)
{
// Setup the phrase positions.
$i2 = $i + 1;
$i3 = $i + 2;
// Create the two word phrase.
if ($i2 < $n && isset($tokens[$i2]))
{
// Tokenize the two word phrase.
$token = new FinderIndexerToken(array($tokens[$i]->term, $tokens[$i2]->term), $lang, $lang === 'zh' ? '' : ' ');
$token->derived = true;
// Add the token to the stack.
$tokens[] = $token;
}
// Create the three word phrase.
if ($i3 < $n && isset($tokens[$i3]))
{
// Tokenize the three word phrase.
$token = new FinderIndexerToken(array($tokens[$i]->term, $tokens[$i2]->term, $tokens[$i3]->term), $lang, $lang === 'zh' ? '' : ' ');
$token->derived = true;
// Add the token to the stack.
$tokens[] = $token;
}
}
}
if ($store)
{
$cache[$store] = count($tokens) > 1 ? $tokens : array_shift($tokens);
return $cache[$store];
}
else
{
return count($tokens) > 1 ? $tokens : array_shift($tokens);
}
}
/**
* Method to get the base word of a token. This method uses the public
* {@link FinderIndexerHelper::$stemmer} object if it is set. If no stemmer is set,
* the original token is returned.
*
* @param string $token The token to stem.
* @param string $lang The language of the token.
*
* @return string The root token.
*
* @since 2.5
*/
public static function stem($token, $lang)
{
// Trim apostrophes at either end of the token.
$token = JString::trim($token, '\'');
// Trim everything after any apostrophe in the token.
if (($pos = JString::strpos($token, '\'')) !== false)
{
$token = JString::substr($token, 0, $pos);
}
// Stem the token if we have a valid stemmer to use.
if (self::$stemmer instanceof FinderIndexerStemmer)
{
return self::$stemmer->stem($token, $lang);
}
else
{
return $token;
}
}
/**
* Method to add a content type to the database.
*
* @param string $title The type of content. For example: PDF
* @param string $mime The mime type of the content. For example: PDF [optional]
*
* @return integer The id of the content type.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function addContentType($title, $mime = null)
{
static $types;
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// Check if the types are loaded.
if (empty($types))
{
// Build the query to get the types.
$query->select('*')
->from($db->quoteName('#__finder_types'));
// Get the types.
$db->setQuery($query);
$types = $db->loadObjectList('title');
}
// Check if the type already exists.
if (isset($types[$title]))
{
return (int) $types[$title]->id;
}
// Add the type.
$query->clear()
->insert($db->quoteName('#__finder_types'))
->columns(array($db->quoteName('title'), $db->quoteName('mime')))
->values($db->quote($title) . ', ' . $db->quote($mime));
$db->setQuery($query);
$db->execute();
// Return the new id.
return (int) $db->insertid();
}
/**
* Method to check if a token is common in a language.
*
* @param string $token The token to test.
* @param string $lang The language to reference.
*
* @return boolean True if common, false otherwise.
*
* @since 2.5
*/
public static function isCommon($token, $lang)
{
static $data;
// Load the common tokens for the language if necessary.
if (!isset($data[$lang]))
{
$data[$lang] = self::getCommonWords($lang);
}
// Check if the token is in the common array.
if (in_array($token, $data[$lang]))
{
return true;
}
else
{
return false;
}
}
/**
* Method to get an array of common terms for a language.
*
* @param string $lang The language to use.
*
* @return array Array of common terms.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function getCommonWords($lang)
{
$db = JFactory::getDbo();
// Create the query to load all the common terms for the language.
$query = $db->getQuery(true)
->select($db->quoteName('term'))
->from($db->quoteName('#__finder_terms_common'))
->where($db->quoteName('language') . ' = ' . $db->quote($lang));
// Load all of the common terms for the language.
$db->setQuery($query);
$results = $db->loadColumn();
return $results;
}
/**
* Method to get the default language for the site.
*
* @return string The default language string.
*
* @since 2.5
*/
public static function getDefaultLanguage()
{
static $lang;
// We need to go to com_languages to get the site default language, it's the best we can guess.
if (empty($lang))
{
$lang = JComponentHelper::getParams('com_languages')->get('site', 'en-GB');
}
return $lang;
}
/**
* Method to parse a language/locale key and return a simple language string.
*
* @param string $lang The language/locale key. For example: en-GB
*
* @return string The simple language string. For example: en
*
* @since 2.5
*/
public static function getPrimaryLanguage($lang)
{
static $data;
// Only parse the identifier if necessary.
if (!isset($data[$lang]))
{
if (is_callable(array('Locale', 'getPrimaryLanguage')))
{
// Get the language key using the Locale package.
$data[$lang] = Locale::getPrimaryLanguage($lang);
}
else
{
// Get the language key using string position.
$data[$lang] = JString::substr($lang, 0, JString::strpos($lang, '-'));
}
}
return $data[$lang];
}
/**
* Method to get the path (SEF route) for a content item.
*
* @param string $url The non-SEF route to the content item.
*
* @return string The path for the content item.
*
* @since 2.5
*/
public static function getContentPath($url)
{
static $router;
// Only get the router once.
if (!($router instanceof JRouter))
{
jimport('joomla.application.router');
include_once JPATH_SITE . '/includes/application.php';
// Get and configure the site router.
$config = JFactory::getConfig();
$router = JRouter::getInstance('site');
$router->setMode($config->get('sef', 1));
}
// Build the relative route.
$uri = $router->build($url);
$route = $uri->toString(array('path', 'query', 'fragment'));
$route = str_replace(JUri::base(true) . '/', '', $route);
return $route;
}
/**
* Method to get extra data for a content before being indexed. This is how
* we add Comments, Tags, Labels, etc. that should be available to Finder.
*
* @param FinderIndexerResult &$item The item to index as an FinderIndexerResult object.
*
* @return boolean True on success, false on failure.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function getContentExtras(FinderIndexerResult &$item)
{
// Get the event dispatcher.
$dispatcher = JEventDispatcher::getInstance();
// Load the finder plugin group.
JPluginHelper::importPlugin('finder');
try
{
// Trigger the event.
$results = $dispatcher->trigger('onPrepareFinderContent', array(&$item));
// Check the returned results. This is for plugins that don't throw
// exceptions when they encounter serious errors.
if (in_array(false, $results))
{
throw new Exception($dispatcher->getError(), 500);
}
}
catch (Exception $e)
{
// Handle a caught exception.
throw $e;
}
return true;
}
/**
* Method to process content text using the onContentPrepare event trigger.
*
* @param string $text The content to process.
* @param JRegistry $params The parameters object. [optional]
*
* @return string The processed content.
*
* @since 2.5
*/
public static function prepareContent($text, $params = null)
{
static $loaded;
// Get the dispatcher.
$dispatcher = JEventDispatcher::getInstance();
// Load the content plugins if necessary.
if (empty($loaded))
{
JPluginHelper::importPlugin('content');
$loaded = true;
}
// Instantiate the parameter object if necessary.
if (!($params instanceof JRegistry))
{
$registry = new JRegistry;
$registry->loadString($params);
$params = $registry;
}
// Create a mock content object.
$content = JTable::getInstance('Content');
$content->text = $text;
// Fire the onContentPrepare event.
$dispatcher->trigger('onContentPrepare', array('com_finder.indexer', &$content, &$params, 0));
return $content->text;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,484 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerHelper', __DIR__ . '/helper.php');
JLoader::register('FinderIndexerParser', __DIR__ . '/parser.php');
JLoader::register('FinderIndexerStemmer', __DIR__ . '/stemmer.php');
JLoader::register('FinderIndexerTaxonomy', __DIR__ . '/taxonomy.php');
JLoader::register('FinderIndexerToken', __DIR__ . '/token.php');
jimport('joomla.filesystem.file');
/**
* Main indexer class for the Finder indexer package.
*
* The indexer class provides the core functionality of the Finder
* search engine. It is responsible for adding and updating the
* content links table; extracting and scoring tokens; and maintaining
* all referential information for the content.
*
* Note: All exceptions thrown from within this class should be caught
* by the controller.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
abstract class FinderIndexer
{
/**
* The title context identifier.
*
* @var integer
* @since 2.5
*/
const TITLE_CONTEXT = 1;
/**
* The text context identifier.
*
* @var integer
* @since 2.5
*/
const TEXT_CONTEXT = 2;
/**
* The meta context identifier.
*
* @var integer
* @since 2.5
*/
const META_CONTEXT = 3;
/**
* The path context identifier.
*
* @var integer
* @since 2.5
*/
const PATH_CONTEXT = 4;
/**
* The misc context identifier.
*
* @var integer
* @since 2.5
*/
const MISC_CONTEXT = 5;
/**
* The indexer state object.
*
* @var object
* @since 2.5
*/
public static $state;
/**
* The indexer profiler object.
*
* @var object
* @since 2.5
*/
public static $profiler;
/**
* Returns a reference to the FinderIndexer object.
*
* @return FinderIndexer instance based on the database driver
*
* @since 3.0
* @throws RuntimeException if driver class for indexer not present.
*/
public static function getInstance()
{
// Setup the adapter for the indexer.
$format = JFactory::getDbo()->name;
if ($format == 'mysqli')
{
$format = 'mysql';
}
elseif ($format == 'sqlazure')
{
$format = 'sqlsrv';
}
$path = __DIR__ . '/driver/' . $format . '.php';
$class = 'FinderIndexerDriver' . ucfirst($format);
// Check if a parser exists for the format.
if (file_exists($path))
{
// Instantiate the parser.
include_once $path;
return new $class;
}
else
{
// Throw invalid format exception.
throw new RuntimeException(JText::sprintf('COM_FINDER_INDEXER_INVALID_DRIVER', $format));
}
}
/**
* Method to get the indexer state.
*
* @return object The indexer state object.
*
* @since 2.5
*/
public static function getState()
{
// First, try to load from the internal state.
if (!empty(self::$state))
{
return self::$state;
}
// If we couldn't load from the internal state, try the session.
$session = JFactory::getSession();
$data = $session->get('_finder.state', null);
// If the state is empty, load the values for the first time.
if (empty($data))
{
$data = new JObject;
// Load the default configuration options.
$data->options = JComponentHelper::getParams('com_finder');
// Setup the weight lookup information.
$data->weights = array(
self::TITLE_CONTEXT => round($data->options->get('title_multiplier', 1.7), 2),
self::TEXT_CONTEXT => round($data->options->get('text_multiplier', 0.7), 2),
self::META_CONTEXT => round($data->options->get('meta_multiplier', 1.2), 2),
self::PATH_CONTEXT => round($data->options->get('path_multiplier', 2.0), 2),
self::MISC_CONTEXT => round($data->options->get('misc_multiplier', 0.3), 2)
);
// Set the current time as the start time.
$data->startTime = JFactory::getDate()->toSQL();
// Set the remaining default values.
$data->batchSize = (int) $data->options->get('batch_size', 50);
$data->batchOffset = 0;
$data->totalItems = 0;
$data->pluginState = array();
}
// Setup the profiler if debugging is enabled.
if (JFactory::getApplication()->getCfg('debug'))
{
self::$profiler = JProfiler::getInstance('FinderIndexer');
}
// Setup the stemmer.
if ($data->options->get('stem', 1) && $data->options->get('stemmer', 'porter_en'))
{
FinderIndexerHelper::$stemmer = FinderIndexerStemmer::getInstance($data->options->get('stemmer', 'porter_en'));
}
// Set the state.
self::$state = $data;
return self::$state;
}
/**
* Method to set the indexer state.
*
* @param object $data A new indexer state object.
*
* @return boolean True on success, false on failure.
*
* @since 2.5
*/
public static function setState($data)
{
// Check the state object.
if (empty($data) || !$data instanceof JObject)
{
return false;
}
// Set the new internal state.
self::$state = $data;
// Set the new session state.
$session = JFactory::getSession();
$session->set('_finder.state', $data);
return true;
}
/**
* Method to reset the indexer state.
*
* @return void
*
* @since 2.5
*/
public static function resetState()
{
// Reset the internal state to null.
self::$state = null;
// Reset the session state to null.
$session = JFactory::getSession();
$session->set('_finder.state', null);
}
/**
* Method to index a content item.
*
* @param FinderIndexerResult $item The content item to index.
* @param string $format The format of the content. [optional]
*
* @return integer The ID of the record in the links table.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract public function index($item, $format = 'html');
/**
* Method to remove a link from the index.
*
* @param integer $linkId The id of the link.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract public function remove($linkId);
/**
* Method to optimize the index. We use this method to remove unused terms
* and any other optimizations that might be necessary.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract public function optimize();
/**
* Method to get a content item's signature.
*
* @param object $item The content item to index.
*
* @return string The content item's signature.
*
* @since 2.5
*/
protected static function getSignature($item)
{
// Get the indexer state.
$state = self::getState();
// Get the relevant configuration variables.
$config = array();
$config[] = $state->weights;
$config[] = $state->options->get('stem', 1);
$config[] = $state->options->get('stemmer', 'porter_en');
return md5(serialize(array($item, $config)));
}
/**
* Method to parse input, tokenize it, and then add it to the database.
*
* @param mixed $input String or resource to use as input. A resource
* input will automatically be chunked to conserve
* memory. Strings will be chunked if longer than
* 2K in size.
* @param integer $context The context of the input. See context constants.
* @param string $lang The language of the input.
* @param string $format The format of the input.
*
* @return integer The number of tokens extracted from the input.
*
* @since 2.5
*/
protected function tokenizeToDB($input, $context, $lang, $format)
{
$count = 0;
$buffer = null;
if (!empty($input))
{
// If the input is a resource, batch the process out.
if (is_resource($input))
{
// Batch the process out to avoid memory limits.
while (!feof($input))
{
// Read into the buffer.
$buffer .= fread($input, 2048);
/*
* If we haven't reached the end of the file, seek to the last
* space character and drop whatever is after that to make sure
* we didn't truncate a term while reading the input.
*/
if (!feof($input))
{
// Find the last space character.
$ls = strrpos($buffer, ' ');
// Adjust string based on the last space character.
if ($ls)
{
// Truncate the string to the last space character.
$string = substr($buffer, 0, $ls);
// Adjust the buffer based on the last space for the next iteration and trim.
$buffer = JString::trim(substr($buffer, $ls));
}
// No space character was found.
else
{
$string = $buffer;
}
}
// We've reached the end of the file, so parse whatever remains.
else
{
$string = $buffer;
}
// Parse the input.
$string = FinderIndexerHelper::parse($string, $format);
// Check the input.
if (empty($string))
{
continue;
}
// Tokenize the input.
$tokens = FinderIndexerHelper::tokenize($string, $lang);
// Add the tokens to the database.
$count += $this->addTokensToDB($tokens, $context);
// Check if we're approaching the memory limit of the token table.
if ($count > self::$state->options->get('memory_table_limit', 30000))
{
self::toggleTables(false);
}
unset($string);
unset($tokens);
}
}
// If the input is greater than 2K in size, it is more efficient to
// batch out the operation into smaller chunks of work.
elseif (strlen($input) > 2048)
{
$start = 0;
$end = strlen($input);
$chunk = 2048;
/*
* As it turns out, the complex regular expressions we use for
* sanitizing input are not very efficient when given large
* strings. It is much faster to process lots of short strings.
*/
while ($start < $end)
{
// Setup the string.
$string = substr($input, $start, $chunk);
// Find the last space character if we aren't at the end.
$ls = (($start + $chunk) < $end ? strrpos($string, ' ') : false);
// Truncate to the last space character.
if ($ls !== false)
{
$string = substr($string, 0, $ls);
}
// Adjust the start position for the next iteration.
$start += ($ls !== false ? ($ls + 1 - $chunk) + $chunk : $chunk);
// Parse the input.
$string = FinderIndexerHelper::parse($string, $format);
// Check the input.
if (empty($string))
{
continue;
}
// Tokenize the input.
$tokens = FinderIndexerHelper::tokenize($string, $lang);
// Add the tokens to the database.
$count += $this->addTokensToDB($tokens, $context);
// Check if we're approaching the memory limit of the token table.
if ($count > self::$state->options->get('memory_table_limit', 30000))
{
self::toggleTables(false);
}
}
}
else
{
// Parse the input.
$input = FinderIndexerHelper::parse($input, $format);
// Check the input.
if (empty($input))
{
return $count;
}
// Tokenize the input.
$tokens = FinderIndexerHelper::tokenize($input, $lang);
// Add the tokens to the database.
$count = $this->addTokensToDB($tokens, $context);
}
}
return $count;
}
/**
* Method to add a set of tokens to the database.
*
* @param mixed $tokens An array or single FinderIndexerToken object.
* @param mixed $context The context of the tokens. See context constants. [optional]
*
* @return integer The number of tokens inserted into the database.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract protected function addTokensToDB($tokens, $context = '');
/**
* Method to switch the token tables from Memory tables to MyISAM tables
* when they are close to running out of memory.
*
* @param boolean $memory Flag to control how they should be toggled.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
abstract protected function toggleTables($memory);
}

View File

@ -0,0 +1,132 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Parser base class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
abstract class FinderIndexerParser
{
/**
* Method to get a parser, creating it if necessary.
*
* @param string $format The type of parser to load.
*
* @return FinderIndexerParser A FinderIndexerParser instance.
*
* @since 2.5
* @throws Exception on invalid parser.
*/
public static function getInstance($format)
{
static $instances;
// Only create one parser for each format.
if (isset($instances[$format]))
{
return $instances[$format];
}
// Create an array of instances if necessary.
if (!is_array($instances))
{
$instances = array();
}
// Setup the adapter for the parser.
$format = JFilterInput::getInstance()->clean($format, 'cmd');
$path = __DIR__ . '/parser/' . $format . '.php';
$class = 'FinderIndexerParser' . ucfirst($format);
// Check if a parser exists for the format.
if (file_exists($path))
{
// Instantiate the parser.
include_once $path;
$instances[$format] = new $class;
}
else
{
// Throw invalid format exception.
throw new Exception(JText::sprintf('COM_FINDER_INDEXER_INVALID_PARSER', $format));
}
return $instances[$format];
}
/**
* Method to parse input and extract the plain text. Because this method is
* called from both inside and outside the indexer, it needs to be able to
* batch out its parsing functionality to deal with the inefficiencies of
* regular expressions. We will parse recursively in 2KB chunks.
*
* @param string $input The input to parse.
*
* @return string The plain text input.
*
* @since 2.5
*/
public function parse($input)
{
$return = null;
// Parse the input in batches if bigger than 2KB.
if (strlen($input) > 2048)
{
$start = 0;
$end = strlen($input);
$chunk = 2048;
while ($start < $end)
{
// Setup the string.
$string = substr($input, $start, $chunk);
// Find the last space character if we aren't at the end.
$ls = (($start + $chunk) < $end ? strrpos($string, ' ') : false);
// Truncate to the last space character.
if ($ls !== false)
{
$string = substr($string, 0, $ls);
}
// Adjust the start position for the next iteration.
$start += ($ls !== false ? ($ls + 1 - $chunk) + $chunk : $chunk);
// Parse the chunk.
$return .= $this->process($string);
}
}
// The input is less than 2KB so we can parse it efficiently.
else
{
// Parse the chunk.
$return .= $this->process($input);
}
return $return;
}
/**
* Method to process input and extract the plain text.
*
* @param string $input The input to process.
*
* @return string The plain text input.
*
* @since 2.5
*/
abstract protected function process($input);
}

View File

@ -0,0 +1,52 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerParser', dirname(__DIR__) . '/parser.php');
/**
* HTML Parser class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerParserHtml extends FinderIndexerParser
{
/**
* Method to process HTML input and extract the plain text.
*
* @param string $input The input to process.
*
* @return string The plain text input.
*
* @since 2.5
*/
protected function process($input)
{
// Strip invalid UTF-8 characters.
$input = iconv("utf-8", "utf-8//IGNORE", $input);
// Strip all script tags.
$input = preg_replace('#<script[^>]*>.*?</script>#si', ' ', $input);
// Deal with spacing issues in the input.
$input = str_replace('>', '> ', $input);
$input = str_replace(array('&nbsp;', '&#160;'), ' ', $input);
$input = trim(preg_replace('#\s+#u', ' ', $input));
// Strip the tags from the input and decode entities.
$input = strip_tags($input);
$input = html_entity_decode($input, ENT_QUOTES, 'UTF-8');
$input = trim(preg_replace('#\s+#u', ' ', $input));
return $input;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,44 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerParser', dirname(__DIR__) . '/parser.php');
/**
* RTF Parser class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerParserRtf extends FinderIndexerParser
{
/**
* Method to process RTF input and extract the plain text.
*
* @param string $input The input to process.
*
* @return string The plain text input.
*
* @since 2.5
*/
protected function process($input)
{
// Remove embedded pictures.
$input = preg_replace('#{\\\pict[^}]*}#mis', '', $input);
// Remove control characters.
$input = str_replace(array('{', '}', "\\\n"), array(' ', ' ', "\n"), $input);
$input = preg_replace('#\\\([^;]+?);#mis', ' ', $input);
$input = preg_replace('#\\\[\'a-zA-Z0-9]+#mis', ' ', $input);
return $input;
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerParser', dirname(__DIR__) . '/parser.php');
/**
* Text Parser class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerParserTxt extends FinderIndexerParser
{
/**
* Method to process Text input and extract the plain text.
*
* @param string $input The input to process.
*
* @return string The plain text input.
*
* @since 2.5
*/
protected function process($input)
{
return $input;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,431 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexer', __DIR__ . '/indexer.php');
/**
* Result class for the Finder indexer package.
*
* This class uses magic __get() and __set() methods to prevent properties
* being added that might confuse the system. All properties not explicitly
* declared will be pushed into the elements array and can be accessed
* explicitly using the getElement() method.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerResult
{
/**
* An array of extra result properties.
*
* @var array
* @since 2.5
*/
protected $elements = array();
/**
* This array tells the indexer which properties should be indexed and what
* weights to use for those properties.
*
* @var array
* @since 2.5
*/
protected $instructions = array(
FinderIndexer::TITLE_CONTEXT => array('title', 'subtitle', 'id'),
FinderIndexer::TEXT_CONTEXT => array('summary', 'body'),
FinderIndexer::META_CONTEXT => array('meta', 'list_price', 'sale_price'),
FinderIndexer::PATH_CONTEXT => array('path', 'alias'),
FinderIndexer::MISC_CONTEXT => array('comments')
);
/**
* The indexer will use this data to create taxonomy mapping entries for
* the item so that it can be filtered by type, label, category,
* or whatever.
*
* @var array
* @since 2.5
*/
protected $taxonomy = array();
/**
* The content URL.
*
* @var string
* @since 2.5
*/
public $url;
/**
* The content route.
*
* @var string
* @since 2.5
*/
public $route;
/**
* The content title.
*
* @var string
* @since 2.5
*/
public $title;
/**
* The content description.
*
* @var string
* @since 2.5
*/
public $description;
/**
* The published state of the result.
*
* @var integer
* @since 2.5
*/
public $published;
/**
* The content published state.
*
* @var integer
* @since 2.5
*/
public $state;
/**
* The content access level.
*
* @var integer
* @since 2.5
*/
public $access;
/**
* The content language.
*
* @var string
* @since 2.5
*/
public $language = '*';
/**
* The publishing start date.
*
* @var string
* @since 2.5
*/
public $publish_start_date;
/**
* The publishing end date.
*
* @var string
* @since 2.5
*/
public $publish_end_date;
/**
* The generic start date.
*
* @var string
* @since 2.5
*/
public $start_date;
/**
* The generic end date.
*
* @var string
* @since 2.5
*/
public $end_date;
/**
* The item list price.
*
* @var mixed
* @since 2.5
*/
public $list_price;
/**
* The item sale price.
*
* @var mixed
* @since 2.5
*/
public $sale_price;
/**
* The content type id. This is set by the adapter.
*
* @var integer
* @since 2.5
*/
public $type_id;
/**
* The default language for content.
*
* @var string
* @since 3.0.2
*/
public $defaultLanguage;
/**
* Constructor
*
* @since 3.0.3
*/
public function __construct()
{
$this->defaultLanguage = JComponentHelper::getParams('com_languages')->get('site', 'en-GB');
}
/**
* The magic set method is used to push additional values into the elements
* array in order to preserve the cleanliness of the object.
*
* @param string $name The name of the element.
* @param mixed $value The value of the element.
*
* @return void
*
* @since 2.5
*/
public function __set($name, $value)
{
$this->elements[$name] = $value;
}
/**
* The magic get method is used to retrieve additional element values
* from the elements array.
*
* @param string $name The name of the element.
*
* @return mixed The value of the element if set, null otherwise.
*
* @since 2.5
*/
public function __get($name)
{
// Get the element value if set.
if (array_key_exists($name, $this->elements))
{
return $this->elements[$name];
}
else
{
return null;
}
}
/**
* The magic isset method is used to check the state of additional element
* values in the elements array.
*
* @param string $name The name of the element.
*
* @return boolean True if set, false otherwise.
*
* @since 2.5
*/
public function __isset($name)
{
return isset($this->elements[$name]);
}
/**
* The magic unset method is used to unset additional element values in the
* elements array.
*
* @param string $name The name of the element.
*
* @return void
*
* @since 2.5
*/
public function __unset($name)
{
unset($this->elements[$name]);
}
/**
* Method to retrieve additional element values from the elements array.
*
* @param string $name The name of the element.
*
* @return mixed The value of the element if set, null otherwise.
*
* @since 2.5
*/
public function getElement($name)
{
// Get the element value if set.
if (array_key_exists($name, $this->elements))
{
return $this->elements[$name];
}
else
{
return null;
}
}
/**
* Method to set additional element values in the elements array.
*
* @param string $name The name of the element.
* @param mixed $value The value of the element.
*
* @return void
*
* @since 2.5
*/
public function setElement($name, $value)
{
$this->elements[$name] = $value;
}
/**
* Method to get all processing instructions.
*
* @return array An array of processing instructions.
*
* @since 2.5
*/
public function getInstructions()
{
return $this->instructions;
}
/**
* Method to add a processing instruction for an item property.
*
* @param string $group The group to associate the property with.
* @param string $property The property to process.
*
* @return void
*
* @since 2.5
*/
public function addInstruction($group, $property)
{
// Check if the group exists. We can't add instructions for unknown groups.
if (array_key_exists($group, $this->instructions))
{
// Check if the property exists in the group.
if (!in_array($property, $this->instructions[$group]))
{
// Add the property to the group.
$this->instructions[$group][] = $property;
}
}
}
/**
* Method to remove a processing instruction for an item property.
*
* @param string $group The group to associate the property with.
* @param string $property The property to process.
*
* @return void
*
* @since 2.5
*/
public function removeInstruction($group, $property)
{
// Check if the group exists. We can't remove instructions for unknown groups.
if (array_key_exists($group, $this->instructions))
{
// Search for the property in the group.
$key = array_search($property, $this->instructions[$group]);
// If the property was found, remove it.
if ($key !== false)
{
unset($this->instructions[$group][$key]);
}
}
}
/**
* Method to get the taxonomy maps for an item.
*
* @param string $branch The taxonomy branch to get. [optional]
*
* @return array An array of taxonomy maps.
*
* @since 2.5
*/
public function getTaxonomy($branch = null)
{
// Get the taxonomy branch if available.
if ($branch !== null && isset($this->taxonomy[$branch]))
{
// Filter the input.
$branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $branch);
return $this->taxonomy[$branch];
}
return $this->taxonomy;
}
/**
* Method to add a taxonomy map for an item.
*
* @param string $branch The title of the taxonomy branch to add the node to.
* @param string $title The title of the taxonomy node.
* @param integer $state The published state of the taxonomy node. [optional]
* @param integer $access The access level of the taxonomy node. [optional]
*
* @return void
*
* @since 2.5
*/
public function addTaxonomy($branch, $title, $state = 1, $access = 1)
{
// Filter the input.
$branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,]+#mui', ' ', $branch);
// Create the taxonomy node.
$node = new JObject;
$node->title = $title;
$node->state = (int) $state;
$node->access = (int) $access;
// Add the node to the taxonomy branch.
$this->taxonomy[$branch][$node->title] = $node;
}
/**
* Method to set the item language
*
* @return void
*
* @since 3.0
*/
public function setLanguage()
{
if ($this->language == '*' || $this->language == '')
{
$this->language = $this->defaultLanguage;
}
}
}

View File

@ -0,0 +1,87 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Stemmer base class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
abstract class FinderIndexerStemmer
{
/**
* An internal cache of stemmed tokens.
*
* @var array
* @since 2.5
*/
public $cache = array();
/**
* Method to get a stemmer, creating it if necessary.
*
* @param string $adapter The type of stemmer to load.
*
* @return FinderIndexerStemmer A FinderIndexerStemmer instance.
*
* @since 2.5
* @throws Exception on invalid stemmer.
*/
public static function getInstance($adapter)
{
static $instances;
// Only create one stemmer for each adapter.
if (isset($instances[$adapter]))
{
return $instances[$adapter];
}
// Create an array of instances if necessary.
if (!is_array($instances))
{
$instances = array();
}
// Setup the adapter for the stemmer.
$adapter = JFilterInput::getInstance()->clean($adapter, 'cmd');
$path = __DIR__ . '/stemmer/' . $adapter . '.php';
$class = 'FinderIndexerStemmer' . ucfirst($adapter);
// Check if a stemmer exists for the adapter.
if (file_exists($path))
{
// Instantiate the stemmer.
include_once $path;
$instances[$adapter] = new $class;
}
else
{
// Throw invalid adapter exception.
throw new Exception(JText::sprintf('COM_FINDER_INDEXER_INVALID_STEMMER', $adapter));
}
return $instances[$adapter];
}
/**
* Method to stem a token and return the root.
*
* @param string $token The token to stem.
* @param string $lang The language of the token.
*
* @return string The root token.
*
* @since 2.5
*/
abstract public function stem($token, $lang);
}

View File

@ -0,0 +1,264 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerStemmer', dirname(__DIR__) . '/stemmer.php');
/**
* French stemmer class for Smart Search indexer.
*
* First contributed by Eric Sanou (bobotche@hotmail.fr)
* This class is inspired in Alexis Ulrich's French stemmer code (http://alx2002.free.fr)
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 3.0
*/
class FinderIndexerStemmerFr extends FinderIndexerStemmer
{
/**
* Stemming rules.
*
* @var array
* @since 3.0
*/
private static $_stemRules = null;
/**
* Method to stem a token and return the root.
*
* @param string $token The token to stem.
* @param string $lang The language of the token.
*
* @return string The root token.
*
* @since 3.0
*/
public function stem($token, $lang)
{
// Check if the token is long enough to merit stemming.
if (strlen($token) <= 2)
{
return $token;
}
// Check if the language is French or All.
if ($lang !== 'fr' && $lang != '*')
{
return $token;
}
// Stem the token if it is not in the cache.
if (!isset($this->cache[$lang][$token]))
{
// Stem the token.
$result = static::_getStem($token);
// Add the token to the cache.
$this->cache[$lang][$token] = $result;
}
return $this->cache[$lang][$token];
}
/**
* French stemmer rules variables.
*
* @return array The rules
*
* @since 3.0
*/
protected static function getStemRules()
{
if (static::$_stemRules)
{
return static::$_stemRules;
}
$vars = array();
// French accented letters in ISO-8859-1 encoding
$vars['accents'] = chr(224) . chr(226) . chr(232) . chr(233) . chr(234) . chr(235) . chr(238) . chr(239) . chr(244) . chr(251) . chr(249) . chr(231);
// The rule patterns include all accented words for french language
$vars['rule_pattern'] = "/^([a-z" . $vars['accents'] . "]*)(\*){0,1}(\d)([a-z" . $vars['accents'] . "]*)([.|>])/";
// French vowels (including y) in ISO-8859-1 encoding
$vars['vowels'] = chr(97) . chr(224) . chr(226) . chr(101) . chr(232) . chr(233) . chr(234) . chr(235) . chr(105) . chr(238) . chr(239) . chr(111) . chr(244) . chr(117) . chr(251) . chr(249) . chr(121);
// The French rules in ISO-8859-1 encoding
$vars['rules'] = array(
'esre1>', 'esio1>', 'siol1.', 'siof0.', 'sioe0.', 'sio3>', 'st1>', 'sf1>', 'sle1>', 'slo1>', 's' . chr(233) . '1>', chr(233) . 'tuae5.',
chr(233) . 'tuae2.', 'tnia0.', 'tniv1.', 'tni3>', 'suor1.', 'suo0.', 'sdrail5.', 'sdrai4.', 'er' . chr(232) . 'i1>', 'sesue3x>',
'esuey5i.', 'esue2x>', 'se1>', 'er' . chr(232) . 'g3.', 'eca1>', 'esiah0.', 'esi1>', 'siss2.', 'sir2>', 'sit2>', 'egan' . chr(233) . '1.',
'egalli6>', 'egass1.', 'egas0.', 'egat3.', 'ega3>', 'ette4>', 'ett2>', 'etio1.', 'tio' . chr(231) . '4c.', 'tio0.', 'et1>', 'eb1>',
'snia1>', 'eniatnau8>', 'eniatn4.', 'enia1>', 'niatnio3.', 'niatg3.', 'e' . chr(233) . '1>', chr(233) . 'hcat1.', chr(233) . 'hca4.',
chr(233) . 'tila5>', chr(233) . 'tici5.', chr(233) . 'tir1.', chr(233) . 'ti3>', chr(233) . 'gan1.', chr(233) . 'ga3>',
chr(233) . 'tehc1.', chr(233) . 'te3>', chr(233) . 'it0.', chr(233) . '1>', 'eire4.', 'eirue5.', 'eio1.', 'eia1.', 'ei1>', 'eng1.',
'xuaessi7.', 'xuae1>', 'uaes0.', 'uae3.', 'xuave2l.', 'xuav2li>', 'xua3la>', 'ela1>', 'lart2.', 'lani2>', 'la' . chr(233) . '2>',
'siay4i.', 'siassia7.', 'siarv1*.', 'sia1>', 'tneiayo6i.', 'tneiay6i.', 'tneiassia9.', 'tneiareio7.', 'tneia5>', 'tneia4>', 'tiario4.',
'tiarim3.', 'tiaria3.', 'tiaris3.', 'tiari5.', 'tiarve6>', 'tiare5>', 'iare4>', 'are3>', 'tiay4i.', 'tia3>', 'tnay4i.',
'em' . chr(232) . 'iu5>', 'em' . chr(232) . 'i4>', 'tnaun3.', 'tnauqo3.', 'tnau4>', 'tnaf0.', 'tnat' . chr(233) . '2>', 'tna3>', 'tno3>',
'zeiy4i.', 'zey3i.', 'zeire5>', 'zeird4.', 'zeirio4.', 'ze2>', 'ssiab0.', 'ssia4.', 'ssi3.', 'tnemma6>', 'tnemesuey9i.', 'tnemesue8>',
'tnemevi7.', 'tnemessia5.', 'tnemessi8.', 'tneme5>', 'tnemia4.', 'tnem' . chr(233) . '5>', 'el2l>', 'lle3le>', 'let' . chr(244) . '0.',
'lepp0.', 'le2>', 'srei1>', 'reit3.', 'reila2.', 'rei3>', 'ert' . chr(226) . 'e5.', 'ert' . chr(226) . chr(233) . '1.',
'ert' . chr(226) . '4.', 'drai4.', 'erdro0.', 'erute5.', 'ruta0.', 'eruta1.', 'erutiov1.', 'erub3.', 'eruh3.', 'erul3.', 'er2r>', 'nn1>',
'r' . chr(232) . 'i3.', 'srev0.', 'sr1>', 'rid2>', 're2>', 'xuei4.', 'esuei5.', 'lbati3.', 'lba3>', 'rueis0.', 'ruehcn4.', 'ecirta6.',
'ruetai6.', 'rueta5.', 'rueir0.', 'rue3>', 'esseti6.', 'essere6>', 'esserd1.', 'esse4>', 'essiab1.', 'essia5.', 'essio1.', 'essi4.',
'essal4.', 'essa1>', 'ssab1.', 'essurp1.', 'essu4.', 'essi1.', 'ssor1.', 'essor2.', 'esso1>', 'ess2>', 'tio3.', 'r' . chr(232) . 's2re.',
'r' . chr(232) . '0e.', 'esn1.', 'eu1>', 'sua0.', 'su1>', 'utt1>', 'tu' . chr(231) . '3c.', 'u' . chr(231) . '2c.', 'ur1.', 'ehcn2>',
'ehcu1>', 'snorr3.', 'snoru3.', 'snorua3.', 'snorv3.', 'snorio4.', 'snori5.', 'snore5>', 'snortt4>', 'snort' . chr(238) . 'a7.', 'snort3.',
'snor4.', 'snossi6.', 'snoire6.', 'snoird5.', 'snoitai7.', 'snoita6.', 'snoits1>', 'noits0.', 'snoi4>', 'noitaci7>', 'noitai6.', 'noita5.',
'noitu4.', 'noi3>', 'snoya0.', 'snoy4i.', 'sno' . chr(231) . 'a1.', 'sno' . chr(231) . 'r1.', 'snoe4.', 'snosiar1>', 'snola1.', 'sno3>',
'sno1>', 'noll2.', 'tnennei4.', 'ennei2>', 'snei1>', 'sne' . chr(233) . '1>', 'enne' . chr(233) . '5e.', 'ne' . chr(233) . '3e.', 'neic0.',
'neiv0.', 'nei3.', 'sc1.', 'sd1.', 'sg1.', 'sni1.', 'tiu0.', 'ti2.', 'sp1>', 'sna1>', 'sue1.', 'enn2>', 'nong2.', 'noss2.', 'rioe4.',
'riot0.', 'riorc1.', 'riovec5.', 'rio3.', 'ric2.', 'ril2.', 'tnerim3.', 'tneris3>', 'tneri5.', 't' . chr(238) . 'a3.', 'riss2.',
't' . chr(238) . '2.', 't' . chr(226) . '2>', 'ario2.', 'arim1.', 'ara1.', 'aris1.', 'ari3.', 'art1>', 'ardn2.', 'arr1.', 'arua1.',
'aro1.', 'arv1.', 'aru1.', 'ar2.', 'rd1.', 'ud1.', 'ul1.', 'ini1.', 'rin2.', 'tnessiab3.', 'tnessia7.', 'tnessi6.', 'tnessni4.', 'sini2.',
'sl1.', 'iard3.', 'iario3.', 'ia2>', 'io0.', 'iule2.', 'i1>', 'sid2.', 'sic2.', 'esoi4.', 'ed1.', 'ai2>', 'a1>', 'adr1.',
'tner' . chr(232) . '5>', 'evir1.', 'evio4>', 'evi3.', 'fita4.', 'fi2>', 'enie1.', 'sare4>', 'sari4>', 'sard3.', 'sart2>', 'sa2.',
'tnessa6>', 'tnessu6>', 'tnegna3.', 'tnegi3.', 'tneg0.', 'tneru5>', 'tnemg0.', 'tnerni4.', 'tneiv1.', 'tne3>', 'une1.', 'en1>', 'nitn2.',
'ecnay5i.', 'ecnal1.', 'ecna4.', 'ec1>', 'nn1.', 'rit2>', 'rut2>', 'rud2.', 'ugn1>', 'eg1>', 'tuo0.', 'tul2>', 't' . chr(251) . '2>',
'ev1>', 'v' . chr(232) . '2ve>', 'rtt1>', 'emissi6.', 'em1.', 'ehc1.', 'c' . chr(233) . 'i2c' . chr(232) . '.', 'libi2l.', 'llie1.',
'liei4i.', 'xuev1.', 'xuey4i.', 'xueni5>', 'xuell4.', 'xuere5.', 'xue3>', 'rb' . chr(233) . '3rb' . chr(232) . '.', 'tur2.',
'rir' . chr(233) . '4re.', 'rir2.', 'c' . chr(226) . '2ca.', 'snu1.', 'rt' . chr(238) . 'a4.', 'long2.', 'vec2.', chr(231) . '1c>',
'ssilp3.', 'silp2.', 't' . chr(232) . 'hc2te.', 'n' . chr(232) . 'm2ne.', 'llepp1.', 'tan2.', 'rv' . chr(232) . '3rve.',
'rv' . chr(233) . '3rve.', 'r' . chr(232) . '2re.', 'r' . chr(233) . '2re.', 't' . chr(232) . '2te.', 't' . chr(233) . '2te.', 'epp1.',
'eya2i.', 'ya1i.', 'yo1i.', 'esu1.', 'ugi1.', 'tt1.', 'end0.'
);
static::$_stemRules = $vars;
return static::$_stemRules;
}
/**
* Returns the number of the first rule from the rule number
* that can be applied to the given reversed input.
* returns -1 if no rule can be applied, ie the stem has been found
*
* @param string $reversed_input The input to check in reversed order
* @param integer $rule_number The rule number to check
*
* @return integer Number of the first rule
*
* @since 3.0
*/
private static function _getFirstRule($reversed_input, $rule_number)
{
$vars = static::getStemRules();
$nb_rules = count($vars['rules']);
for ($i = $rule_number; $i < $nb_rules; $i++)
{
// Gets the letters from the current rule
$rule = $vars['rules'][$i];
$rule = preg_replace($vars['rule_pattern'], "\\1", $rule);
if (strncasecmp(utf8_decode($rule), $reversed_input, strlen(utf8_decode($rule))) == 0)
{
return $i;
}
}
return -1;
}
/**
* Check the acceptability of a stem for French language
*
* @param string $reversed_stem The stem to check in reverse form
*
* @return boolean True if stem is acceptable
*
* @since 3.0
*/
private static function _check($reversed_stem)
{
$vars = static::getStemRules();
if (preg_match('/[' . $vars['vowels'] . ']$/', utf8_encode($reversed_stem)))
{
// If the form starts with a vowel then at least two letters must remain after stemming (e.g.: "etaient" --> "et")
return (strlen($reversed_stem) > 2);
}
else
{
// If the reversed stem starts with a consonant then at least two letters must remain after stemming
if (strlen($reversed_stem) <= 2)
{
return false;
}
// And at least one of these must be a vowel or "y"
return (preg_match('/[' . $vars['vowels'] . ']/', utf8_encode($reversed_stem)));
}
}
/**
* Paice/Husk stemmer which returns a stem for the given $input
*
* @param string $input The word for which we want the stem in UTF-8
*
* @return string The stem
*
* @since 3.0
*/
private static function _getStem($input)
{
$vars = static::getStemRules();
$intact = true;
$reversed_input = strrev(utf8_decode($input));
$rule_number = 0;
// This loop goes through the rules' array until it finds an ending one (ending by '.') or the last one ('end0.')
while (true)
{
$rule_number = static::_getFirstRule($reversed_input, $rule_number);
if ($rule_number == -1)
{
// No other rule can be applied => the stem has been found
break;
}
$rule = $vars['rules'][$rule_number];
preg_match($vars['rule_pattern'], $rule, $matches);
if (($matches[2] != '*') || ($intact))
{
$reversed_stem = utf8_decode($matches[4]) . substr($reversed_input, $matches[3], strlen($reversed_input) - $matches[3]);
if (self::_check($reversed_stem))
{
$reversed_input = $reversed_stem;
if ($matches[5] == '.')
{
break;
}
}
else
{
// Go to another rule
$rule_number++;
}
}
else
{
// Go to another rule
$rule_number++;
}
}
return utf8_encode(strrev($reversed_input));
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,448 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerStemmer', dirname(__DIR__) . '/stemmer.php');
/**
* Porter English stemmer class for the Finder indexer package.
*
* This class was adapted from one written by Richard Heyes.
* See copyright and link information above.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerStemmerPorter_En extends FinderIndexerStemmer
{
/**
* Regex for matching a consonant.
*
* @var string
* @since 2.5
*/
private static $_regex_consonant = '(?:[bcdfghjklmnpqrstvwxz]|(?<=[aeiou])y|^y)';
/**
* Regex for matching a vowel
*
* @var string
* @since 2.5
*/
private static $_regex_vowel = '(?:[aeiou]|(?<![aeiou])y)';
/**
* Method to stem a token and return the root.
*
* @param string $token The token to stem.
* @param string $lang The language of the token.
*
* @return string The root token.
*
* @since 2.5
*/
public function stem($token, $lang)
{
// Check if the token is long enough to merit stemming.
if (strlen($token) <= 2)
{
return $token;
}
// Check if the language is English or All.
if ($lang !== 'en' && $lang != '*')
{
return $token;
}
// Stem the token if it is not in the cache.
if (!isset($this->cache[$lang][$token]))
{
// Stem the token.
$result = $token;
$result = self::_step1ab($result);
$result = self::_step1c($result);
$result = self::_step2($result);
$result = self::_step3($result);
$result = self::_step4($result);
$result = self::_step5($result);
// Add the token to the cache.
$this->cache[$lang][$token] = $result;
}
return $this->cache[$lang][$token];
}
/**
* Step 1
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step1ab($word)
{
// Part a
if (substr($word, -1) == 's')
{
self::_replace($word, 'sses', 'ss')
or self::_replace($word, 'ies', 'i')
or self::_replace($word, 'ss', 'ss')
or self::_replace($word, 's', '');
}
// Part b
if (substr($word, -2, 1) != 'e' or !self::_replace($word, 'eed', 'ee', 0))
{
// First rule
$v = self::$_regex_vowel;
// Words ending with ing and ed
// Note use of && and OR, for precedence reasons
if (preg_match("#$v+#", substr($word, 0, -3)) && self::_replace($word, 'ing', '')
or preg_match("#$v+#", substr($word, 0, -2)) && self::_replace($word, 'ed', ''))
{
// If one of above two test successful
if (!self::_replace($word, 'at', 'ate') and !self::_replace($word, 'bl', 'ble') and !self::_replace($word, 'iz', 'ize'))
{
// Double consonant ending
if (self::_doubleConsonant($word) and substr($word, -2) != 'll' and substr($word, -2) != 'ss' and substr($word, -2) != 'zz')
{
$word = substr($word, 0, -1);
}
elseif (self::_m($word) == 1 and self::_cvc($word))
{
$word .= 'e';
}
}
}
}
return $word;
}
/**
* Step 1c
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step1c($word)
{
$v = self::$_regex_vowel;
if (substr($word, -1) == 'y' && preg_match("#$v+#", substr($word, 0, -1)))
{
self::_replace($word, 'y', 'i');
}
return $word;
}
/**
* Step 2
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step2($word)
{
switch (substr($word, -2, 1))
{
case 'a':
self::_replace($word, 'ational', 'ate', 0)
or self::_replace($word, 'tional', 'tion', 0);
break;
case 'c':
self::_replace($word, 'enci', 'ence', 0)
or self::_replace($word, 'anci', 'ance', 0);
break;
case 'e':
self::_replace($word, 'izer', 'ize', 0);
break;
case 'g':
self::_replace($word, 'logi', 'log', 0);
break;
case 'l':
self::_replace($word, 'entli', 'ent', 0)
or self::_replace($word, 'ousli', 'ous', 0)
or self::_replace($word, 'alli', 'al', 0)
or self::_replace($word, 'bli', 'ble', 0)
or self::_replace($word, 'eli', 'e', 0);
break;
case 'o':
self::_replace($word, 'ization', 'ize', 0)
or self::_replace($word, 'ation', 'ate', 0)
or self::_replace($word, 'ator', 'ate', 0);
break;
case 's':
self::_replace($word, 'iveness', 'ive', 0)
or self::_replace($word, 'fulness', 'ful', 0)
or self::_replace($word, 'ousness', 'ous', 0)
or self::_replace($word, 'alism', 'al', 0);
break;
case 't':
self::_replace($word, 'biliti', 'ble', 0)
or self::_replace($word, 'aliti', 'al', 0)
or self::_replace($word, 'iviti', 'ive', 0);
break;
}
return $word;
}
/**
* Step 3
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step3($word)
{
switch (substr($word, -2, 1))
{
case 'a':
self::_replace($word, 'ical', 'ic', 0);
break;
case 's':
self::_replace($word, 'ness', '', 0);
break;
case 't':
self::_replace($word, 'icate', 'ic', 0)
or self::_replace($word, 'iciti', 'ic', 0);
break;
case 'u':
self::_replace($word, 'ful', '', 0);
break;
case 'v':
self::_replace($word, 'ative', '', 0);
break;
case 'z':
self::_replace($word, 'alize', 'al', 0);
break;
}
return $word;
}
/**
* Step 4
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step4($word)
{
switch (substr($word, -2, 1))
{
case 'a':
self::_replace($word, 'al', '', 1);
break;
case 'c':
self::_replace($word, 'ance', '', 1)
or self::_replace($word, 'ence', '', 1);
break;
case 'e':
self::_replace($word, 'er', '', 1);
break;
case 'i':
self::_replace($word, 'ic', '', 1);
break;
case 'l':
self::_replace($word, 'able', '', 1)
or self::_replace($word, 'ible', '', 1);
break;
case 'n':
self::_replace($word, 'ant', '', 1)
or self::_replace($word, 'ement', '', 1)
or self::_replace($word, 'ment', '', 1)
or self::_replace($word, 'ent', '', 1);
break;
case 'o':
if (substr($word, -4) == 'tion' or substr($word, -4) == 'sion')
{
self::_replace($word, 'ion', '', 1);
}
else
{
self::_replace($word, 'ou', '', 1);
}
break;
case 's':
self::_replace($word, 'ism', '', 1);
break;
case 't':
self::_replace($word, 'ate', '', 1)
or self::_replace($word, 'iti', '', 1);
break;
case 'u':
self::_replace($word, 'ous', '', 1);
break;
case 'v':
self::_replace($word, 'ive', '', 1);
break;
case 'z':
self::_replace($word, 'ize', '', 1);
break;
}
return $word;
}
/**
* Step 5
*
* @param string $word The token to stem.
*
* @return string
*
* @since 2.5
*/
private static function _step5($word)
{
// Part a
if (substr($word, -1) == 'e')
{
if (self::_m(substr($word, 0, -1)) > 1)
{
self::_replace($word, 'e', '');
}
elseif (self::_m(substr($word, 0, -1)) == 1)
{
if (!self::_cvc(substr($word, 0, -1)))
{
self::_replace($word, 'e', '');
}
}
}
// Part b
if (self::_m($word) > 1 and self::_doubleConsonant($word) and substr($word, -1) == 'l')
{
$word = substr($word, 0, -1);
}
return $word;
}
/**
* Replaces the first string with the second, at the end of the string. If third
* arg is given, then the preceding string must match that m count at least.
*
* @param string &$str String to check
* @param string $check Ending to check for
* @param string $repl Replacement string
* @param integer $m Optional minimum number of m() to meet
*
* @return boolean Whether the $check string was at the end
* of the $str string. True does not necessarily mean
* that it was replaced.
*
* @since 2.5
*/
private static function _replace(&$str, $check, $repl, $m = null)
{
$len = 0 - strlen($check);
if (substr($str, $len) == $check)
{
$substr = substr($str, 0, $len);
if (is_null($m) or self::_m($substr) > $m)
{
$str = $substr . $repl;
}
return true;
}
return false;
}
/**
* m() measures the number of consonant sequences in $str. if c is
* a consonant sequence and v a vowel sequence, and <..> indicates arbitrary
* presence,
*
* <c><v> gives 0
* <c>vc<v> gives 1
* <c>vcvc<v> gives 2
* <c>vcvcvc<v> gives 3
*
* @param string $str The string to return the m count for
*
* @return integer The m count
*
* @since 2.5
*/
private static function _m($str)
{
$c = self::$_regex_consonant;
$v = self::$_regex_vowel;
$str = preg_replace("#^$c+#", '', $str);
$str = preg_replace("#$v+$#", '', $str);
preg_match_all("#($v+$c+)#", $str, $matches);
return count($matches[1]);
}
/**
* Returns true/false as to whether the given string contains two
* of the same consonant next to each other at the end of the string.
*
* @param string $str String to check
*
* @return boolean Result
*
* @since 2.5
*/
private static function _doubleConsonant($str)
{
$c = self::$_regex_consonant;
return preg_match("#$c{2}$#", $str, $matches) and $matches[0]{0} == $matches[0]{1};
}
/**
* Checks for ending CVC sequence where second C is not W, X or Y
*
* @param string $str String to check
*
* @return boolean Result
*
* @since 2.5
*/
private static function _cvc($str)
{
$c = self::$_regex_consonant;
$v = self::$_regex_vowel;
return preg_match("#($c$v$c)$#", $str, $matches) and strlen($matches[1]) == 3 and $matches[1]{2} != 'w' and $matches[1]{2} != 'x'
and $matches[1]{2} != 'y';
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderIndexerStemmer', dirname(__DIR__) . '/stemmer.php');
/**
* Snowball stemmer class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerStemmerSnowball extends FinderIndexerStemmer
{
/**
* Method to stem a token and return the root.
*
* @param string $token The token to stem.
* @param string $lang The language of the token.
*
* @return string The root token.
*
* @since 2.5
*/
public function stem($token, $lang)
{
// Language to use if All is specified.
static $defaultLang = '';
// If language is All then try to get site default language.
if ($lang == '*' && $defaultLang == '')
{
$languages = JLanguageHelper::getLanguages();
$defaultLang = isset($languages[0]->sef) ? $languages[0]->sef : '*';
$lang = $defaultLang;
}
// Stem the token if it is not in the cache.
if (!isset($this->cache[$lang][$token]))
{
// Get the stem function from the language string.
switch ($lang)
{
// Danish stemmer.
case 'da':
$function = 'stem_danish';
break;
// German stemmer.
case 'de':
$function = 'stem_german';
break;
// English stemmer.
default:
case 'en':
$function = 'stem_english';
break;
// Spanish stemmer.
case 'es':
$function = 'stem_spanish';
break;
// Finnish stemmer.
case 'fi':
$function = 'stem_finnish';
break;
// French stemmer.
case 'fr':
$function = 'stem_french';
break;
// Hungarian stemmer.
case 'hu':
$function = 'stem_hungarian';
break;
// Italian stemmer.
case 'it':
$function = 'stem_italian';
break;
// Norwegian stemmer.
case 'nb':
$function = 'stem_norwegian';
break;
// Dutch stemmer.
case 'nl':
$function = 'stem_dutch';
break;
// Portuguese stemmer.
case 'pt':
$function = 'stem_portuguese';
break;
// Romanian stemmer.
case 'ro':
$function = 'stem_romanian';
break;
// Russian stemmer.
case 'ru':
$function = 'stem_russian_unicode';
break;
// Swedish stemmer.
case 'sv':
$function = 'stem_swedish';
break;
// Turkish stemmer.
case 'tr':
$function = 'stem_turkish_unicode';
break;
}
// Stem the word if the stemmer method exists.
$this->cache[$lang][$token] = function_exists($function) ? $function($token) : $token;
}
return $this->cache[$lang][$token];
}
}

View File

@ -0,0 +1,375 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Stemmer base class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerTaxonomy
{
/**
* An internal cache of taxonomy branch data.
*
* @var array
* @since 2.5
*/
public static $branches = array();
/**
* An internal cache of taxonomy node data.
*
* @var array
* @since 2.5
*/
public static $nodes = array();
/**
* Method to add a branch to the taxonomy tree.
*
* @param string $title The title of the branch.
* @param integer $state The published state of the branch. [optional]
* @param integer $access The access state of the branch. [optional]
*
* @return integer The id of the branch.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function addBranch($title, $state = 1, $access = 1)
{
// Check to see if the branch is in the cache.
if (isset(self::$branches[$title]))
{
return self::$branches[$title]->id;
}
// Check to see if the branch is in the table.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' = 1')
->where($db->quoteName('title') . ' = ' . $db->quote($title));
$db->setQuery($query);
// Get the result.
$result = $db->loadObject();
// Check if the database matches the input data.
if (!empty($result) && $result->state == $state && $result->access == $access)
{
// The data matches, add the item to the cache.
self::$branches[$title] = $result;
return self::$branches[$title]->id;
}
/*
* The database did not match the input. This could be because the
* state has changed or because the branch does not exist. Let's figure
* out which case is true and deal with it.
*/
$branch = new JObject;
if (empty($result))
{
// Prepare the branch object.
$branch->parent_id = 1;
$branch->title = $title;
$branch->state = (int) $state;
$branch->access = (int) $access;
}
else
{
// Prepare the branch object.
$branch->id = (int) $result->id;
$branch->parent_id = (int) $result->parent_id;
$branch->title = $result->title;
$branch->state = (int) $result->title;
$branch->access = (int) $result->access;
$branch->ordering = (int) $result->ordering;
}
// Store the branch.
self::storeNode($branch);
// Add the branch to the cache.
self::$branches[$title] = $branch;
return self::$branches[$title]->id;
}
/**
* Method to add a node to the taxonomy tree.
*
* @param string $branch The title of the branch to store the node in.
* @param string $title The title of the node.
* @param integer $state The published state of the node. [optional]
* @param integer $access The access state of the node. [optional]
*
* @return integer The id of the node.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function addNode($branch, $title, $state = 1, $access = 1)
{
// Check to see if the node is in the cache.
if (isset(self::$nodes[$branch][$title]))
{
return self::$nodes[$branch][$title]->id;
}
// Get the branch id, insert it if it does not exist.
$branchId = self::addBranch($branch);
// Check to see if the node is in the table.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' = ' . $db->quote($branchId))
->where($db->quoteName('title') . ' = ' . $db->quote($title));
$db->setQuery($query);
// Get the result.
$result = $db->loadObject();
// Check if the database matches the input data.
if (!empty($result) && $result->state == $state && $result->access == $access)
{
// The data matches, add the item to the cache.
self::$nodes[$branch][$title] = $result;
return self::$nodes[$branch][$title]->id;
}
/*
* The database did not match the input. This could be because the
* state has changed or because the node does not exist. Let's figure
* out which case is true and deal with it.
*/
$node = new JObject;
if (empty($result))
{
// Prepare the node object.
$node->parent_id = (int) $branchId;
$node->title = $title;
$node->state = (int) $state;
$node->access = (int) $access;
}
else
{
// Prepare the node object.
$node->id = (int) $result->id;
$node->parent_id = (int) $result->parent_id;
$node->title = $result->title;
$node->state = (int) $result->title;
$node->access = (int) $result->access;
$node->ordering = (int) $result->ordering;
}
// Store the node.
self::storeNode($node);
// Add the node to the cache.
self::$nodes[$branch][$title] = $node;
return self::$nodes[$branch][$title]->id;
}
/**
* Method to add a map entry between a link and a taxonomy node.
*
* @param integer $linkId The link to map to.
* @param integer $nodeId The node to map to.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function addMap($linkId, $nodeId)
{
// Insert the map.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('link_id'))
->from($db->quoteName('#__finder_taxonomy_map'))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId)
->where($db->quoteName('node_id') . ' = ' . (int) $nodeId);
$db->setQuery($query);
$db->execute();
$id = (int) $db->loadResult();
$map = new JObject;
$map->link_id = (int) $linkId;
$map->node_id = (int) $nodeId;
if ($id)
{
$db->updateObject('#__finder_taxonomy_map', $map);
}
else
{
$db->insertObject('#__finder_taxonomy_map', $map);
}
return true;
}
/**
* Method to get the title of all taxonomy branches.
*
* @return array An array of branch titles.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function getBranchTitles()
{
$db = JFactory::getDbo();
// Set user variables
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
// Create a query to get the taxonomy branch titles.
$query = $db->getQuery(true)
->select($db->quoteName('title'))
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' = 1')
->where($db->quoteName('state') . ' = 1')
->where($db->quoteName('access') . ' IN (' . $groups . ')');
// Get the branch titles.
$db->setQuery($query);
$results = $db->loadColumn();
return $results;
}
/**
* Method to find a taxonomy node in a branch.
*
* @param string $branch The branch to search.
* @param string $title The title of the node.
*
* @return mixed Integer id on success, null on no match.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function getNodeByTitle($branch, $title)
{
$db = JFactory::getDbo();
// Set user variables
$user = JFactory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
// Create a query to get the node.
$query = $db->getQuery(true)
->select('t1.*')
->from($db->quoteName('#__finder_taxonomy') . ' AS t1')
->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS t2 ON t2.id = t1.parent_id')
->where('t1.access IN (' . $groups . ')')
->where('t1.state = 1')
->where('t1.title LIKE ' . $db->quote($db->escape($title) . '%'))
->where('t2.access IN (' . $groups . ')')
->where('t2.state = 1')
->where('t2.title = ' . $db->quote($branch));
// Get the node.
$db->setQuery($query, 0, 1);
$result = $db->loadObject();
return $result;
}
/**
* Method to remove map entries for a link.
*
* @param integer $linkId The link to remove.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function removeMaps($linkId)
{
// Delete the maps.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->delete($db->quoteName('#__finder_taxonomy_map'))
->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
$db->setQuery($query);
$db->execute();
return true;
}
/**
* Method to remove orphaned taxonomy nodes and branches.
*
* @return integer The number of deleted rows.
*
* @since 2.5
* @throws Exception on database error.
*/
public static function removeOrphanNodes()
{
// Delete all orphaned nodes.
$db = JFactory::getDbo();
$query = 'DELETE t' .
' FROM ' . $db->quoteName('#__finder_taxonomy') . ' AS t' .
' LEFT JOIN ' . $db->quoteName('#__finder_taxonomy_map') . ' AS m ON m.node_id = t.id' .
' WHERE t.parent_id > 1' .
' AND m.link_id IS NULL';
$db->setQuery($query);
$db->execute();
return $db->getAffectedRows();
}
/**
* Method to store a node to the database. This method will accept either a branch or a node.
*
* @param object $item The item to store.
*
* @return boolean True on success.
*
* @since 2.5
* @throws Exception on database error.
*/
protected static function storeNode($item)
{
$db = JFactory::getDbo();
// Check if we are updating or inserting the item.
if (empty($item->id))
{
// Insert the item.
$db->insertObject('#__finder_taxonomy', $item, 'id');
}
else
{
// Update the item.
$db->updateObject('#__finder_taxonomy', $item, 'id');
}
return true;
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Token class for the Finder indexer package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderIndexerToken
{
/**
* This is the term that will be referenced in the terms table and the
* mapping tables.
*
* @var string
* @since 2.5
*/
public $term;
/**
* The stem is used to match the root term and produce more potential
* matches when searching the index.
*
* @var string
* @since 2.5
*/
public $stem;
/**
* If the token is numeric, it is likely to be short and uncommon so the
* weight is adjusted to compensate for that situation.
*
* @var boolean
* @since 2.5
*/
public $numeric;
/**
* If the token is a common term, the weight is adjusted to compensate for
* the higher frequency of the term in relation to other terms.
*
* @var boolean
* @since 2.5
*/
public $common;
/**
* Flag for phrase tokens.
*
* @var boolean
* @since 2.5
*/
public $phrase;
/**
* The length is used to calculate the weight of the token.
*
* @var integer
* @since 2.5
*/
public $length;
/**
* The weight is calculated based on token size and whether the token is
* considered a common term.
*
* @var integer
* @since 2.5
*/
public $weight;
/**
* The simple language identifier for the token.
*
* @var string
* @since 2.5
*/
public $language;
/**
* Method to construct the token object.
*
* @param mixed $term The term as a string for words or an array for phrases.
* @param string $lang The simple language identifier.
* @param string $spacer The space separator for phrases. [optional]
*
* @since 2.5
*/
public function __construct($term, $lang, $spacer = ' ')
{
$this->language = $lang;
// Tokens can be a single word or an array of words representing a phrase.
if (is_array($term))
{
// Populate the token instance.
$this->term = implode($spacer, $term);
$this->stem = implode($spacer, array_map(array('FinderIndexerHelper', 'stem'), $term, array($lang)));
$this->numeric = false;
$this->common = false;
$this->phrase = true;
$this->length = JString::strlen($this->term);
/*
* Calculate the weight of the token.
*
* 1. Length of the token up to 30 and divide by 30, add 1.
* 2. Round weight to 4 decimal points.
*/
$this->weight = (($this->length >= 30 ? 30 : $this->length) / 30) + 1;
$this->weight = round($this->weight, 4);
}
else
{
// Populate the token instance.
$this->term = $term;
$this->stem = FinderIndexerHelper::stem($this->term, $lang);
$this->numeric = (is_numeric($this->term) || (bool) preg_match('#^[0-9,.\-\+]+$#', $this->term));
$this->common = $this->numeric ? false : FinderIndexerHelper::isCommon($this->term, $lang);
$this->phrase = false;
$this->length = JString::strlen($this->term);
/*
* Calculate the weight of the token.
*
* 1. Length of the token up to 15 and divide by 15.
* 2. If common term, divide weight by 8.
* 3. If numeric, multiply weight by 1.5.
* 4. Round weight to 4 decimal points.
*/
$this->weight = (($this->length >= 15 ? 15 : $this->length) / 15);
$this->weight = ($this->common == true ? $this->weight / 8 : $this->weight);
$this->weight = ($this->numeric == true ? $this->weight * 1.5 : $this->weight);
$this->weight = round($this->weight, 4);
}
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Finder language helper class.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderHelperLanguage
{
/**
* Method to return a plural language code for a taxonomy branch.
*
* @param string $branchName Branch title.
*
* @return string Language key code.
*
* @since 2.5
*/
public static function branchPlural($branchName)
{
$return = preg_replace('/[^a-zA-Z0-9]+/', '_', strtoupper($branchName));
return 'PLG_FINDER_QUERY_FILTER_BRANCH_P_' . $return;
}
/**
* Method to return a singular language code for a taxonomy branch.
*
* @param string $branchName Branch name.
*
* @return string Language key code.
*
* @since 2.5
*/
public static function branchSingular($branchName)
{
$return = preg_replace('/[^a-zA-Z0-9]+/', '_', strtoupper($branchName));
return 'PLG_FINDER_QUERY_FILTER_BRANCH_S_' . $return;
}
/**
* Method to load Smart Search component language file.
*
* @return void
*
* @since 2.5
*/
public static function loadComponentLanguage()
{
$lang = JFactory::getLanguage();
$lang->load('com_finder', JPATH_SITE);
}
/**
* Method to load Smart Search plug-in language files.
*
* @return void
*
* @since 2.5
*/
public static function loadPluginLanguage()
{
static $loaded = false;
// If already loaded, don't load again.
if ($loaded)
{
return;
}
$loaded = true;
// Get array of all the enabled Smart Search plug-in names.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('name')
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('finder'))
->where($db->quoteName('enabled') . ' = 1');
$db->setQuery($query);
$plugins = $db->loadObjectList();
if (empty($plugins))
{
return;
}
// Load generic language strings.
$lang = JFactory::getLanguage();
$lang->load('plg_content_finder', JPATH_ADMINISTRATOR);
// Load language file for each plug-in.
foreach ($plugins as $plugin)
{
$lang->load($plugin->name, JPATH_ADMINISTRATOR);
}
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,95 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_BASE') or die;
JFormHelper::loadFieldClass('list');
// Load the base adapter.
require_once JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php';
/**
* Renders a list of directories.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class JFormFieldDirectories extends JFormFieldList
{
/**
* The form field type.
*
* @var string
* @since 2.5
*/
protected $type = 'Directories';
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 2.5
*/
public function getOptions()
{
$values = array();
$options = array();
$exclude = array(
JPATH_ADMINISTRATOR,
JPATH_INSTALLATION,
JPATH_LIBRARIES,
JPATH_PLUGINS,
JPATH_SITE . '/cache',
JPATH_SITE . '/components',
JPATH_SITE . '/includes',
JPATH_SITE . '/language',
JPATH_SITE . '/modules',
JPATH_THEMES,
JFactory::getApplication()->getCfg('log_path'),
JFactory::getApplication()->getCfg('tmp_path')
);
// Get the base directories.
jimport('joomla.filesystem.folder');
$dirs = JFolder::folders(JPATH_SITE, '.', false, true);
// Iterate through the base directories and find the subdirectories.
foreach ($dirs as $dir)
{
// Check if the directory should be excluded.
if (in_array($dir, $exclude))
{
continue;
}
// Get the child directories.
$return = JFolder::folders($dir, '.', true, true);
// Merge the directories.
if (is_array($return))
{
$values[] = $dir;
$values = array_merge($values, $return);
}
}
// Convert the values to options.
foreach ($values as $value)
{
$options[] = JHtml::_('select.option', str_replace(JPATH_SITE . '/', '', $value), str_replace(JPATH_SITE . '/', '', $values));
}
// Add a null option.
array_unshift($options, JHtml::_('select.option', '', '- ' . JText::_('JNONE') . ' -'));
return $options;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,54 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_BASE') or die();
JFormHelper::loadFieldClass('list');
/**
* Search Filter field for the Finder package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class JFormFieldSearchFilter extends JFormFieldList
{
/**
* The form field type.
*
* @var string
* @since 2.5
*/
protected $type = 'SearchFilter';
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 2.5
*/
public function getOptions()
{
// Build the query.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('f.title AS text, f.filter_id AS value')
->from($db->quoteName('#__finder_filters') . ' AS f')
->where('f.state = 1')
->order('f.title ASC');
$db->setQuery($query);
$options = $db->loadObjectList();
array_unshift($options, JHtml::_('select.option', '', JText::_('COM_FINDER_SELECT_SEARCH_FILTER'), 'value', 'text'));
return $options;
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filter model class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelFilter extends JModelAdmin
{
/**
* The prefix to use with controller messages.
*
* @var string
* @since 2.5
*/
protected $text_prefix = 'COM_FINDER';
/**
* Model context string.
*
* @var string
* @since 2.5
*/
protected $context = 'com_finder.filter';
/**
* Custom clean cache method.
*
* @param string $group The component name. [optional]
* @param integer $client_id The client ID. [optional]
*
* @return void
*
* @since 2.5
*/
protected function cleanCache($group = 'com_finder', $client_id = 1)
{
parent::cleanCache($group, $client_id);
}
/**
* Method to get the filter data.
*
* @return mixed The filter data.
*
* @since 2.5
*/
public function getFilter()
{
$filter_id = (int) $this->getState('filter.id');
// Get a FinderTableFilter instance.
$filter = $this->getTable();
// Attempt to load the row.
$return = $filter->load($filter_id);
// Check for a database error.
if ($return === false && $filter->getError())
{
$this->setError($filter->getError());
return false;
}
// Process the filter data.
if (!empty($filter->data))
{
$filter->data = explode(',', $filter->data);
}
elseif (empty($filter->data))
{
$filter->data = array();
}
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
return $filter;
}
/**
* Method to get the record form.
*
* @param array $data Data for the form. [optional]
* @param boolean $loadData True if the form is to load its own data (default case), false if not. [optional]
*
* @return mixed A JForm object on success, false on failure
*
* @since 2.5
*/
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_finder.filter', 'filter', array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
return false;
}
return $form;
}
/**
* Returns a JTable object, always creating it.
*
* @param string $type The table type to instantiate. [optional]
* @param string $prefix A prefix for the table class name. [optional]
* @param array $config Configuration array for model. [optional]
*
* @return JTable A database object
*
* @since 2.5
*/
public function getTable($type = 'Filter', $prefix = 'FinderTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
/**
* Method to get the data that should be injected in the form.
*
* @return mixed The data for the form.
*
* @since 2.5
*/
protected function loadFormData()
{
// Check the session for previously entered form data.
$data = JFactory::getApplication()->getUserState('com_finder.edit.filter.data', array());
if (empty($data))
{
$data = $this->getItem();
}
$this->preprocessData('com_finder.filter', $data);
return $data;
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filters model class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelFilters extends JModelList
{
/**
* Constructor.
*
* @param array $config An associative array of configuration settings. [optional]
*
* @since 2.5
* @see JController
*/
public function __construct($config = array())
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'filter_id', 'a.filter_id',
'title', 'a.title',
'state', 'a.state',
'created_by_alias', 'a.created_by_alias',
'created', 'a.created',
'map_count', 'a.map_count'
);
}
parent::__construct($config);
}
/**
* Build an SQL query to load the list data.
*
* @return JDatabaseQuery A JDatabaseQuery object
*
* @since 2.5
*/
protected function getListQuery()
{
$db = $this->getDbo();
$query = $db->getQuery(true);
// Select all fields from the table.
$query->select('a.*')
->from($db->quoteName('#__finder_filters') . ' AS a');
// Join over the users for the checked out user.
$query->select('uc.name AS editor')
->join('LEFT', $db->quoteName('#__users') . ' AS uc ON uc.id=a.checked_out');
// Join over the users for the author.
$query->select('ua.name AS user_name')
->join('LEFT', $db->quoteName('#__users') . ' AS ua ON ua.id = a.created_by');
// Check for a search filter.
if ($this->getState('filter.search'))
{
$query->where('( a.title LIKE \'%' . $db->escape($this->getState('filter.search')) . '%\' )');
}
// If the model is set to check item state, add to the query.
if (is_numeric($this->getState('filter.state')))
{
$query->where('a.state = ' . (int) $this->getState('filter.state'));
}
// Add the list ordering clause.
$query->order($db->escape($this->getState('list.ordering') . ' ' . $db->escape($this->getState('list.direction'))));
return $query;
}
/**
* Method to get a store id based on model 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 A prefix for the store id. [optional]
*
* @return string A store id.
*
* @since 2.5
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.state');
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)
{
// Load the filter state.
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string');
$this->setState('filter.state', $state);
// Load the parameters.
$params = JComponentHelper::getParams('com_finder');
$this->setState('params', $params);
// List state information.
parent::populateState('a.title', 'asc');
}
}

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<form>
<fieldset>
<field name="filter_id" type="text" class="readonly" label="JGLOBAL_FIELD_ID_LABEL"
description ="JGLOBAL_FIELD_ID_DESC" size="10" default="0"
readonly="true" />
<field
name="title" type="text" id="title"
label="JGLOBAL_TITLE" description="COM_FINDER_FILTER_TITLE_DESCRIPTION"
size="30" default="" required="true" />
<field name="alias" type="text" label="JFIELD_ALIAS_LABEL"
description="JFIELD_ALIAS_DESC" class="inputbox" size="45" />
<field name="created" type="calendar" label="JGLOBAL_FIELD_CREATED_LABEL"
description="JGLOBAL_FIELD_CREATED_DESC" class="inputbox" size="22"
format="%Y-%m-%d %H:%M:%S" filter="user_utc" />
<field name="modified" type="calendar" class="readonly"
label="JGLOBAL_FIELD_MODIFIED_LABEL" description="COM_FINDER_FIELD_MODIFIED_DESCRIPTION"
size="22" readonly="true" format="%Y-%m-%d %H:%M:%S" filter="user_utc" />
<field name="created_by" type="user"
label="COM_FINDER_FIELD_CREATED_BY_LABEL" description="COM_FINDER_FIELD_CREATED_BY_DESC" />
<field name="created_by_alias" type="text"
label="COM_FINDER_FIELD_CREATED_BY_ALIAS_LABEL" description="COM_FINDER_FIELD_CREATED_BY_ALIAS_DESC"
class="inputbox" size="20" />
<field name="modified_by" type="user"
label="JGLOBAL_FIELD_MODIFIED_BY_LABEL"
class="readonly"
readonly="true"
filter="unset"
/>
<field name="checked_out" type="hidden" filter="unset" />
<field name="checked_out_time" type="hidden" filter="unset" />
<field name="state" type="list" label="JSTATUS"
description="JFIELD_PUBLISHED_DESC" class="inputbox"
filter="intval" size="1" default="1" >
<option value="1">
JPUBLISHED</option>
<option value="0">
JUNPUBLISHED</option>
</field>
<field
name="map_count" type="text" class="readonly"
label="COM_FINDER_FILTER_MAP_COUNT" description="COM_FINDER_FILTER_MAP_COUNT_DESCRIPTION"
size="10" default="0" readonly="true" />
</fieldset>
<fields name="params">
<field
name="w1"
type="list"
label="COM_FINDER_FILTER_WHEN_START_DATE_LABEL"
description="COM_FINDER_FILTER_WHEN_START_DATE_DESCRIPTION"
default=""
filter="string">
<option value="">JNONE</option>
<option value="-1">COM_FINDER_FILTER_WHEN_BEFORE</option>
<option value="0">COM_FINDER_FILTER_WHEN_EXACTLY</option>
<option value="1">COM_FINDER_FILTER_WHEN_AFTER</option>
</field>
<field name="d1" type="calendar" class="inputbox"
label="COM_FINDER_FILTER_START_DATE_LABEL" description="COM_FINDER_FILTER_START_DATE_DESCRIPTION"
size="22" format="%Y-%m-%d" filter="user_utc" />
<field
name="w2"
type="list"
label="COM_FINDER_FILTER_WHEN_END_DATE_LABEL"
description="COM_FINDER_FILTER_WHEN_END_DATE_DESCRIPTION"
default=""
filter="string">
<option value="">JNONE</option>
<option value="-1">COM_FINDER_FILTER_WHEN_BEFORE</option>
<option value="0">COM_FINDER_FILTER_WHEN_EXACTLY</option>
<option value="1">COM_FINDER_FILTER_WHEN_AFTER</option>
</field>
<field name="d2" type="calendar" class="inputbox"
label="COM_FINDER_FILTER_END_DATE_LABEL" description="COM_FINDER_FILTER_END_DATE_DESCRIPTION"
size="22" format="%Y-%m-%d" filter="user_utc" />
</fields>
</form>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,410 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Index model class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelIndex extends JModelList
{
/**
* The event to trigger after deleting the data.
*
* @var string
* @since 2.5
*/
protected $event_after_delete = 'onContentAfterDelete';
/**
* The event to trigger before deleting the data.
*
* @var string
* @since 2.5
*/
protected $event_before_delete = 'onContentBeforeDelete';
/**
* Constructor.
*
* @param array $config An associative array of configuration settings. [optional]
*
* @since 2.5
* @see JController
*/
public function __construct($config = array())
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'published', 'l.published',
'title', 'l.title',
'type_id', 'l.type_id',
'url', 'l.url',
'indexdate', 'l.indexdate'
);
}
parent::__construct($config);
}
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to delete the record. Defaults to the permission for the component.
*
* @since 2.5
*/
protected function canDelete($record)
{
$user = JFactory::getUser();
return $user->authorise('core.delete', $this->option);
}
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to change the state of the record. Defaults to the permission for the component.
*
* @since 2.5
*/
protected function canEditState($record)
{
$user = JFactory::getUser();
return $user->authorise('core.edit.state', $this->option);
}
/**
* Method to delete one or more records.
*
* @param array &$pks An array of record primary keys.
*
* @return boolean True if successful, false if an error occurs.
*
* @since 2.5
*/
public function delete(&$pks)
{
$dispatcher = JEventDispatcher::getInstance();
$pks = (array) $pks;
$table = $this->getTable();
// Include the content plugins for the on delete events.
JPluginHelper::importPlugin('content');
// Iterate the items to delete each one.
foreach ($pks as $i => $pk)
{
if ($table->load($pk))
{
if ($this->canDelete($table))
{
$context = $this->option . '.' . $this->name;
// Trigger the onContentBeforeDelete event.
$result = $dispatcher->trigger($this->event_before_delete, array($context, $table));
if (in_array(false, $result, true))
{
$this->setError($table->getError());
return false;
}
if (!$table->delete($pk))
{
$this->setError($table->getError());
return false;
}
// Trigger the onContentAfterDelete event.
$dispatcher->trigger($this->event_after_delete, array($context, $table));
}
else
{
// Prune items that you can't change.
unset($pks[$i]);
$error = $this->getError();
if ($error)
{
$this->setError($error);
}
else
{
$this->setError(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'));
}
}
}
else
{
$this->setError($table->getError());
return false;
}
}
// Clear the component's cache
$this->cleanCache();
return true;
}
/**
* Build an SQL query to load the list data.
*
* @return JDatabaseQuery A JDatabaseQuery object
*
* @since 2.5
*/
protected function getListQuery()
{
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('l.*')
->select('t.title AS t_title')
->from($db->quoteName('#__finder_links') . ' AS l')
->join('INNER', $db->quoteName('#__finder_types') . ' AS t ON t.id = l.type_id');
// Check the type filter.
if ($this->getState('filter.type'))
{
$query->where('l.type_id = ' . (int) $this->getState('filter.type'));
}
// Check for state filter.
if (is_numeric($this->getState('filter.state')))
{
$query->where('l.published = ' . (int) $this->getState('filter.state'));
}
// Check the search phrase.
if ($this->getState('filter.search') != '')
{
$search = $db->escape($this->getState('filter.search'));
$query->where(
'l.title LIKE ' . $db->quote('%' . $db->escape($search) . '%') . ' OR l.url LIKE ' . $db->quote('%' . $db->escape($search) . '%')
. ' OR l.indexdate LIKE ' . $db->quote('%' . $db->escape($search) . '%')
);
}
// Handle the list ordering.
$ordering = $this->getState('list.ordering');
$direction = $this->getState('list.direction');
if (!empty($ordering))
{
$query->order($db->escape($ordering) . ' ' . $db->escape($direction));
}
return $query;
}
/**
* Method to get the state of the Smart Search plug-ins.
*
* @return array Array of relevant plug-ins and whether they are enabled or not.
*
* @since 2.5
*/
public function getPluginState()
{
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('name, enabled')
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' IN(' . $db->quote('system') . ',' . $db->quote('content') . ')')
->where($db->quoteName('element') . ' = ' . $db->quote('finder'));
$db->setQuery($query);
$db->execute();
$plugins = $db->loadObjectList('name');
return $plugins;
}
/**
* Method to get a store id based on model 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 A prefix for the store id. [optional]
*
* @return string A store id.
*
* @since 2.5
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.state');
$id .= ':' . $this->getState('filter.type');
return parent::getStoreId($id);
}
/**
* Returns a JTable object, always creating it.
*
* @param string $type The table type to instantiate. [optional]
* @param string $prefix A prefix for the table class name. [optional]
* @param array $config Configuration array for model. [optional]
*
* @return JTable A database object
*
* @since 2.5
*/
public function getTable($type = 'Link', $prefix = 'FinderTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
/**
* Method to purge the index, deleting all links.
*
* @return boolean True on success, false on failure.
*
* @since 2.5
* @throws Exception on database error
*/
public function purge()
{
$db = $this->getDbo();
// Truncate the links table.
$db->truncateTable('#__finder_links');
// Truncate the links terms tables.
for ($i = 0; $i <= 15; $i++)
{
// Get the mapping table suffix.
$suffix = dechex($i);
$db->truncateTable('#__finder_links_terms' . $suffix);
}
// Truncate the terms table.
$db->truncateTable('#__finder_terms');
// Truncate the taxonomy map table.
$db->truncateTable('#__finder_taxonomy_map');
// Delete all the taxonomy nodes except the root.
$query = $db->getQuery(true)
->delete($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('id') . ' > 1');
$db->setQuery($query);
$db->execute();
// Truncate the tokens tables.
$db->truncateTable('#__finder_tokens');
// Truncate the tokens aggregate table.
$db->truncateTable('#__finder_tokens_aggregate');
return true;
}
/**
* 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)
{
// Load the filter state.
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string');
$this->setState('filter.state', $state);
$type = $this->getUserStateFromRequest($this->context . '.filter.type', 'filter_type', '', 'string');
$this->setState('filter.type', $type);
// Load the parameters.
$params = JComponentHelper::getParams('com_finder');
$this->setState('params', $params);
// List state information.
parent::populateState('l.title', 'asc');
}
/**
* Method to change the published state of one or more records.
*
* @param array &$pks A list of the primary keys to change.
* @param integer $value The value of the published state. [optional]
*
* @return boolean True on success.
*
* @since 2.5
*/
public function publish(&$pks, $value = 1)
{
$dispatcher = JEventDispatcher::getInstance();
$user = JFactory::getUser();
$table = $this->getTable();
$pks = (array) $pks;
// Include the content plugins for the change of state event.
JPluginHelper::importPlugin('content');
// Access checks.
foreach ($pks as $i => $pk)
{
$table->reset();
if ($table->load($pk))
{
if (!$this->canEditState($table))
{
// Prune items that you can't change.
unset($pks[$i]);
$this->setError(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
return false;
}
}
}
// Attempt to change the state of the records.
if (!$table->publish($pks, $value, $user->get('id')))
{
$this->setError($table->getError());
return false;
}
$context = $this->option . '.' . $this->name;
// Trigger the onContentChangeState event.
$result = $dispatcher->trigger('onContentChangeState', array($context, $pks, $value));
if (in_array(false, $result, true))
{
$this->setError($table->getError());
return false;
}
// Clear the component's cache
$this->cleanCache();
return true;
}
}

View File

@ -0,0 +1,21 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Indexer model class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelIndexer extends JModelLegacy
{
}

View File

@ -0,0 +1,355 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die();
/**
* Maps model for the Finder package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelMaps extends JModelList
{
/**
* Constructor.
*
* @param array $config An associative array of configuration settings. [optional]
*
* @since 2.5
* @see JController
*/
public function __construct($config = array())
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'state', 'a.state',
'title', 'a.title'
);
}
parent::__construct($config);
}
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to delete the record. Defaults to the permission for the component.
*
* @since 2.5
*/
protected function canDelete($record)
{
$user = JFactory::getUser();
return $user->authorise('core.delete', $this->option);
}
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to change the state of the record. Defaults to the permission for the component.
*
* @since 2.5
*/
protected function canEditState($record)
{
$user = JFactory::getUser();
return $user->authorise('core.edit.state', $this->option);
}
/**
* Method to delete one or more records.
*
* @param array &$pks An array of record primary keys.
*
* @return boolean True if successful, false if an error occurs.
*
* @since 2.5
*/
public function delete(&$pks)
{
$dispatcher = JEventDispatcher::getInstance();
$pks = (array) $pks;
$table = $this->getTable();
// Include the content plugins for the on delete events.
JPluginHelper::importPlugin('content');
// Iterate the items to delete each one.
foreach ($pks as $i => $pk)
{
if ($table->load($pk))
{
if ($this->canDelete($table))
{
$context = $this->option . '.' . $this->name;
// Trigger the onContentBeforeDelete event.
$result = $dispatcher->trigger('onContentBeforeDelete', array($context, $table));
if (in_array(false, $result, true))
{
$this->setError($table->getError());
return false;
}
if (!$table->delete($pk))
{
$this->setError($table->getError());
return false;
}
// Trigger the onContentAfterDelete event.
$dispatcher->trigger('onContentAfterDelete', array($context, $table));
}
else
{
// Prune items that you can't change.
unset($pks[$i]);
$error = $this->getError();
if ($error)
{
$this->setError($error);
}
else
{
$this->setError(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'));
}
}
}
else
{
$this->setError($table->getError());
return false;
}
}
// Clear the component's cache
$this->cleanCache();
return true;
}
/**
* Build an SQL query to load the list data.
*
* @return JDatabaseQuery A JDatabaseQuery object
*
* @since 2.5
*/
protected function getListQuery()
{
$db = $this->getDbo();
$query = $db->getQuery(true);
// Select all fields from the table.
$query->select('a.*')
->from($db->quoteName('#__finder_taxonomy') . ' AS a');
// Self-join to get children.
$query->select('COUNT(b.id) AS num_children')
->join('LEFT', $db->quoteName('#__finder_taxonomy') . ' AS b ON b.parent_id=a.id');
// Join to get the map links
$query->select('COUNT(c.node_id) AS num_nodes')
->join('LEFT', $db->quoteName('#__finder_taxonomy_map') . ' AS c ON c.node_id=a.id')
->group('a.id, a.parent_id, a.title, a.state, a.access, a.ordering');
// If the model is set to check item state, add to the query.
if (is_numeric($this->getState('filter.state')))
{
$query->where('a.state = ' . (int) $this->getState('filter.state'));
}
// Filter the maps over the branch if set.
$branch_id = $this->getState('filter.branch');
if (!empty($branch_id))
{
$query->where('a.parent_id = ' . (int) $branch_id);
}
// Filter the maps over the search string if set.
$search = $this->getState('filter.search');
if (!empty($search))
{
$query->where('a.title LIKE ' . $db->quote('%' . $search . '%'));
}
// Handle the list ordering.
$ordering = $this->getState('list.ordering');
$direction = $this->getState('list.direction');
if (!empty($ordering))
{
$query->order($db->escape($ordering) . ' ' . $db->escape($direction));
}
return $query;
}
/**
* Method to get a store id based on model 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 A prefix for the store id. [optional]
*
* @return string A store id.
*
* @since 2.5
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('filter.state');
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.branch');
return parent::getStoreId($id);
}
/**
* Returns a JTable object, always creating it.
*
* @param string $type The table type to instantiate. [optional]
* @param string $prefix A prefix for the table class name. [optional]
* @param array $config Configuration array for model. [optional]
*
* @return JTable A database object
*
* @since 2.5
*/
public function getTable($type = 'Map', $prefix = 'FinderTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
/**
* 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)
{
// Load the filter state.
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string');
$this->setState('filter.state', $state);
$branch = $this->getUserStateFromRequest($this->context . '.filter.branch', 'filter_branch', '1', 'string');
$this->setState('filter.branch', $branch);
// Load the parameters.
$params = JComponentHelper::getParams('com_finder');
$this->setState('params', $params);
// List state information.
parent::populateState('a.title', 'asc');
}
/**
* Method to change the published state of one or more records.
*
* @param array &$pks A list of the primary keys to change.
* @param integer $value The value of the published state. [optional]
*
* @return boolean True on success.
*
* @since 2.5
*/
public function publish(&$pks, $value = 1)
{
$dispatcher = JEventDispatcher::getInstance();
$user = JFactory::getUser();
$table = $this->getTable();
$pks = (array) $pks;
// Include the content plugins for the change of state event.
JPluginHelper::importPlugin('content');
// Access checks.
foreach ($pks as $i => $pk)
{
$table->reset();
if ($table->load($pk))
{
if (!$this->canEditState($table))
{
// Prune items that you can't change.
unset($pks[$i]);
$this->setError(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
return false;
}
}
}
// Attempt to change the state of the records.
if (!$table->publish($pks, $value, $user->get('id')))
{
$this->setError($table->getError());
return false;
}
$context = $this->option . '.' . $this->name;
// Trigger the onContentChangeState event.
$result = $dispatcher->trigger('onContentChangeState', array($context, $pks, $value));
if (in_array(false, $result, true))
{
$this->setError($table->getError());
return false;
}
// Clear the component's cache
$this->cleanCache();
return true;
}
/**
* Method to purge all maps from the taxonomy.
*
* @return boolean Returns true on success, false on failure.
*
* @since 2.5
*/
public function purge()
{
$db = $this->getDbo();
$query = $db->getQuery(true)
->delete($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' > 1');
$db->setQuery($query);
$db->execute();
$query->clear()
->delete($db->quoteName('#__finder_taxonomy_map'))
->where('1');
$db->setQuery($query);
$db->execute();
return true;
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Statistics model class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderModelStatistics extends JModelLegacy
{
/**
* Method to get the component statistics
*
* @return object The component statistics
*
* @since 2.5
*/
public function getData()
{
// Initialise
$db = $this->getDbo();
$query = $db->getQuery(true);
$data = new JObject;
$query->select('COUNT(term_id)')
->from($db->quoteName('#__finder_terms'));
$db->setQuery($query);
$data->term_count = $db->loadResult();
$query->clear()
->select('COUNT(link_id)')
->from($db->quoteName('#__finder_links'));
$db->setQuery($query);
$data->link_count = $db->loadResult();
$query->clear()
->select('COUNT(id)')
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' = 1');
$db->setQuery($query);
$data->taxonomy_branch_count = $db->loadResult();
$query->clear()
->select('COUNT(id)')
->from($db->quoteName('#__finder_taxonomy'))
->where($db->quoteName('parent_id') . ' > 1');
$db->setQuery($query);
$data->taxonomy_node_count = $db->loadResult();
$query->clear()
->select('t.title AS type_title, COUNT(a.link_id) AS link_count')
->from($db->quoteName('#__finder_links') . ' AS a')
->join('INNER', $db->quoteName('#__finder_types') . ' AS t ON t.id = a.type_id')
->group('a.type_id, t.title')
->order($db->quoteName('type_title'), 'ASC');
$db->setQuery($query);
$data->type_list = $db->loadObjectList();
return $data;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,547 @@
--
-- Table structure for table `#__finder_filters`
--
CREATE TABLE IF NOT EXISTS `#__finder_filters` (
`filter_id` int(10) unsigned NOT NULL auto_increment,
`title` varchar(255) NOT NULL,
`alias` varchar(255) NOT NULL,
`state` tinyint(1) NOT NULL default '1',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`created_by` int(10) unsigned NOT NULL,
`created_by_alias` varchar(255) NOT NULL,
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`modified_by` int(10) unsigned NOT NULL default '0',
`checked_out` int(10) unsigned NOT NULL default '0',
`checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00',
`map_count` int(10) unsigned NOT NULL default '0',
`data` text NOT NULL,
`params` mediumtext,
PRIMARY KEY (`filter_id`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links`
--
CREATE TABLE IF NOT EXISTS `#__finder_links` (
`link_id` int(10) unsigned NOT NULL auto_increment,
`url` varchar(255) NOT NULL,
`route` varchar(255) NOT NULL,
`title` varchar(255) default NULL,
`description` varchar(255) default NULL,
`indexdate` datetime NOT NULL default '0000-00-00 00:00:00',
`md5sum` varchar(32) default NULL,
`published` tinyint(1) NOT NULL default '1',
`state` int(5) default '1',
`access` int(5) default '0',
`language` varchar(8) NOT NULL,
`publish_start_date` datetime NOT NULL default '0000-00-00 00:00:00',
`publish_end_date` datetime NOT NULL default '0000-00-00 00:00:00',
`start_date` datetime NOT NULL default '0000-00-00 00:00:00',
`end_date` datetime NOT NULL default '0000-00-00 00:00:00',
`list_price` double unsigned NOT NULL default '0',
`sale_price` double unsigned NOT NULL default '0',
`type_id` int(11) NOT NULL,
`object` mediumblob NOT NULL,
PRIMARY KEY (`link_id`),
KEY `idx_type` (`type_id`),
KEY `idx_title` (`title`),
KEY `idx_md5` (`md5sum`),
KEY `idx_url` (`url`(75)),
KEY `idx_published_list` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`list_price`),
KEY `idx_published_sale` (`published`,`state`,`access`,`publish_start_date`,`publish_end_date`,`sale_price`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms0`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms0` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms1`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms1` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms2`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms2` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms3`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms3` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms4`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms4` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms5`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms5` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms6`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms6` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms7`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms7` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms8`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms8` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_terms9`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_terms9` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termsa`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termsa` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termsb`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termsb` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termsc`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termsc` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termsd`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termsd` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termse`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termse` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_links_termsf`
--
CREATE TABLE IF NOT EXISTS `#__finder_links_termsf` (
`link_id` int(10) unsigned NOT NULL,
`term_id` int(10) unsigned NOT NULL,
`weight` float unsigned NOT NULL,
PRIMARY KEY (`link_id`,`term_id`),
KEY `idx_term_weight` (`term_id`,`weight`),
KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_taxonomy`
--
CREATE TABLE IF NOT EXISTS `#__finder_taxonomy` (
`id` int(10) unsigned NOT NULL auto_increment,
`parent_id` int(10) unsigned NOT NULL default '0',
`title` varchar(255) NOT NULL,
`state` tinyint(1) unsigned NOT NULL default '1',
`access` tinyint(1) unsigned NOT NULL default '0',
`ordering` tinyint(1) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`),
KEY `state` (`state`),
KEY `ordering` (`ordering`),
KEY `access` (`access`),
KEY `idx_parent_published` (`parent_id`,`state`,`access`)
) DEFAULT CHARSET=utf8;
--
-- Dumping data for table `#__finder_taxonomy`
--
REPLACE INTO `#__finder_taxonomy` (`id`, `parent_id`, `title`, `state`, `access`, `ordering`) VALUES
(1, 0, 'ROOT', 0, 0, 0);
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_taxonomy_map`
--
CREATE TABLE IF NOT EXISTS `#__finder_taxonomy_map` (
`link_id` int(10) unsigned NOT NULL,
`node_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`link_id`,`node_id`),
KEY `link_id` (`link_id`),
KEY `node_id` (`node_id`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_terms`
--
CREATE TABLE IF NOT EXISTS `#__finder_terms` (
`term_id` int(10) unsigned NOT NULL auto_increment,
`term` varchar(75) NOT NULL,
`stem` varchar(75) NOT NULL,
`common` tinyint(1) unsigned NOT NULL default '0',
`phrase` tinyint(1) unsigned NOT NULL default '0',
`weight` float unsigned NOT NULL default '0',
`soundex` varchar(75) NOT NULL,
`links` int(10) NOT NULL default '0',
PRIMARY KEY (`term_id`),
UNIQUE KEY `idx_term` (`term`),
KEY `idx_term_phrase` (`term`,`phrase`),
KEY `idx_stem_phrase` (`stem`,`phrase`),
KEY `idx_soundex_phrase` (`soundex`,`phrase`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_terms_common`
--
CREATE TABLE IF NOT EXISTS `#__finder_terms_common` (
`term` varchar(75) NOT NULL,
`language` varchar(3) NOT NULL,
KEY `idx_word_lang` (`term`,`language`),
KEY `idx_lang` (`language`)
) DEFAULT CHARSET=utf8;
--
-- Dumping data for table `#__finder_terms_common`
--
REPLACE INTO `#__finder_terms_common` (`term`, `language`) VALUES
('a', 'en'),
('about', 'en'),
('after', 'en'),
('ago', 'en'),
('all', 'en'),
('am', 'en'),
('an', 'en'),
('and', 'en'),
('ani', 'en'),
('any', 'en'),
('are', 'en'),
('aren''t', 'en'),
('as', 'en'),
('at', 'en'),
('be', 'en'),
('but', 'en'),
('by', 'en'),
('for', 'en'),
('from', 'en'),
('get', 'en'),
('go', 'en'),
('how', 'en'),
('if', 'en'),
('in', 'en'),
('into', 'en'),
('is', 'en'),
('isn''t', 'en'),
('it', 'en'),
('its', 'en'),
('me', 'en'),
('more', 'en'),
('most', 'en'),
('must', 'en'),
('my', 'en'),
('new', 'en'),
('no', 'en'),
('none', 'en'),
('not', 'en'),
('noth', 'en'),
('nothing', 'en'),
('of', 'en'),
('off', 'en'),
('often', 'en'),
('old', 'en'),
('on', 'en'),
('onc', 'en'),
('once', 'en'),
('onli', 'en'),
('only', 'en'),
('or', 'en'),
('other', 'en'),
('our', 'en'),
('ours', 'en'),
('out', 'en'),
('over', 'en'),
('page', 'en'),
('she', 'en'),
('should', 'en'),
('small', 'en'),
('so', 'en'),
('some', 'en'),
('than', 'en'),
('thank', 'en'),
('that', 'en'),
('the', 'en'),
('their', 'en'),
('theirs', 'en'),
('them', 'en'),
('then', 'en'),
('there', 'en'),
('these', 'en'),
('they', 'en'),
('this', 'en'),
('those', 'en'),
('thus', 'en'),
('time', 'en'),
('times', 'en'),
('to', 'en'),
('too', 'en'),
('true', 'en'),
('under', 'en'),
('until', 'en'),
('up', 'en'),
('upon', 'en'),
('use', 'en'),
('user', 'en'),
('users', 'en'),
('veri', 'en'),
('version', 'en'),
('very', 'en'),
('via', 'en'),
('want', 'en'),
('was', 'en'),
('way', 'en'),
('were', 'en'),
('what', 'en'),
('when', 'en'),
('where', 'en'),
('whi', 'en'),
('which', 'en'),
('who', 'en'),
('whom', 'en'),
('whose', 'en'),
('why', 'en'),
('wide', 'en'),
('will', 'en'),
('with', 'en'),
('within', 'en'),
('without', 'en'),
('would', 'en'),
('yes', 'en'),
('yet', 'en'),
('you', 'en'),
('your', 'en'),
('yours', 'en');
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_tokens`
--
CREATE TABLE IF NOT EXISTS `#__finder_tokens` (
`term` varchar(75) NOT NULL,
`stem` varchar(75) NOT NULL,
`common` tinyint(1) unsigned NOT NULL default '0',
`phrase` tinyint(1) unsigned NOT NULL default '0',
`weight` float unsigned NOT NULL default '1',
`context` tinyint(1) unsigned NOT NULL default '2',
KEY `idx_word` (`term`),
KEY `idx_context` (`context`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_tokens_aggregate`
--
CREATE TABLE IF NOT EXISTS `#__finder_tokens_aggregate` (
`term_id` int(10) unsigned NOT NULL,
`map_suffix` char(1) NOT NULL,
`term` varchar(75) NOT NULL,
`stem` varchar(75) NOT NULL,
`common` tinyint(1) unsigned NOT NULL default '0',
`phrase` tinyint(1) unsigned NOT NULL default '0',
`term_weight` float unsigned NOT NULL,
`context` tinyint(1) unsigned NOT NULL default '2',
`context_weight` float unsigned NOT NULL,
`total_weight` float unsigned NOT NULL,
KEY `token` (`term`),
KEY `keyword_id` (`term_id`)
) DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `#__finder_types`
--
CREATE TABLE IF NOT EXISTS `#__finder_types` (
`id` int(10) unsigned NOT NULL auto_increment,
`title` varchar(100) NOT NULL,
`mime` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`)
) DEFAULT CHARSET=utf8;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
DROP TABLE IF EXISTS `#__finder_filters`;
DROP TABLE IF EXISTS `#__finder_links`;
DROP TABLE IF EXISTS `#__finder_links_terms0`;
DROP TABLE IF EXISTS `#__finder_links_terms1`;
DROP TABLE IF EXISTS `#__finder_links_terms2`;
DROP TABLE IF EXISTS `#__finder_links_terms3`;
DROP TABLE IF EXISTS `#__finder_links_terms4`;
DROP TABLE IF EXISTS `#__finder_links_terms5`;
DROP TABLE IF EXISTS `#__finder_links_terms6`;
DROP TABLE IF EXISTS `#__finder_links_terms7`;
DROP TABLE IF EXISTS `#__finder_links_terms8`;
DROP TABLE IF EXISTS `#__finder_links_terms9`;
DROP TABLE IF EXISTS `#__finder_links_termsa`;
DROP TABLE IF EXISTS `#__finder_links_termsb`;
DROP TABLE IF EXISTS `#__finder_links_termsc`;
DROP TABLE IF EXISTS `#__finder_links_termsd`;
DROP TABLE IF EXISTS `#__finder_links_termse`;
DROP TABLE IF EXISTS `#__finder_links_termsf`;
DROP TABLE IF EXISTS `#__finder_taxonomy`;
DROP TABLE IF EXISTS `#__finder_taxonomy_map`;
DROP TABLE IF EXISTS `#__finder_terms`;
DROP TABLE IF EXISTS `#__finder_terms_common`;
DROP TABLE IF EXISTS `#__finder_tokens`;
DROP TABLE IF EXISTS `#__finder_tokens_aggregate`;
DROP TABLE IF EXISTS `#__finder_types`;

View File

@ -0,0 +1,25 @@
DROP TABLE IF EXISTS "#__finder_filters";
DROP TABLE IF EXISTS "#__finder_links";
DROP TABLE IF EXISTS "#__finder_links_terms0";
DROP TABLE IF EXISTS "#__finder_links_terms1";
DROP TABLE IF EXISTS "#__finder_links_terms2";
DROP TABLE IF EXISTS "#__finder_links_terms3";
DROP TABLE IF EXISTS "#__finder_links_terms4";
DROP TABLE IF EXISTS "#__finder_links_terms5";
DROP TABLE IF EXISTS "#__finder_links_terms6";
DROP TABLE IF EXISTS "#__finder_links_terms7";
DROP TABLE IF EXISTS "#__finder_links_terms8";
DROP TABLE IF EXISTS "#__finder_links_terms9";
DROP TABLE IF EXISTS "#__finder_links_termsa";
DROP TABLE IF EXISTS "#__finder_links_termsb";
DROP TABLE IF EXISTS "#__finder_links_termsc";
DROP TABLE IF EXISTS "#__finder_links_termsd";
DROP TABLE IF EXISTS "#__finder_links_termse";
DROP TABLE IF EXISTS "#__finder_links_termsf";
DROP TABLE IF EXISTS "#__finder_taxonomy";
DROP TABLE IF EXISTS "#__finder_taxonomy_map";
DROP TABLE IF EXISTS "#__finder_terms";
DROP TABLE IF EXISTS "#__finder_terms_common";
DROP TABLE IF EXISTS "#__finder_tokens";
DROP TABLE IF EXISTS "#__finder_tokens_aggregate";
DROP TABLE IF EXISTS "#__finder_types";

View File

@ -0,0 +1,241 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filter table class for the Finder package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderTableFilter extends JTable
{
/**
* Constructor
*
* @param JDatabaseDriver &$db JDatabaseDriver connector object.
*
* @since 2.5
*/
public function __construct(&$db)
{
parent::__construct('#__finder_filters', 'filter_id', $db);
}
/**
* Method to bind an associative array or object to the JTable instance. This
* method only binds properties that are publicly accessible and optionally
* takes an array of properties to ignore when binding.
*
* @param array $array Named array
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding. [optional]
*
* @return mixed Null if operation was satisfactory, otherwise returns an error string
*
* @since 2.5
*/
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
return parent::bind($array, $ignore);
}
/**
* Method to perform sanity checks on the JTable instance properties to ensure
* they are safe to store in the database. Child classes should override this
* method to make sure the data they are storing in the database is safe and
* as expected before storage.
*
* @return boolean True if the instance is sane and able to be stored in the database.
*
* @since 2.5
*/
public function check()
{
if (trim($this->alias) == '')
{
$this->alias = $this->title;
}
$this->alias = JApplication::stringURLSafe($this->alias);
if (trim(str_replace('-', '', $this->alias)) == '')
{
$this->alias = JFactory::getDate()->format('Y-m-d-H-i-s');
}
// Check the end date is not earlier than start up.
if ($this->d2 > $this->_db->getNullDate() && $this->d2 < $this->d1)
{
// Swap the dates.
$temp = $this->d1;
$this->d1 = $this->d2;
$this->d2 = $temp;
}
return true;
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* @param mixed $pks An array of primary key values to update. If not
* set the instance property value is used. [optional]
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published] [optional]
* @param integer $userId The user id of the user performing the operation. [optional]
*
* @return boolean True on success.
*
* @since 2.5
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
return false;
}
}
// Build the WHERE clause for the primary keys.
$where = $k . '=' . implode(' OR ' . $k . '=', $pks);
// Determine if there is checkin support for the table.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
$checkin = '';
}
else
{
$checkin = ' AND (checked_out = 0 OR checked_out = ' . (int) $userId . ')';
}
// Update the publishing state for rows with the given primary keys.
$query = $this->_db->getQuery(true)
->update($this->_db->quoteName($this->_tbl))
->set($this->_db->quoteName('state') . ' = ' . (int) $state)
->where($where);
$this->_db->setQuery($query . $checkin);
try
{
$this->_db->execute();
}
catch (RuntimeException $e)
{
$this->setError($e->getMessage());
return false;
}
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin && (count($pks) == $this->_db->getAffectedRows()))
{
// Checkin the rows.
foreach ($pks as $pk)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->state = $state;
}
$this->setError('');
return true;
}
/**
* Method to store a row in the database from the JTable instance properties.
* If a primary key value is set the row with that primary key value will be
* updated with the instance property values. If no primary key value is set
* a new row will be inserted into the database with the properties from the
* JTable instance.
*
* @param boolean $updateNulls True to update fields even if they are null. [optional]
*
* @return boolean True on success.
*
* @since 2.5
*/
public function store($updateNulls = false)
{
$date = JFactory::getDate();
$user = JFactory::getUser();
if ($this->filter_id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else
{
// New item. A filter's created field can be set by the user,
// so we don't touch it if it is set.
if (!(int) $this->created)
{
$this->created = $date->toSql();
}
if (empty($this->created_by))
{
$this->created_by = $user->get('id');
}
}
if (is_array($this->data))
{
$this->map_count = count($this->data);
$this->data = implode(',', $this->data);
}
else
{
$this->map_count = 0;
$this->data = implode(',', array());
}
// Verify that the alias is unique
$table = JTable::getInstance('Filter', 'FinderTable');
if ($table->load(array('alias' => $this->alias)) && ($table->filter_id != $this->filter_id || $this->filter_id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS'));
return false;
}
return parent::store($updateNulls);
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,32 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Link table class for the Finder package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderTableLink extends JTable
{
/**
* Constructor
*
* @param JDatabaseDriver &$db JDatabaseDriver connector object.
*
* @since 2.5
*/
public function __construct(&$db)
{
parent::__construct('#__finder_links', 'link_id', $db);
}
}

View File

@ -0,0 +1,100 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Map table class for the Finder package.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderTableMap extends JTable
{
/**
* Constructor
*
* @param JDatabaseDriver &$db JDatabaseDriver connector object.
*
* @since 2.5
*/
public function __construct(&$db)
{
parent::__construct('#__finder_taxonomy', 'id', $db);
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* @param mixed $pks An array of primary key values to update. If not
* set the instance property value is used. [optional]
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published] [optional]
* @param integer $userId The user id of the user performing the operation. [optional]
*
* @return boolean True on success.
*
* @since 2.5
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
return false;
}
}
// Build the WHERE clause for the primary keys.
$where = $k . '=' . implode(' OR ' . $k . '=', $pks);
// Update the publishing state for rows with the given primary keys.
$query = $this->_db->getQuery(true)
->update($this->_db->quoteName($this->_tbl))
->set($this->_db->quoteName('state') . ' = ' . (int) $state)
->where($where);
$this->_db->setQuery($query);
try
{
$this->_db->execute();
}
catch (RuntimeException $e)
{
$this->setError($e->getMessage());
return false;
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->state = $state;
}
$this->setError('');
return true;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,86 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JHtml::_('behavior.formvalidation');
JHtml::_('behavior.keepalive');
JHtml::_('formbehavior.chosen', 'select');
?>
<form action="<?php echo JRoute::_('index.php?option=com_finder&view=filter&layout=edit&filter_id=' . (int) $this->item->filter_id); ?>" method="post" name="adminForm" id="adminForm" class="form-validate form-horizontal">
<fieldset>
<?php echo JHtml::_('bootstrap.startTabSet', 'myTab', array('active' => 'basic')); ?>
<?php echo JHtml::_('bootstrap.addTab', 'myTab', 'basic', JText::_('COM_FINDER_EDIT_FILTER', true)); ?>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('title'); ?></div>
<div class="controls"><?php echo $this->form->getInput('title'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('alias'); ?></div>
<div class="controls"><?php echo $this->form->getInput('alias'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('state'); ?></div>
<div class="controls"><?php echo $this->form->getInput('state'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('map_count'); ?></div>
<div class="controls"><?php echo $this->form->getInput('map_count'); ?></div>
</div>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php echo JHtml::_('bootstrap.addTab', 'myTab', 'params', JText::_('COM_FINDER_FILTER_FIELDSET_PARAMS', true)); ?>
<?php foreach ($this->form->getGroup('params') as $field) : ?>
<div class="control-group">
<?php if (!$field->hidden) : ?>
<div class="control-label"><?php echo $field->label; ?></div>
<?php endif; ?>
<div class="controls"><?php echo $field->input; ?></div>
</div>
<?php endforeach; ?>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php echo JHtml::_('bootstrap.addTab', 'myTab', 'details', JText::_('COM_FINDER_FILTER_FIELDSET_DETAILS', true)); ?>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('created_by'); ?></div>
<div class="controls"><?php echo $this->form->getInput('created_by'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('created_by_alias'); ?></div>
<div class="controls"><?php echo $this->form->getInput('created_by_alias'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('created'); ?></div>
<div class="controls"><?php echo $this->form->getInput('created'); ?></div>
</div>
<?php if ($this->item->modified_by) : ?>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('modified_by'); ?></div>
<div class="controls"><?php echo $this->form->getInput('modified_by'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('modified'); ?></div>
<div class="controls"><?php echo $this->form->getInput('modified'); ?></div>
</div>
<?php endif; ?>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php echo JHtml::_('bootstrap.endTabSet'); ?>
</fieldset>
<div id="finder-filter-window">
<?php echo JHtml::_('filter.slider', array('selected_nodes' => $this->filter->data)); ?>
</div>
<input type="hidden" name="task" value="" />
<input type="hidden" name="return" value="<?php echo JFactory::getApplication()->input->get('return', '', 'cmd');?>" />
<?php echo JHtml::_('form.token'); ?>
</form>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,114 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filter view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewFilter extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return mixed A string if successful, otherwise a JError object.
*
* @since 2.5
*/
public function display($tpl = null)
{
// Load the view data.
$this->filter = $this->get('Filter');
$this->item = $this->get('Item');
$this->form = $this->get('Form');
$this->state = $this->get('State');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors));
return false;
}
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::addIncludePath(JPATH_SITE . '/components/com_finder/helpers/html');
// Configure the toolbar.
$this->addToolbar();
parent::display($tpl);
}
/**
* Method to configure the toolbar for this view.
*
* @return void
*
* @since 2.5
*/
protected function addToolbar()
{
JFactory::getApplication()->input->set('hidemainmenu', true);
$user = JFactory::getUser();
$userId = $user->get('id');
$isNew = ($this->item->filter_id == 0);
$checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId);
$canDo = FinderHelper::getActions();
// Configure the toolbar.
JToolbarHelper::title(JText::_('COM_FINDER_FILTER_EDIT_TOOLBAR_TITLE'), 'finder');
// Set the actions for new and existing records.
if ($isNew)
{
// For new records, check the create permission.
if ($canDo->get('core.create'))
{
JToolbarHelper::apply('filter.apply');
JToolbarHelper::save('filter.save');
JToolbarHelper::save2new('filter.save2new');
}
JToolbarHelper::cancel('filter.cancel');
}
else
{
// Can't save the record if it's checked out.
if (!$checkedOut)
{
// Since it's an existing record, check the edit permission.
if ($canDo->get('core.edit'))
{
JToolbarHelper::apply('filter.apply');
JToolbarHelper::save('filter.save');
// We can save this record, but check the create permission to see if we can return to make a new one.
if ($canDo->get('core.create'))
{
JToolbarHelper::save2new('filter.save2new');
}
}
}
// If an existing item, can save as a copy
if ($canDo->get('core.create'))
{
JToolbarHelper::save2copy('filter.save2copy');
}
JToolbarHelper::cancel('filter.cancel', 'JTOOLBAR_CLOSE');
}
JToolbarHelper::divider();
JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS_EDIT');
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,161 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JHtml::_('formbehavior.chosen', 'select');
JHtml::_('bootstrap.tooltip');
$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');
?>
<script type="text/javascript">
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);
}
</script>
<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;?>
<div id="filter-bar" class="btn-toolbar">
<div class="filter-search btn-group pull-left">
<input type="text" name="filter_search" id="filter_search" placeholder="<?php echo JText::_('JSEARCH_FILTER'); ?>" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" class="hasTooltip" title="<?php echo JHtml::tooltipText('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
</div>
<div class="btn-group pull-left">
<button type="submit" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_SUBMIT'); ?>"><i class="icon-search"></i></button>
<button type="button" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_CLEAR'); ?>" onclick="document.id('filter_search').value='';this.form.submit();"><i class="icon-remove"></i></button>
</div>
</div>
<div class="clearfix"> </div>
<table class="table table-striped">
<thead>
<tr>
<th width="1%">
<?php echo JHtml::_('grid.checkall'); ?>
</th>
<th class="nowrap">
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th width="5%" class="nowrap">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
</th>
<th width="10%" class="center nowrap">
<?php echo JHtml::_('grid.sort', 'JGRID_HEADING_CREATED_BY', 'a.created_by_alias', $listDirn, $listOrder); ?>
</th>
<th width="10%" class="center nowrap">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_FILTER_TIMESTAMP', 'a.created', $listDirn, $listOrder); ?>
</th>
<th width="5%" class="center nowrap">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_FILTER_MAP_COUNT', 'a.map_count', $listDirn, $listOrder); ?>
</th>
<th width="1%" class="center nowrap">
<?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') || $item->checked_out == $user->get('id') || $item->checked_out == 0;
$canChange = $user->authorise('core.edit.state', 'com_finder') && $canCheckin;
?>
<tr class="row<?php echo $i % 2; ?>">
<td class="center">
<?php echo JHtml::_('grid.id', $i, $item->filter_id); ?>
</td>
<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->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>
<tfoot>
<tr>
<td colspan="7" class="nowrap">
<?php echo $this->pagination->getListFooter(); ?>
</td>
</tr>
</tfoot>
</table>
<input type="hidden" name="task" value="" />
<input type="hidden" name="boxchecked" value="0" />
<input type="hidden" name="filter_order" value="<?php echo $this->state->get('list.ordering'); ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $this->state->get('list.direction'); ?>" />
<?php echo JHtml::_('form.token'); ?>
</div>
</form>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,103 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Filters view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewFilters extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return mixed A string if successful, otherwise a JError object.
*
* @since 2.5
*/
public function display($tpl = null)
{
// Load the view data.
$this->items = $this->get('Items');
$this->pagination = $this->get('Pagination');
$this->total = $this->get('Total');
$this->state = $this->get('State');
FinderHelper::addSubmenu('filters');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors));
return false;
}
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
// Configure the toolbar.
$this->addToolbar();
$this->sidebar = JHtmlSidebar::render();
parent::display($tpl);
}
/**
* Method to configure the toolbar for this view.
*
* @return void
*
* @since 2.5
*/
protected function addToolbar()
{
$canDo = FinderHelper::getActions();
JToolbarHelper::title(JText::_('COM_FINDER_FILTERS_TOOLBAR_TITLE'), 'finder');
$toolbar = JToolbar::getInstance('toolbar');
if ($canDo->get('core.create'))
{
JToolbarHelper::addNew('filter.add');
JToolbarHelper::editList('filter.edit');
JToolbarHelper::divider();
}
if ($canDo->get('core.edit.state'))
{
JToolbarHelper::publishList('filters.publish');
JToolbarHelper::unpublishList('filters.unpublish');
JToolbarHelper::divider();
}
if ($canDo->get('core.delete'))
{
JToolbarHelper::deleteList('', 'filters.delete');
JToolbarHelper::divider();
}
if ($canDo->get('core.admin'))
{
JToolbarHelper::preferences('com_finder');
}
JToolbarHelper::divider();
$toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350);
JToolbarHelper::divider();
JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS');
JHtmlSidebar::setAction('index.php?option=com_finder&view=filters');
JHtmlSidebar::addFilter(
JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'),
'filter_state',
JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state'))
);
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,173 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JHtml::_('bootstrap.tooltip');
JHtml::_('formbehavior.chosen', 'select');
JHtml::_('bootstrap.popover');
$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');
?>
<script type="text/javascript">
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);
}
</script>
<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;?>
<div id="filter-bar" class="btn-toolbar">
<div class="filter-search btn-group pull-left">
<input type="text" name="filter_search" id="filter_search" placeholder="<?php echo JText::_('JSEARCH_FILTER'); ?>" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" class="hasTooltip" title="<?php echo JHtml::tooltipText('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
</div>
<div class="btn-group pull-left">
<button type="submit" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_SUBMIT'); ?>"><i class="icon-search"></i></button>
<button type="button" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_CLEAR'); ?>" onclick="document.id('filter_search').value='';this.form.submit();"><i class="icon-remove"></i></button>
</div>
</div>
<div class="clearfix"> </div>
<?php if (!$this->pluginState['plg_content_finder']->enabled) : ?>
<div class="alert fade in">
<button class="close" data-dismiss="alert">×</button>
<?php echo JText::_('COM_FINDER_INDEX_PLUGIN_CONTENT_NOT_ENABLED'); ?>
</div>
<?php endif; ?>
<table class="table table-striped">
<thead>
<tr>
<th width="1%" class="hidden-phone">
<?php echo JHtml::_('grid.checkall'); ?>
</th>
<th width="5%">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'l.published', $listDirn, $listOrder); ?>
</th>
<th>
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'l.title', $listDirn, $listOrder); ?>
</th>
<th class="hidden-phone"></th>
<th width="5%" class="hidden-phone">
<?php echo JHtml::_('grid.sort', 'COM_FINDER_INDEX_HEADING_INDEX_TYPE', 'l.type_id', $listDirn, $listOrder); ?>
</th>
<th width="15%" class="hidden-phone">
<?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="6">
<?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; ?>">
<td class="center hidden-phone">
<?php echo JHtml::_('grid.id', $i, $item->link_id); ?>
</td>
<td>
<?php echo JHtml::_('jgrid.published', $item->published, $i, 'index.', $canChange, 'cb'); ?>
</td>
<td>
<strong>
<?php echo $this->escape($item->title); ?>
</strong>
<small class="muted">
<?php
if (strlen($item->url) > 80)
{
echo substr($item->url, 0, 70) . '...';
} else {
echo $item->url;
}
?>
</small>
</td>
<td class="hidden-phone">
<?php if (intval($item->publish_start_date) or intval($item->publish_end_date) or intval($item->start_date) or intval($item->end_date)) : ?>
<i class="icon-calendar pull-right pop hasPopover" data-placement="left" title="<?php echo JText::_('JDETAILS');?>" data-content="<?php echo JText::sprintf('COM_FINDER_INDEX_DATE_INFO', $item->publish_start_date, $item->publish_end_date, $item->start_date, $item->end_date);?>"></i>
<?php endif; ?>
</td>
<td class="small nowrap hidden-phone">
<?php
$key = FinderHelperLanguage::branchSingular($item->t_title);
echo $lang->hasKey($key) ? JText::_($key) : $item->t_title;
?>
</td>
<td class="small nowrap hidden-phone">
<?php echo JHtml::_('date', $item->indexdate, JText::_('DATE_FORMAT_LC4')); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="6" class="nowrap">
<?php echo $this->pagination->getListFooter(); ?>
</td>
</tr>
</tfoot>
</table>
<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>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,116 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/language.php');
/**
* Index view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewIndex extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return mixed A string if successful, otherwise a JError object.
*
* @since 2.5
*/
public function display($tpl = null)
{
// Load plug-in language files.
FinderHelperLanguage::loadPluginLanguage();
$this->items = $this->get('Items');
$this->total = $this->get('Total');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
$this->pluginState = $this->get('pluginState');
FinderHelper::addSubmenu('index');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors));
return false;
}
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
// Configure the toolbar.
$this->addToolbar();
$this->sidebar = JHtmlSidebar::render();
parent::display($tpl);
}
/**
* Method to configure the toolbar for this view.
*
* @return void
*
* @since 2.5
*/
protected function addToolbar()
{
$canDo = FinderHelper::getActions();
JToolbarHelper::title(JText::_('COM_FINDER_INDEX_TOOLBAR_TITLE'), 'finder');
$toolbar = JToolbar::getInstance('toolbar');
$toolbar->appendButton(
'Popup', 'archive', 'COM_FINDER_INDEX', 'index.php?option=com_finder&view=indexer&tmpl=component', 500, 210, 0, 0,
'window.parent.location.reload()', 'COM_FINDER_HEADING_INDEXER'
);
if ($canDo->get('core.edit.state'))
{
JToolbarHelper::publishList('index.publish');
JToolbarHelper::unpublishList('index.unpublish');
}
if ($canDo->get('core.delete'))
{
JToolbarHelper::deleteList('', 'index.delete');
}
if ($canDo->get('core.edit.state'))
{
JToolbarHelper::trash('index.purge', 'COM_FINDER_INDEX_TOOLBAR_PURGE', false);
}
if ($canDo->get('core.admin'))
{
JToolbarHelper::preferences('com_finder');
}
$toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350);
JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_INDEXED_CONTENT');
JHtmlSidebar::setAction('index.php?option=com_finder&view=index');
JHtmlSidebar::addFilter(
JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'),
'filter_state',
JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state'))
);
JHtmlSidebar::addFilter(
JText::_('COM_FINDER_INDEX_TYPE_FILTER'),
'filter_type',
JHtml::_('select.options', JHtml::_('finder.typeslist'), 'value', 'text', $this->state->get('filter.type'))
);
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,27 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JHtml::_('behavior.framework');
JHtml::_('behavior.keepalive');
?>
<div id="finder-indexer-container">
<br /><br />
<h1 id="finder-progress-header"><?php echo JText::_('COM_FINDER_INDEXER_HEADER_INIT'); ?></h1>
<p id="finder-progress-message"><?php echo JText::_('COM_FINDER_INDEXER_MESSAGE_INIT'); ?></p>
<form id="finder-progress-form"></form>
<div id="finder-progress-container"></div>
<input id="finder-indexer-token" type="hidden" name="<?php echo JFactory::getSession()->getFormToken(); ?>" value="1" />
</div>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,39 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Indexer view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewIndexer extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return void
*
* @since 2.5
*/
public function display($tpl = null)
{
JHtml::_('behavior.framework');
JHtml::_('stylesheet', 'com_finder/indexer.css', false, true, false);
JHtml::_('script', 'com_finder/indexer.js', false, true);
JHtml::_('script', 'system/progressbar.js', true, true);
parent::display();
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,137 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JHtml::_('formbehavior.chosen', 'select');
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_MAPS_CONFIRM_DELETE_PROMPT');
?>
<script type="text/javascript">
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);
}
</script>
<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;?>
<div id="filter-bar" class="btn-toolbar">
<div class="filter-search btn-group pull-left">
<input type="text" name="filter_search" id="filter_search" placeholder="<?php echo JText::_('JSEARCH_FILTER'); ?>" value="<?php echo $this->escape($this->state->get('filter.search')); ?>" class="hasTooltip" title="<?php echo JHtml::tooltipText('COM_FINDER_FILTER_SEARCH_DESCRIPTION'); ?>" />
</div>
<div class="btn-group pull-left">
<button type="submit" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_SUBMIT'); ?>"><i class="icon-search"></i></button>
<button type="button" class="btn hasTooltip" title="<?php echo JHtml::tooltipText('JSEARCH_FILTER_CLEAR'); ?>" onclick="document.id('filter_search').value='';this.form.submit();"><i class="icon-remove"></i></button>
</div>
</div>
<div class="clearfix"> </div>
<table class="table table-striped">
<thead>
<tr>
<th width="1%">
<?php echo JHtml::_('grid.checkall'); ?>
</th>
<th class="nowrap">
<?php echo JHtml::_('grid.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th class="nowrap" width="10%">
<?php echo JHtml::_('grid.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
</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 if ($this->state->get('filter.branch') != 1) : ?>
<tr class="row1">
<td colspan="5" class="center">
<a href="#" onclick="document.id('filter_branch').value='1';document.adminForm.submit();">
<?php echo JText::_('COM_FINDER_MAPS_RETURN_TO_BRANCHES'); ?></a>
</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; ?>">
<td class="center">
<?php echo JHtml::_('grid.id', $i, $item->id); ?>
</td>
<td>
<?php
$key = FinderHelperLanguage::branchSingular($item->title);
$title = $lang->hasKey($key) ? JText::_($key) : $item->title;
?>
<?php if ($this->state->get('filter.branch') == 1 && $item->num_children) : ?>
<a href="#" onclick="document.id('filter_branch').value='<?php echo (int) $item->id;?>';document.adminForm.submit();" title="<?php echo JText::_('COM_FINDER_MAPS_BRANCH_LINK'); ?>">
<?php echo $this->escape($title); ?></a>
<?php else: ?>
<?php echo $this->escape(($title == '*') ? JText::_('JALL_LANGUAGE') : $title); ?>
<?php endif; ?>
<?php if ($item->num_children > 0) : ?>
<small>(<?php echo $item->num_children; ?>)</small>
<?php elseif ($item->num_nodes > 0) : ?>
<small>(<?php echo $item->num_nodes; ?>)</small>
<?php endif; ?>
<?php if ($this->escape(trim($title, '**')) == 'Language' && JLanguageMultilang::isEnabled()) : ?>
<strong><?php echo JText::_('COM_FINDER_MAPS_MULTILANG'); ?></strong>
<?php endif; ?>
</td>
<td class="center nowrap">
<?php echo JHtml::_('jgrid.published', $item->state, $i, 'maps.', $canChange, 'cb'); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="9" class="nowrap">
<?php echo $this->pagination->getListFooter(); ?>
</td>
</tr>
</tfoot>
</table>
<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 ?>" />
</div>
<?php echo JHtml::_('form.token'); ?>
</form>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,111 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/language.php');
/**
* Groups view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewMaps extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return mixed A string if successful, otherwise a JError object.
*
* @since 2.5
*/
public function display($tpl = null)
{
// Load plug-in language files.
FinderHelperLanguage::loadPluginLanguage();
// Load the view data.
$this->items = $this->get('Items');
$this->total = $this->get('Total');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
FinderHelper::addSubmenu('maps');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors));
return false;
}
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
// Prepare the view.
$this->addToolbar();
$this->sidebar = JHtmlSidebar::render();
parent::display($tpl);
}
/**
* Method to configure the toolbar for this view.
*
* @return void
*
* @since 2.5
*/
protected function addToolbar()
{
// For whatever reason, the helper isn't being found
include_once JPATH_COMPONENT . '/helpers/finder.php';
$canDo = FinderHelper::getActions();
JToolbarHelper::title(JText::_('COM_FINDER_MAPS_TOOLBAR_TITLE'), 'finder');
$toolbar = JToolbar::getInstance('toolbar');
if ($canDo->get('core.edit.state'))
{
JToolbarHelper::publishList('maps.publish');
JToolbarHelper::unpublishList('maps.unpublish');
JToolbarHelper::divider();
}
if ($canDo->get('core.delete'))
{
JToolbarHelper::deleteList('', 'maps.delete');
JToolbarHelper::divider();
}
if ($canDo->get('core.admin'))
{
JToolbarHelper::preferences('com_finder');
}
JToolbarHelper::divider();
$toolbar->appendButton('Popup', 'stats', 'COM_FINDER_STATISTICS', 'index.php?option=com_finder&view=statistics&tmpl=component', 550, 350);
JToolbarHelper::divider();
JToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_CONTENT_MAPS');
JHtmlSidebar::setAction('index.php?option=com_finder&view=maps');
JHtmlSidebar::addFilter(
'',
'filter_branch',
JHtml::_('select.options', JHtml::_('finder.mapslist'), 'value', 'text', $this->state->get('filter.branch')),
true
);
JHtmlSidebar::addFilter(
JText::_('COM_FINDER_INDEX_FILTER_BY_STATE'),
'filter_state',
JHtml::_('select.options', JHtml::_('finder.statelist'), 'value', 'text', $this->state->get('filter.state'))
);
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,52 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
?>
<h3>
<?php echo JText::_('COM_FINDER_STATISTICS_TITLE') ?>
</h3>
<div class="row-fluid">
<div class="span6">
<p class="tab-description"><?php echo JText::sprintf('COM_FINDER_STATISTICS_STATS_DESCRIPTION', number_format($this->data->term_count), number_format($this->data->link_count), number_format($this->data->taxonomy_node_count), number_format($this->data->taxonomy_branch_count)); ?></p>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th class="center">
<?php echo JText::_('COM_FINDER_STATISTICS_LINK_TYPE_HEADING');?>
</th>
<th class="center">
<?php echo JText::_('COM_FINDER_STATISTICS_LINK_TYPE_COUNT');?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->data->type_list as $type) :?>
<tr>
<td>
<?php echo $type->type_title;?>
</td>
<td>
<span class="badge badge-info"><?php echo number_format($type->link_count);?></span>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td>
<strong><?php echo JText::_('COM_FINDER_STATISTICS_LINK_TYPE_TOTAL'); ?></strong>
</td>
<td>
<span class="badge badge-info"><?php echo number_format($this->data->link_count); ?></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,44 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_finder
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('_JEXEC') or die;
/**
* Statistics view class for Finder.
*
* @package Joomla.Administrator
* @subpackage com_finder
* @since 2.5
*/
class FinderViewStatistics extends JViewLegacy
{
/**
* Method to display the view.
*
* @param string $tpl A template file to load. [optional]
*
* @return mixed A string if successful, otherwise a JError object.
*
* @since 2.5
*/
public function display($tpl = null)
{
// Load the view data.
$this->data = $this->get('Data');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors));
return false;
}
parent::display($tpl);
}
}