primo commit
This commit is contained in:
		| @ -0,0 +1,67 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Controller\BaseController; | ||||
| use Joomla\CMS\Router\Route; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Base controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class DisplayController extends BaseController | ||||
| { | ||||
|     /** | ||||
|      * The default view. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     protected $default_view = 'index'; | ||||
|  | ||||
|     /** | ||||
|      * Method to display a view. | ||||
|      * | ||||
|      * @param   boolean  $cachable   If true, the view output will be cached | ||||
|      * @param   array    $urlparams  An array of safe URL parameters and their variable types | ||||
|      *                   @see        \Joomla\CMS\Filter\InputFilter::clean() for valid values. | ||||
|      * | ||||
|      * @return  static|boolean   A Controller object to support chaining or false on failure. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function display($cachable = false, $urlparams = []) | ||||
|     { | ||||
|         $view     = $this->input->get('view', 'index', 'word'); | ||||
|         $layout   = $this->input->get('layout', 'index', 'word'); | ||||
|         $filterId = $this->input->get('filter_id', null, 'int'); | ||||
|  | ||||
|         // Check for edit form. | ||||
|         if ($view === 'filter' && $layout === 'edit' && !$this->checkEditId('com_finder.edit.filter', $filterId)) { | ||||
|             // Somehow the person just went to the form - we don't allow that. | ||||
|             if (!\count($this->app->getMessageQueue())) { | ||||
|                 $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $filterId), 'error'); | ||||
|             } | ||||
|  | ||||
|             $this->setRedirect(Route::_('index.php?option=com_finder&view=filters', false)); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return parent::display(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,230 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\Application\CMSWebApplicationInterface; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Controller\FormController; | ||||
| use Joomla\CMS\Router\Route; | ||||
| use Joomla\Utilities\ArrayHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Indexer controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FilterController extends FormController | ||||
| { | ||||
|     /** | ||||
|      * 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. | ||||
|         $this->checkToken(); | ||||
|  | ||||
|         /** @var \Joomla\Component\Finder\Administrator\Model\FilterModel $model */ | ||||
|         $model   = $this->getModel(); | ||||
|         $table   = $model->getTable(); | ||||
|         $data    = $this->input->post->get('jform', [], 'array'); | ||||
|         $checkin = $table->hasField('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 = $this->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->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId), 'error'); | ||||
|             $this->setRedirect(Route::_('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. | ||||
|                 if (!\count($this->app->getMessageQueue())) { | ||||
|                     $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->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->setMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error'); | ||||
|             $this->setRedirect(Route::_('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) { | ||||
|             $this->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) { | ||||
|                     $this->app->enqueueMessage($errors[$i]->getMessage(), CMSWebApplicationInterface::MSG_ERROR); | ||||
|                 } else { | ||||
|                     $this->app->enqueueMessage($errors[$i], CMSWebApplicationInterface::MSG_ERROR); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Save the data in the session. | ||||
|             $this->app->setUserState($context . '.data', $data); | ||||
|  | ||||
|             // Redirect back to the edit screen. | ||||
|             $this->setRedirect( | ||||
|                 Route::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key), false) | ||||
|             ); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Get and sanitize the filter data. | ||||
|         $validData['data'] = $this->input->post->get('t', [], 'array'); | ||||
|         $validData['data'] = array_unique($validData['data']); | ||||
|         $validData['data'] = ArrayHelper::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. | ||||
|             $this->app->setUserState($context . '.data', $validData); | ||||
|  | ||||
|             // Redirect back to the edit screen. | ||||
|             $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error'); | ||||
|             $this->setRedirect( | ||||
|                 Route::_('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. | ||||
|             $this->app->setUserState($context . '.data', $validData); | ||||
|  | ||||
|             // Check-in failed, so go back to the record and display a notice. | ||||
|             $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'error'); | ||||
|             $this->setRedirect('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId, $key)); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $this->setMessage( | ||||
|             Text::_( | ||||
|                 ($this->app->getLanguage()->hasKey($this->text_prefix . ($recordId === 0 && $this->app->isClient('site') ? '_SUBMIT' : '') . '_SAVE_SUCCESS') | ||||
|                 ? $this->text_prefix : 'JLIB_APPLICATION') . ($recordId === 0 && $this->app->isClient('site') ? '_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); | ||||
|                 $this->app->setUserState($context . '.data', null); | ||||
|                 $model->checkout($recordId); | ||||
|  | ||||
|                 // Redirect back to the edit screen. | ||||
|                 $this->setRedirect( | ||||
|                     Route::_('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); | ||||
|                 $this->app->setUserState($context . '.data', null); | ||||
|  | ||||
|                 // Redirect back to the edit screen. | ||||
|                 $this->setRedirect( | ||||
|                     Route::_('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); | ||||
|                 $this->app->setUserState($context . '.data', null); | ||||
|  | ||||
|                 // Redirect to the list screen. | ||||
|                 $this->setRedirect( | ||||
|                     Route::_('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; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\MVC\Controller\AdminController; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filters controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FiltersController extends AdminController | ||||
| { | ||||
|     /** | ||||
|      * The prefix to use with controller messages. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $text_prefix = 'COM_FINDER_FILTERS'; | ||||
|  | ||||
|     /** | ||||
|      * 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  \Joomla\CMS\MVC\Model\BaseDatabaseModel  The model. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getModel($name = 'Filter', $prefix = 'Administrator', $config = ['ignore_request' => true]) | ||||
|     { | ||||
|         return parent::getModel($name, $prefix, $config); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,107 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\Event\Finder\GarbageCollectionEvent; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Controller\AdminController; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Indexer; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Index controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class IndexController extends AdminController | ||||
| { | ||||
|     /** | ||||
|      * 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  \Joomla\CMS\MVC\Model\BaseDatabaseModel  The model. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getModel($name = 'Index', $prefix = 'Administrator', $config = ['ignore_request' => true]) | ||||
|     { | ||||
|         return parent::getModel($name, $prefix, $config); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to optimise the index by removing orphaned entries. | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   4.2.0 | ||||
|      */ | ||||
|     public function optimise() | ||||
|     { | ||||
|         $this->checkToken(); | ||||
|  | ||||
|         $dispatcher = $this->getDispatcher(); | ||||
|  | ||||
|         // Optimise the index by first running the garbage collection | ||||
|         PluginHelper::importPlugin('finder', null, true, $dispatcher); | ||||
|         $dispatcher->dispatch('onFinderGarbageCollection', new GarbageCollectionEvent('onFinderGarbageCollection', [])); | ||||
|  | ||||
|         // Now run the optimisation method from the indexer | ||||
|         $indexer = new Indexer(); | ||||
|         $indexer->optimize(); | ||||
|  | ||||
|         $message = Text::_('COM_FINDER_INDEX_OPTIMISE_FINISHED'); | ||||
|         $this->setRedirect('index.php?option=com_finder&view=index', $message); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to purge all indexed links from the database. | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function purge() | ||||
|     { | ||||
|         $this->checkToken(); | ||||
|  | ||||
|         // Remove the script time limit. | ||||
|         if (\function_exists('set_time_limit')) { | ||||
|             set_time_limit(0); | ||||
|         } | ||||
|  | ||||
|         /** @var \Joomla\Component\Finder\Administrator\Model\IndexModel $model */ | ||||
|         $model = $this->getModel('Index', 'Administrator'); | ||||
|  | ||||
|         // Attempt to purge the index. | ||||
|         $return = $model->purge(); | ||||
|  | ||||
|         if (!$return) { | ||||
|             $message = Text::_('COM_FINDER_INDEX_PURGE_FAILED', $model->getError()); | ||||
|             $this->setRedirect('index.php?option=com_finder&view=index', $message); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $message = Text::_('COM_FINDER_INDEX_PURGE_SUCCESS'); | ||||
|         $this->setRedirect('index.php?option=com_finder&view=index', $message); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,424 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Event\Finder\BeforeIndexEvent; | ||||
| use Joomla\CMS\Event\Finder\BuildIndexEvent; | ||||
| use Joomla\CMS\Event\Finder\StartIndexEvent; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\Log\Log; | ||||
| use Joomla\CMS\MVC\Controller\BaseController; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\CMS\Session\Session; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Adapter; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\DebugAdapter; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\DebugIndexer; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Indexer; | ||||
| use Joomla\Component\Finder\Administrator\Response\Response; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Indexer controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class IndexerController extends BaseController | ||||
| { | ||||
|     /** | ||||
|      * Method to start the indexer. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function start() | ||||
|     { | ||||
|         // Check for a valid token. If invalid, send a 403 with the error message. | ||||
|         if (!Session::checkToken('request')) { | ||||
|             static::sendResponse(new \Exception(Text::_('JINVALID_TOKEN_NOTICE'), 403)); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $params     = ComponentHelper::getParams('com_finder'); | ||||
|         $dispatcher = $this->getDispatcher(); | ||||
|  | ||||
|         if ($params->get('enable_logging', '0')) { | ||||
|             $options['format']    = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; | ||||
|             $options['text_file'] = 'indexer.php'; | ||||
|             Log::addLogger($options); | ||||
|         } | ||||
|  | ||||
|         // Log the start | ||||
|         try { | ||||
|             Log::add('Starting the indexer', Log::INFO); | ||||
|         } catch (\RuntimeException $exception) { | ||||
|             // Informational log only | ||||
|         } | ||||
|  | ||||
|         // We don't want this form to be cached. | ||||
|         $this->app->allowCache(false); | ||||
|  | ||||
|         // Put in a buffer to silence noise. | ||||
|         ob_start(); | ||||
|  | ||||
|         // Reset the indexer state. | ||||
|         Indexer::resetState(); | ||||
|  | ||||
|         // Import the finder plugins. | ||||
|         PluginHelper::importPlugin('finder', null, true, $dispatcher); | ||||
|  | ||||
|         // Add the indexer language to \JS | ||||
|         Text::script('COM_FINDER_AN_ERROR_HAS_OCCURRED'); | ||||
|         Text::script('COM_FINDER_NO_ERROR_RETURNED'); | ||||
|  | ||||
|         // Start the indexer. | ||||
|         try { | ||||
|             // Trigger the onStartIndex event. | ||||
|             $dispatcher->dispatch('onStartIndex', new StartIndexEvent('onStartIndex', [])); | ||||
|  | ||||
|             // Get the indexer state. | ||||
|             $state        = Indexer::getState(); | ||||
|             $state->start = 1; | ||||
|  | ||||
|             $output = ob_get_contents(); | ||||
|  | ||||
|             // Finder plugins should not create output of any kind. If there is output, that very likely is the result of a PHP error. | ||||
|             if (trim($output)) { | ||||
|                 throw new \Exception(Text::_('COM_FINDER_AN_ERROR_HAS_OCCURRED')); | ||||
|             } | ||||
|  | ||||
|             // Send the response. | ||||
|             static::sendResponse($state); | ||||
|         } catch (\Exception $e) { | ||||
|             // Catch an exception and return the response. | ||||
|             static::sendResponse($e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to run the next batch of content through the indexer. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function batch() | ||||
|     { | ||||
|         // Check for a valid token. If invalid, send a 403 with the error message. | ||||
|         if (!Session::checkToken('request')) { | ||||
|             static::sendResponse(new \Exception(Text::_('JINVALID_TOKEN_NOTICE'), 403)); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $params     = ComponentHelper::getParams('com_finder'); | ||||
|         $dispatcher = $this->getDispatcher(); | ||||
|  | ||||
|         if ($params->get('enable_logging', '0')) { | ||||
|             $options['format']    = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; | ||||
|             $options['text_file'] = 'indexer.php'; | ||||
|             Log::addLogger($options); | ||||
|         } | ||||
|  | ||||
|         // Log the start | ||||
|         try { | ||||
|             Log::add('Starting the indexer batch process', Log::INFO); | ||||
|         } catch (\RuntimeException $exception) { | ||||
|             // Informational log only | ||||
|         } | ||||
|  | ||||
|         // We don't want this form to be cached. | ||||
|         $this->app->allowCache(false); | ||||
|  | ||||
|         // Put in a buffer to silence noise. | ||||
|         ob_start(); | ||||
|  | ||||
|         // Remove the script time limit. | ||||
|         if (\function_exists('set_time_limit')) { | ||||
|             set_time_limit(0); | ||||
|         } | ||||
|  | ||||
|         // Get the indexer state. | ||||
|         $state = Indexer::getState(); | ||||
|  | ||||
|         // Reset the batch offset. | ||||
|         $state->batchOffset = 0; | ||||
|  | ||||
|         // Update the indexer state. | ||||
|         Indexer::setState($state); | ||||
|  | ||||
|         // Import the finder plugins. | ||||
|         PluginHelper::importPlugin('finder', null, true, $dispatcher); | ||||
|  | ||||
|         /* | ||||
|          * 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. | ||||
|          */ | ||||
|         $lang = $this->app->getLanguage(); | ||||
|  | ||||
|         // Get the document properties. | ||||
|         $attributes = [ | ||||
|             'charset'   => 'utf-8', | ||||
|             'lineend'   => 'unix', | ||||
|             'tab'       => '  ', | ||||
|             'language'  => $lang->getTag(), | ||||
|             'direction' => $lang->isRtl() ? 'rtl' : 'ltr', | ||||
|         ]; | ||||
|  | ||||
|         // Start the indexer. | ||||
|         try { | ||||
|             // Trigger the onBeforeIndex event. | ||||
|             $dispatcher->dispatch('onBeforeIndex', new BeforeIndexEvent('onBeforeIndex', [])); | ||||
|  | ||||
|             // Trigger the onBuildIndex event. | ||||
|             $dispatcher->dispatch('onBuildIndex', new BuildIndexEvent('onBuildIndex', [])); | ||||
|  | ||||
|             // Get the indexer state. | ||||
|             $state           = Indexer::getState(); | ||||
|             $state->start    = 0; | ||||
|             $state->complete = 0; | ||||
|  | ||||
|             // Log batch completion and memory high-water mark. | ||||
|             try { | ||||
|                 Log::add('Batch completed, peak memory usage: ' . number_format(memory_get_peak_usage(true)) . ' bytes', Log::INFO); | ||||
|             } catch (\RuntimeException $exception) { | ||||
|                 // Informational log only | ||||
|             } | ||||
|  | ||||
|             $output = ob_get_contents(); | ||||
|  | ||||
|             // Finder plugins should not create output of any kind. If there is output, that very likely is the result of a PHP error. | ||||
|             if (trim($output)) { | ||||
|                 throw new \Exception(Text::_('COM_FINDER_INDEXER_ERROR_PLUGIN_FAILURE')); | ||||
|             } | ||||
|  | ||||
|             // Send the response. | ||||
|             static::sendResponse($state); | ||||
|         } catch (\Exception $e) { | ||||
|             // Catch an exception and return the response. | ||||
|             // Send the response. | ||||
|             static::sendResponse($e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to optimize the index and perform any necessary cleanup. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function optimize() | ||||
|     { | ||||
|         // Check for a valid token. If invalid, send a 403 with the error message. | ||||
|         if (!Session::checkToken('request')) { | ||||
|             static::sendResponse(new \Exception(Text::_('JINVALID_TOKEN_NOTICE'), 403)); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // We don't want this form to be cached. | ||||
|         $this->app->allowCache(false); | ||||
|  | ||||
|         // Put in a buffer to silence noise. | ||||
|         ob_start(); | ||||
|  | ||||
|         // Import the finder plugins. | ||||
|         PluginHelper::importPlugin('finder', null, true, $this->getDispatcher()); | ||||
|  | ||||
|         try { | ||||
|             // Optimize the index | ||||
|             $indexer = new Indexer(); | ||||
|             $indexer->optimize(); | ||||
|  | ||||
|             // Get the indexer state. | ||||
|             $state           = Indexer::getState(); | ||||
|             $state->start    = 0; | ||||
|             $state->complete = 1; | ||||
|  | ||||
|             $output = ob_get_contents(); | ||||
|  | ||||
|             // Finder plugins should not create output of any kind. If there is output, that very likely is the result of a PHP error. | ||||
|             if (trim($output)) { | ||||
|                 throw new \Exception(Text::_('COM_FINDER_AN_ERROR_HAS_OCCURRED')); | ||||
|             } | ||||
|  | ||||
|             // Send the response. | ||||
|             static::sendResponse($state); | ||||
|         } catch (\Exception $e) { | ||||
|             // Catch an exception and return the response. | ||||
|             static::sendResponse($e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to handle a send a \JSON response. The body parameter | ||||
|      * can be an \Exception object for when an error has occurred or | ||||
|      * a CMSObject for a good response. | ||||
|      * | ||||
|      * @param   \Joomla\CMS\Object\CMSObject|\Exception  $data  CMSObject on success, \Exception on error. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function sendResponse($data = null) | ||||
|     { | ||||
|         $app = Factory::getApplication(); | ||||
|  | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|  | ||||
|         if ($params->get('enable_logging', '0')) { | ||||
|             $options['format']    = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; | ||||
|             $options['text_file'] = 'indexer.php'; | ||||
|             Log::addLogger($options); | ||||
|         } | ||||
|  | ||||
|         // Send the assigned error code if we are catching an exception. | ||||
|         if ($data instanceof \Exception) { | ||||
|             try { | ||||
|                 Log::add($data->getMessage(), Log::ERROR); | ||||
|             } catch (\RuntimeException $exception) { | ||||
|                 // Informational log only | ||||
|             } | ||||
|  | ||||
|             $app->setHeader('status', $data->getCode()); | ||||
|         } | ||||
|  | ||||
|         // Create the response object. | ||||
|         $response = new Response($data); | ||||
|  | ||||
|         if (\JDEBUG) { | ||||
|             // Add the buffer and memory usage | ||||
|             $response->buffer = ob_get_contents(); | ||||
|             $response->memory = memory_get_usage(true); | ||||
|         } | ||||
|         ob_clean(); | ||||
|  | ||||
|         // Send the JSON response. | ||||
|         echo json_encode($response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to call a specific indexing plugin and return debug info | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @internal | ||||
|      */ | ||||
|     public function debug() | ||||
|     { | ||||
|         // Check for a valid token. If invalid, send a 403 with the error message. | ||||
|         if (!Session::checkToken('request')) { | ||||
|             static::sendResponse(new \Exception(Text::_('JINVALID_TOKEN_NOTICE'), 403)); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // We don't want this form to be cached. | ||||
|         $this->app->allowCache(false); | ||||
|  | ||||
|         // Put in a buffer to silence noise. | ||||
|         ob_start(); | ||||
|  | ||||
|         // Remove the script time limit. | ||||
|         @set_time_limit(0); | ||||
|  | ||||
|         // Get the indexer state. | ||||
|         Indexer::resetState(); | ||||
|         $state = Indexer::getState(); | ||||
|  | ||||
|         // Reset the batch offset. | ||||
|         $state->batchOffset = 0; | ||||
|  | ||||
|         // Update the indexer state. | ||||
|         Indexer::setState($state); | ||||
|  | ||||
|         // Start the indexer. | ||||
|         try { | ||||
|             // Import the finder plugins. | ||||
|             class_alias(DebugAdapter::class, Adapter::class); | ||||
|             $plugin = $this->app->bootPlugin($this->app->getInput()->get('plugin'), 'finder'); | ||||
|             $plugin->setIndexer(new DebugIndexer()); | ||||
|             $plugin->debug($this->app->getInput()->get('id')); | ||||
|  | ||||
|             $output = ''; | ||||
|  | ||||
|             // Create list of attributes | ||||
|             $output .= '<fieldset><legend>' . Text::_('COM_FINDER_INDEXER_FIELDSET_ATTRIBUTES') . '</legend>'; | ||||
|             $output .= '<dl class="row">'; | ||||
|  | ||||
|             foreach (DebugIndexer::$item as $key => $value) { | ||||
|                 $output .= '<dt class="col-sm-2">' . $key . '</dt><dd class="col-sm-10 text-break">' . $value . '</dd>'; | ||||
|             } | ||||
|  | ||||
|             $output .= '</dl>'; | ||||
|             $output .= '</fieldset>'; | ||||
|  | ||||
|             $output .= '<fieldset><legend>' . Text::_('COM_FINDER_INDEXER_FIELDSET_ELEMENTS') . '</legend>'; | ||||
|             $output .= '<dl class="row">'; | ||||
|  | ||||
|             foreach (DebugIndexer::$item->getElements() as $key => $element) { | ||||
|                 $output .= '<dt class="col-sm-2">' . $key . '</dt><dd class="col-sm-10 text-break">' . $element . '</dd>'; | ||||
|             } | ||||
|  | ||||
|             $output .= '</dl>'; | ||||
|             $output .= '</fieldset>'; | ||||
|  | ||||
|             $output .= '<fieldset><legend>' . Text::_('COM_FINDER_INDEXER_FIELDSET_INSTRUCTIONS') . '</legend>'; | ||||
|             $output .= '<dl class="row">'; | ||||
|             $contexts = [ | ||||
|                 1 => 'Title context', | ||||
|                 2 => 'Text context', | ||||
|                 3 => 'Meta context', | ||||
|                 4 => 'Path context', | ||||
|                 5 => 'Misc context', | ||||
|             ]; | ||||
|  | ||||
|             foreach (DebugIndexer::$item->getInstructions() as $key => $element) { | ||||
|                 $output .= '<dt class="col-sm-2">' . $contexts[$key] . '</dt><dd class="col-sm-10 text-break">' . json_encode($element) . '</dd>'; | ||||
|             } | ||||
|  | ||||
|             $output .= '</dl>'; | ||||
|             $output .= '</fieldset>'; | ||||
|  | ||||
|             $output .= '<fieldset><legend>' . Text::_('COM_FINDER_INDEXER_FIELDSET_TAXONOMIES') . '</legend>'; | ||||
|             $output .= '<dl class="row">'; | ||||
|  | ||||
|             foreach (DebugIndexer::$item->getTaxonomy() as $key => $element) { | ||||
|                 $output .= '<dt class="col-sm-2">' . $key . '</dt><dd class="col-sm-10 text-break">' . json_encode($element) . '</dd>'; | ||||
|             } | ||||
|  | ||||
|             $output .= '</dl>'; | ||||
|             $output .= '</fieldset>'; | ||||
|  | ||||
|             // Get the indexer state. | ||||
|             $state           = Indexer::getState(); | ||||
|             $state->start    = 0; | ||||
|             $state->complete = 0; | ||||
|             $state->rendered = $output; | ||||
|  | ||||
|             echo json_encode($state); | ||||
|         } catch (\Exception $e) { | ||||
|             // Catch an exception and return the response. | ||||
|             // Send the response. | ||||
|             static::sendResponse($e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\MVC\Controller\AdminController; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Maps controller class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class MapsController extends AdminController | ||||
| { | ||||
|     /** | ||||
|      * The prefix to use with controller messages. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $text_prefix = 'COM_FINDER_MAPS'; | ||||
|  | ||||
|     /** | ||||
|      * 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  \Joomla\CMS\MVC\Model\BaseDatabaseModel  The model. | ||||
|      * | ||||
|      * @since   1.6 | ||||
|      */ | ||||
|     public function getModel($name = 'Maps', $prefix = 'Administrator', $config = ['ignore_request' => true]) | ||||
|     { | ||||
|         return parent::getModel($name, $prefix, $config); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Controller; | ||||
|  | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Controller\BaseController; | ||||
| use Joomla\CMS\Session\Session; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Methods supporting a list of search terms. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class SearchesController extends BaseController | ||||
| { | ||||
|     /** | ||||
|      * Method to reset the search log table. | ||||
|      * | ||||
|      * @return  void | ||||
|      */ | ||||
|     public function reset() | ||||
|     { | ||||
|         // Check for request forgeries. | ||||
|         Session::checkToken() or jexit(Text::_('JINVALID_TOKEN')); | ||||
|  | ||||
|         $model = $this->getModel('Searches'); | ||||
|  | ||||
|         if (!$model->reset()) { | ||||
|             $this->app->enqueueMessage($model->getError(), 'error'); | ||||
|         } | ||||
|  | ||||
|         $this->setRedirect('index.php?option=com_finder&view=searches'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Extension; | ||||
|  | ||||
| use Joomla\CMS\Component\Router\RouterServiceInterface; | ||||
| use Joomla\CMS\Component\Router\RouterServiceTrait; | ||||
| use Joomla\CMS\Extension\BootableExtensionInterface; | ||||
| use Joomla\CMS\Extension\MVCComponent; | ||||
| use Joomla\CMS\HTML\HTMLRegistryAwareTrait; | ||||
| use Joomla\Component\Finder\Administrator\Service\HTML\Filter; | ||||
| use Joomla\Component\Finder\Administrator\Service\HTML\Finder; | ||||
| use Joomla\Component\Finder\Administrator\Service\HTML\Query; | ||||
| use Joomla\Database\DatabaseInterface; | ||||
| use Psr\Container\ContainerInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Component class for com_finder | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class FinderComponent extends MVCComponent implements BootableExtensionInterface, RouterServiceInterface | ||||
| { | ||||
|     use RouterServiceTrait; | ||||
|     use HTMLRegistryAwareTrait; | ||||
|  | ||||
|     /** | ||||
|      * Booting the extension. This is the function to set up the environment of the extension like | ||||
|      * registering new class loaders, etc. | ||||
|      * | ||||
|      * If required, some initial set up can be done from services of the container, eg. | ||||
|      * registering HTML services. | ||||
|      * | ||||
|      * @param   ContainerInterface  $container  The container | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function boot(ContainerInterface $container) | ||||
|     { | ||||
|         $finder = new Finder(); | ||||
|         $finder->setDatabase($container->get(DatabaseInterface::class)); | ||||
|  | ||||
|         $this->getRegistry()->register('finder', $finder); | ||||
|  | ||||
|         $filter = new Filter(); | ||||
|         $filter->setDatabase($container->get(DatabaseInterface::class)); | ||||
|  | ||||
|         $this->getRegistry()->register('filter', $filter); | ||||
|  | ||||
|         $this->getRegistry()->register('query', new Query()); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Field; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Form\Field\ListField; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Search Branches field for the Finder package. | ||||
|  * | ||||
|  * @since  3.5 | ||||
|  */ | ||||
| class BranchesField extends ListField | ||||
| { | ||||
|     /** | ||||
|      * The form field type. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  3.5 | ||||
|      */ | ||||
|     protected $type = 'Branches'; | ||||
|  | ||||
|     /** | ||||
|      * Method to get the field options. | ||||
|      * | ||||
|      * @return  array  The field option objects. | ||||
|      * | ||||
|      * @since   3.5 | ||||
|      */ | ||||
|     public function getOptions() | ||||
|     { | ||||
|         Factory::getApplication()->bootComponent('com_finder'); | ||||
|  | ||||
|         return HTMLHelper::_('finder.mapslist'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,128 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Field; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Form\Field\GroupedlistField; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Supports a select grouped list of finder content map. | ||||
|  * | ||||
|  * @since  3.6.0 | ||||
|  */ | ||||
| class ContentmapField extends GroupedlistField | ||||
| { | ||||
|     /** | ||||
|      * The form field type. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  3.6.0 | ||||
|      */ | ||||
|     public $type = 'ContentMap'; | ||||
|  | ||||
|     /** | ||||
|      * Method to get the list of content map options grouped by first level. | ||||
|      * | ||||
|      * @return  array  The field option objects as a nested array in groups. | ||||
|      * | ||||
|      * @since   3.6.0 | ||||
|      */ | ||||
|     protected function getGroups() | ||||
|     { | ||||
|         $groups = []; | ||||
|  | ||||
|         // Get the database object and a new query object. | ||||
|         $db = $this->getDatabase(); | ||||
|  | ||||
|         // Main query. | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select($db->quoteName('a.title', 'text')) | ||||
|             ->select($db->quoteName('a.id', 'value')) | ||||
|             ->select($db->quoteName('a.parent_id')) | ||||
|             ->select($db->quoteName('a.level')) | ||||
|             ->from($db->quoteName('#__finder_taxonomy', 'a')) | ||||
|             ->where($db->quoteName('a.parent_id') . ' <> 0') | ||||
|             ->order('a.title ASC'); | ||||
|  | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         try { | ||||
|             $contentMap = $db->loadObjectList(); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             return []; | ||||
|         } | ||||
|  | ||||
|         // Build the grouped list array. | ||||
|         if ($contentMap) { | ||||
|             $parents = []; | ||||
|  | ||||
|             foreach ($contentMap as $item) { | ||||
|                 if (!isset($parents[$item->parent_id])) { | ||||
|                     $parents[$item->parent_id] = []; | ||||
|                 } | ||||
|  | ||||
|                 $parents[$item->parent_id][] = $item; | ||||
|             } | ||||
|  | ||||
|             foreach ($parents[1] as $branch) { | ||||
|                 $text          = Text::_(LanguageHelper::branchSingular($branch->text)); | ||||
|                 $groups[$text] = $this->prepareLevel($branch->value, $parents); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Merge any additional groups in the XML definition. | ||||
|         $groups = array_merge(parent::getGroups(), $groups); | ||||
|  | ||||
|         return $groups; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Indenting and translating options for the list | ||||
|      * | ||||
|      * @param   int    $parent   Parent ID to process | ||||
|      * @param   array  $parents  Array of arrays of items with parent IDs as keys | ||||
|      * | ||||
|      * @return  array  The indented list of entries for this branch | ||||
|      * | ||||
|      * @since   4.1.5 | ||||
|      */ | ||||
|     private function prepareLevel($parent, $parents) | ||||
|     { | ||||
|         $lang    = Factory::getLanguage(); | ||||
|         $entries = []; | ||||
|  | ||||
|         foreach ($parents[$parent] as $item) { | ||||
|             $levelPrefix = str_repeat('- ', $item->level - 1); | ||||
|  | ||||
|             if (trim($item->text, '*') === 'Language') { | ||||
|                 $text = LanguageHelper::branchLanguageTitle($item->text); | ||||
|             } else { | ||||
|                 $key  = LanguageHelper::branchSingular($item->text); | ||||
|                 $text = $lang->hasKey($key) ? Text::_($key) : $item->text; | ||||
|             } | ||||
|  | ||||
|             $entries[] = HTMLHelper::_('select.option', $item->value, $levelPrefix . $text); | ||||
|  | ||||
|             if (isset($parents[$item->value])) { | ||||
|                 $entries = array_merge($entries, $this->prepareLevel($item->value, $parents)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $entries; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,85 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Field; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Form\Field\ListField; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
| use Joomla\Utilities\ArrayHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Content Types Filter field for the Finder package. | ||||
|  * | ||||
|  * @since  3.6.0 | ||||
|  */ | ||||
| class ContenttypesField extends ListField | ||||
| { | ||||
|     /** | ||||
|      * The form field type. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  3.6.0 | ||||
|      */ | ||||
|     protected $type = 'ContentTypes'; | ||||
|  | ||||
|     /** | ||||
|      * Method to get the field options. | ||||
|      * | ||||
|      * @return  array  The field option objects. | ||||
|      * | ||||
|      * @since   3.6.0 | ||||
|      */ | ||||
|     public function getOptions() | ||||
|     { | ||||
|         $lang    = Factory::getLanguage(); | ||||
|         $options = []; | ||||
|  | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select($db->quoteName('id', 'value')) | ||||
|             ->select($db->quoteName('title', 'text')) | ||||
|             ->from($db->quoteName('#__finder_types')); | ||||
|  | ||||
|         // Get the options. | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         try { | ||||
|             $contentTypes = $db->loadObjectList(); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); | ||||
|         } | ||||
|  | ||||
|         // Translate. | ||||
|         foreach ($contentTypes as $contentType) { | ||||
|             $key                         = LanguageHelper::branchSingular($contentType->text); | ||||
|             $contentType->translatedText = $lang->hasKey($key) ? Text::_($key) : $contentType->text; | ||||
|         } | ||||
|  | ||||
|         // Order by title. | ||||
|         $contentTypes = ArrayHelper::sortObjects($contentTypes, 'translatedText', 1, true, true); | ||||
|  | ||||
|         // Convert the values to options. | ||||
|         foreach ($contentTypes as $contentType) { | ||||
|             $options[] = HTMLHelper::_('select.option', $contentType->value, $contentType->translatedText); | ||||
|         } | ||||
|  | ||||
|         // Merge any additional options in the XML definition. | ||||
|         $options = array_merge(parent::getOptions(), $options); | ||||
|  | ||||
|         return $options; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Field; | ||||
|  | ||||
| use Joomla\CMS\Form\Field\ListField; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Search Filter field for the Finder package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class SearchfilterField extends ListField | ||||
| { | ||||
|     /** | ||||
|      * 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    = $this->getDatabase(); | ||||
|         $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, HTMLHelper::_('select.option', '', Text::_('COM_FINDER_SELECT_SEARCH_FILTER'), 'value', 'text')); | ||||
|  | ||||
|         return $options; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Field; | ||||
|  | ||||
| use Joomla\CMS\Form\Field\CheckboxesField; | ||||
|  | ||||
| /** | ||||
|  * Taxonomy Types field for the Finder package. | ||||
|  * This is a helper to allow to save an empty set of | ||||
|  * options by having a hidden field with a "none" value. | ||||
|  * | ||||
|  * @since  5.0.0 | ||||
|  */ | ||||
| class TaxonomytypesField extends CheckboxesField | ||||
| { | ||||
|     /** | ||||
|      * The form field type. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $type = 'TaxonomyTypes'; | ||||
|  | ||||
|     /** | ||||
|      * Method to get the field input markup for a generic list. | ||||
|      * Use the multiple attribute to enable multiselect. | ||||
|      * | ||||
|      * @return  string  The field input markup. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     protected function getInput() | ||||
|     { | ||||
|         $html = parent::getInput(); | ||||
|  | ||||
|         $data = $this->getLayoutData(); | ||||
|         $data['id'] .= '_hidden'; | ||||
|         $data['value'] = 'none'; | ||||
|  | ||||
|         return $html . $this->getRenderer('joomla.form.field.hidden')->render($data); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Helper; | ||||
|  | ||||
| use Joomla\CMS\Extension\ExtensionHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Helper class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FinderHelper | ||||
| { | ||||
|     /** | ||||
|      * The extension name. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     public static $extension = 'com_finder'; | ||||
|  | ||||
|     /** | ||||
|      * Gets the finder system plugin extension id. | ||||
|      * | ||||
|      * @return  integer  The finder system plugin extension id. | ||||
|      * | ||||
|      * @since   3.6.0 | ||||
|      */ | ||||
|     public static function getFinderPluginId() | ||||
|     { | ||||
|         $pluginRecord = ExtensionHelper::getExtensionRecord('finder', 'plugin', null, 'content'); | ||||
|  | ||||
|         return $pluginRecord !== null ? $pluginRecord->extension_id : 0; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,151 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Helper; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\LanguageHelper as CMSLanguageHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Finder language helper class. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class LanguageHelper | ||||
| { | ||||
|     /** | ||||
|      * 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)); | ||||
|  | ||||
|         if ($return !== '_') { | ||||
|             return 'PLG_FINDER_QUERY_FILTER_BRANCH_P_' . $return; | ||||
|         } | ||||
|  | ||||
|         return $branchName; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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)); | ||||
|         $language = Factory::getApplication()->getLanguage(); | ||||
|         $debug    = Factory::getApplication()->get('debug_lang'); | ||||
|  | ||||
|         if ($language->hasKey('PLG_FINDER_QUERY_FILTER_BRANCH_S_' . $return) || $debug) { | ||||
|             return 'PLG_FINDER_QUERY_FILTER_BRANCH_S_' . $return; | ||||
|         } | ||||
|  | ||||
|         return $branchName; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to return the language name for a language taxonomy branch. | ||||
|      * | ||||
|      * @param   string  $branchName  Language branch name. | ||||
|      * | ||||
|      * @return  string  The language title. | ||||
|      * | ||||
|      * @since   3.6.0 | ||||
|      */ | ||||
|     public static function branchLanguageTitle($branchName) | ||||
|     { | ||||
|         $title = $branchName; | ||||
|  | ||||
|         if ($branchName === '*') { | ||||
|             $title = Text::_('JALL_LANGUAGE'); | ||||
|         } else { | ||||
|             $languages = CMSLanguageHelper::getLanguages('lang_code'); | ||||
|  | ||||
|             if (isset($languages[$branchName])) { | ||||
|                 $title = $languages[$branchName]->title; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $title; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to load Smart Search component language file. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function loadComponentLanguage() | ||||
|     { | ||||
|         Factory::getLanguage()->load('com_finder', JPATH_SITE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to load Smart Search plugin 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 plugin names. | ||||
|         $db    = Factory::getDbo(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select([$db->quoteName('name'), $db->quoteName('element')]) | ||||
|             ->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 = Factory::getLanguage(); | ||||
|         $lang->load('plg_content_finder', JPATH_ADMINISTRATOR); | ||||
|  | ||||
|         // Load language file for each plugin. | ||||
|         foreach ($plugins as $plugin) { | ||||
|             $lang->load($plugin->name, JPATH_ADMINISTRATOR) | ||||
|                 || $lang->load($plugin->name, JPATH_PLUGINS . '/finder/' . $plugin->element); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										942
									
								
								administrator/components/com_finder/src/Indexer/Adapter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										942
									
								
								administrator/components/com_finder/src/Indexer/Adapter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,942 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Plugin\CMSPlugin; | ||||
| use Joomla\CMS\Table\Table; | ||||
| use Joomla\Database\DatabaseInterface; | ||||
| use Joomla\Database\QueryInterface; | ||||
| use Joomla\Event\DispatcherInterface; | ||||
| use Joomla\Utilities\ArrayHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Prototype adapter class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| abstract class Adapter extends CMSPlugin | ||||
| { | ||||
|     /** | ||||
|      * 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    DatabaseInterface | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     protected $db; | ||||
|  | ||||
|     /** | ||||
|      * The table name. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     protected $table; | ||||
|  | ||||
|     /** | ||||
|      * The indexer object. | ||||
|      * | ||||
|      * @var    Indexer | ||||
|      * @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   DispatcherInterface  $dispatcher  The object to observe. | ||||
|      * @param   array                $config      An array that holds the plugin configuration. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function __construct(DispatcherInterface $dispatcher, array $config) | ||||
|     { | ||||
|         // Call the parent constructor. | ||||
|         parent::__construct($dispatcher, $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 = Helper::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 = new Indexer($this->db); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns an array of events this subscriber will listen to. | ||||
|      * | ||||
|      * @return  array | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public static function getSubscribedEvents(): array | ||||
|     { | ||||
|         return [ | ||||
|             'onBeforeIndex'             => 'onBeforeIndex', | ||||
|             'onBuildIndex'              => 'onBuildIndex', | ||||
|             'onFinderGarbageCollection' => 'onFinderGarbageCollection', | ||||
|             'onStartIndex'              => 'onStartIndex', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the adapter state and push it into the indexer. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on error. | ||||
|      */ | ||||
|     public function onStartIndex() | ||||
|     { | ||||
|         // Get the indexer state. | ||||
|         $iState = Indexer::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. | ||||
|         Indexer::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 = Indexer::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 = Indexer::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. | ||||
|         foreach ($items as $item) { | ||||
|             // Index the item. | ||||
|             $this->index($item); | ||||
|  | ||||
|             // Adjust the offsets. | ||||
|             $offset++; | ||||
|             $iState->batchOffset++; | ||||
|             $iState->totalItems--; | ||||
|         } | ||||
|  | ||||
|         // Update the indexer state. | ||||
|         $aState['offset']                    = $offset; | ||||
|         $iState->pluginState[$this->context] = $aState; | ||||
|         Indexer::setState($iState); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove outdated index entries | ||||
|      * | ||||
|      * @return  integer | ||||
|      * | ||||
|      * @since   4.2.0 | ||||
|      */ | ||||
|     public function onFinderGarbageCollection() | ||||
|     { | ||||
|         $db      = $this->db; | ||||
|         $type_id = $this->getTypeId(); | ||||
|  | ||||
|         $query    = $db->getQuery(true); | ||||
|         $subquery = $db->getQuery(true); | ||||
|         $subquery->select('CONCAT(' . $db->quote($this->getUrl('', $this->extension, $this->layout)) . ', id)') | ||||
|             ->from($db->quoteName($this->table)); | ||||
|         $query->select($db->quoteName('l.link_id')) | ||||
|             ->from($db->quoteName('#__finder_links', 'l')) | ||||
|             ->where($db->quoteName('l.type_id') . ' = ' . $type_id) | ||||
|             ->where($db->quoteName('l.url') . ' LIKE ' . $db->quote($this->getUrl('%', $this->extension, $this->layout))) | ||||
|             ->where($db->quoteName('l.url') . ' NOT IN (' . $subquery . ')'); | ||||
|         $db->setQuery($query); | ||||
|         $items = $db->loadColumn(); | ||||
|  | ||||
|         foreach ($items as $item) { | ||||
|             $this->indexer->remove($item); | ||||
|         } | ||||
|  | ||||
|         return \count($items); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   Result  $item  The item to index as a Result object. | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     abstract protected function index(Result $item); | ||||
|  | ||||
|     /** | ||||
|      * Method to reindex an item. | ||||
|      * | ||||
|      * @param   integer  $id  The ID of the item to reindex. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @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); | ||||
|  | ||||
|         Taxonomy::removeOrphanNodes(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove an item from the index. | ||||
|      * | ||||
|      * @param   string  $id                The ID of the item to remove. | ||||
|      * @param   bool    $removeTaxonomies  Remove empty taxonomies | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function remove($id, $removeTaxonomies = true) | ||||
|     { | ||||
|         // 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)) { | ||||
|             Factory::getApplication()->triggerEvent('onFinderIndexAfterDelete', [$id]); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // Remove the items. | ||||
|         foreach ($items as $item) { | ||||
|             $this->indexer->remove($item, $removeTaxonomies); | ||||
|         } | ||||
|  | ||||
|         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   Table  $row  A Table 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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to check the existing access level for categories | ||||
|      * | ||||
|      * @param   Table  $row  A Table 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   Table  $row  A Table 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 QueryInterface) { | ||||
|             $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(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get a content item to index. | ||||
|      * | ||||
|      * @param   integer  $id  The id of the content item. | ||||
|      * | ||||
|      * @return  Result  A Result 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); | ||||
|         $item = $this->db->loadAssoc(); | ||||
|  | ||||
|         // Convert the item to a result object. | ||||
|         $item = ArrayHelper::toObject((array) $item, Result::class); | ||||
|  | ||||
|         // 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   QueryInterface  $query   A QueryInterface object. [optional] | ||||
|      * | ||||
|      * @return  Result[]  An array of Result objects. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function getItems($offset, $limit, $query = null) | ||||
|     { | ||||
|         // Get the content items to index. | ||||
|         $this->db->setQuery($this->getListQuery($query)->setLimit($limit, $offset)); | ||||
|         $items = $this->db->loadAssocList(); | ||||
|  | ||||
|         foreach ($items as &$item) { | ||||
|             $item = ArrayHelper::toObject($item, Result::class); | ||||
|  | ||||
|             // 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; | ||||
|         } | ||||
|  | ||||
|         return $items; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the SQL query used to retrieve the list of content items. | ||||
|      * | ||||
|      * @param   mixed  $query  A QueryInterface object. [optional] | ||||
|      * | ||||
|      * @return  QueryInterface  A database object. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function getListQuery($query = null) | ||||
|     { | ||||
|         // Check if we can use the supplied SQL query. | ||||
|         return $query instanceof QueryInterface ? $query : $this->db->getQuery(true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the plugin type | ||||
|      * | ||||
|      * @param   integer  $id  The plugin ID | ||||
|      * | ||||
|      * @return  string|null  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('folder') . ' = ' . $this->db->quote('finder')) | ||||
|             ->where($this->db->quoteName('extension_id') . ' = ' . (int) $id); | ||||
|         $this->db->setQuery($query); | ||||
|  | ||||
|         return $this->db->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get a SQL query to load the published and access states for | ||||
|      * an article and category. | ||||
|      * | ||||
|      * @return  QueryInterface  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  QueryInterface  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  QueryInterface  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); | ||||
|  | ||||
|         return (int) $this->db->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   = Factory::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 (isset($params->page_title) && $params->page_title) { | ||||
|             $return = $params->page_title; | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to update index data on access level changes | ||||
|      * | ||||
|      * @param   Table  $row  A Table 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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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); | ||||
|                 } | ||||
|                 // Stop processing plugins | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 && $category == 0) { | ||||
|             $item = 0; | ||||
|         } | ||||
|  | ||||
|         // Translate the state | ||||
|         switch ($item) { | ||||
|             case 1: | ||||
|                 // Published items should always show up in search results | ||||
|                 return 1; | ||||
|  | ||||
|             case 2: | ||||
|                 // Archived items should only show up when option is enabled | ||||
|                 if ($this->params->get('search_archived', 1) == 0) { | ||||
|                     return 0; | ||||
|                 } | ||||
|  | ||||
|                 return 1; | ||||
|  | ||||
|             default: | ||||
|                 // All other states should return an unpublished state | ||||
|                 return 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										969
									
								
								administrator/components/com_finder/src/Indexer/DebugAdapter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										969
									
								
								administrator/components/com_finder/src/Indexer/DebugAdapter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,969 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Plugin\CMSPlugin; | ||||
| use Joomla\CMS\Table\Table; | ||||
| use Joomla\Database\DatabaseInterface; | ||||
| use Joomla\Database\QueryInterface; | ||||
| use Joomla\Event\DispatcherInterface; | ||||
| use Joomla\Utilities\ArrayHelper; | ||||
|  | ||||
| /** | ||||
|  * Prototype debug adapter class for the Finder indexer package. | ||||
|  * THIS CLASS IS ONLY TO BE USED FOR DEBUGGING PURPOSES! DON'T | ||||
|  * USE IT FOR PRODUCTIVE USE! | ||||
|  * | ||||
|  * @since  5.0.0 | ||||
|  * @internal | ||||
|  */ | ||||
| abstract class DebugAdapter extends CMSPlugin | ||||
| { | ||||
|     /** | ||||
|      * 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  5.0.0 | ||||
|      */ | ||||
|     protected $context; | ||||
|  | ||||
|     /** | ||||
|      * The extension name. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $extension; | ||||
|  | ||||
|     /** | ||||
|      * The sublayout to use when rendering the results. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $layout; | ||||
|  | ||||
|     /** | ||||
|      * The mime type of the content the adapter indexes. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $mime; | ||||
|  | ||||
|     /** | ||||
|      * The access level of an item before save. | ||||
|      * | ||||
|      * @var    integer | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $old_access; | ||||
|  | ||||
|     /** | ||||
|      * The access level of a category before save. | ||||
|      * | ||||
|      * @var    integer | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $old_cataccess; | ||||
|  | ||||
|     /** | ||||
|      * The type of content the adapter indexes. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $type_title; | ||||
|  | ||||
|     /** | ||||
|      * The type id of the content. | ||||
|      * | ||||
|      * @var    integer | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $type_id; | ||||
|  | ||||
|     /** | ||||
|      * The database object. | ||||
|      * | ||||
|      * @var    DatabaseInterface | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $db; | ||||
|  | ||||
|     /** | ||||
|      * The table name. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $table; | ||||
|  | ||||
|     /** | ||||
|      * The indexer object. | ||||
|      * | ||||
|      * @var    Indexer | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $indexer; | ||||
|  | ||||
|     /** | ||||
|      * The field the published state is stored in. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $state_field = 'state'; | ||||
|  | ||||
|     /** | ||||
|      * Method to instantiate the indexer adapter. | ||||
|      * | ||||
|      * @param   DispatcherInterface  $dispatcher  The object to observe. | ||||
|      * @param   array                $config      An array that holds the plugin configuration. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function __construct(DispatcherInterface $dispatcher, array $config) | ||||
|     { | ||||
|         // Call the parent constructor. | ||||
|         parent::__construct($dispatcher, $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 = Helper::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 = new Indexer($this->db); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns an array of events this subscriber will listen to. | ||||
|      * | ||||
|      * @return  array | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public static function getSubscribedEvents(): array | ||||
|     { | ||||
|         return [ | ||||
|             'onBeforeIndex'             => 'onBeforeIndex', | ||||
|             'onBuildIndex'              => 'onBuildIndex', | ||||
|             'onFinderGarbageCollection' => 'onFinderGarbageCollection', | ||||
|             'onStartIndex'              => 'onStartIndex', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the adapter state and push it into the indexer. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on error. | ||||
|      */ | ||||
|     public function onStartIndex() | ||||
|     { | ||||
|         // Get the indexer state. | ||||
|         $iState = Indexer::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. | ||||
|         Indexer::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   5.0.0 | ||||
|      * @throws  \Exception on error. | ||||
|      */ | ||||
|     public function onBeforeIndex() | ||||
|     { | ||||
|         // Get the indexer and adapter state. | ||||
|         $iState = Indexer::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   5.0.0 | ||||
|      * @throws  \Exception on error. | ||||
|      */ | ||||
|     public function onBuildIndex() | ||||
|     { | ||||
|         // Get the indexer and adapter state. | ||||
|         $iState = Indexer::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. | ||||
|         foreach ($items as $item) { | ||||
|             // Index the item. | ||||
|             $this->index($item); | ||||
|  | ||||
|             // Adjust the offsets. | ||||
|             $offset++; | ||||
|             $iState->batchOffset++; | ||||
|             $iState->totalItems--; | ||||
|         } | ||||
|  | ||||
|         // Update the indexer state. | ||||
|         $aState['offset']                    = $offset; | ||||
|         $iState->pluginState[$this->context] = $aState; | ||||
|         Indexer::setState($iState); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove outdated index entries | ||||
|      * | ||||
|      * @return  integer | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function onFinderGarbageCollection() | ||||
|     { | ||||
|         $db      = $this->db; | ||||
|         $type_id = $this->getTypeId(); | ||||
|  | ||||
|         $query    = $db->getQuery(true); | ||||
|         $subquery = $db->getQuery(true); | ||||
|         $subquery->select('CONCAT(' . $db->quote($this->getUrl('', $this->extension, $this->layout)) . ', id)') | ||||
|             ->from($db->quoteName($this->table)); | ||||
|         $query->select($db->quoteName('l.link_id')) | ||||
|             ->from($db->quoteName('#__finder_links', 'l')) | ||||
|             ->where($db->quoteName('l.type_id') . ' = ' . $type_id) | ||||
|             ->where($db->quoteName('l.url') . ' LIKE ' . $db->quote($this->getUrl('%', $this->extension, $this->layout))) | ||||
|             ->where($db->quoteName('l.url') . ' NOT IN (' . $subquery . ')'); | ||||
|         $db->setQuery($query); | ||||
|         $items = $db->loadColumn(); | ||||
|  | ||||
|         foreach ($items as $item) { | ||||
|             $this->indexer->remove($item); | ||||
|         } | ||||
|  | ||||
|         return \count($items); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   5.0.0 | ||||
|      * @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   Result  $item  The item to index as a Result object. | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     abstract protected function index(Result $item); | ||||
|  | ||||
|     /** | ||||
|      * Method to reindex an item. | ||||
|      * | ||||
|      * @param   integer  $id  The ID of the item to reindex. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function reindex($id) | ||||
|     { | ||||
|         // Run the setup method. | ||||
|         $this->setup(); | ||||
|  | ||||
|         // Remove the old item. | ||||
|         $this->remove($id, false); | ||||
|  | ||||
|         // Get the item. | ||||
|         $item = $this->getItem($id); | ||||
|  | ||||
|         // Index the item. | ||||
|         $this->index($item); | ||||
|  | ||||
|         Taxonomy::removeOrphanNodes(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove an item from the index. | ||||
|      * | ||||
|      * @param   string  $id                The ID of the item to remove. | ||||
|      * @param   bool    $removeTaxonomies  Remove empty taxonomies | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function remove($id, $removeTaxonomies = true) | ||||
|     { | ||||
|         // 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)) { | ||||
|             $this->getApplication()->triggerEvent('onFinderIndexAfterDelete', [$id]); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // Remove the items. | ||||
|         foreach ($items as $item) { | ||||
|             $this->indexer->remove($item, $removeTaxonomies); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to setup the adapter before indexing. | ||||
|      * | ||||
|      * @return  boolean  True on success, false on failure. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     abstract protected function setup(); | ||||
|  | ||||
|     /** | ||||
|      * Method to update index data on category access level changes | ||||
|      * | ||||
|      * @param   Table  $row  A Table object | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   5.0.0 | ||||
|      */ | ||||
|     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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to check the existing access level for categories | ||||
|      * | ||||
|      * @param   Table  $row  A Table object | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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   Table  $row  A Table object | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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   5.0.0 | ||||
|      * @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 QueryInterface) { | ||||
|             $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(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get a content item to index. | ||||
|      * | ||||
|      * @param   integer  $id  The id of the content item. | ||||
|      * | ||||
|      * @return  Result  A Result object. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @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); | ||||
|         $item = $this->db->loadAssoc(); | ||||
|  | ||||
|         // Convert the item to a result object. | ||||
|         $item = ArrayHelper::toObject((array) $item, Result::class); | ||||
|  | ||||
|         // 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   QueryInterface  $query   A QueryInterface object. [optional] | ||||
|      * | ||||
|      * @return  Result[]  An array of Result objects. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function getItems($offset, $limit, $query = null) | ||||
|     { | ||||
|         // Get the content items to index. | ||||
|         $this->db->setQuery($this->getListQuery($query)->setLimit($limit, $offset)); | ||||
|         $items = $this->db->loadAssocList(); | ||||
|  | ||||
|         foreach ($items as &$item) { | ||||
|             $item = ArrayHelper::toObject($item, Result::class); | ||||
|  | ||||
|             // 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; | ||||
|         } | ||||
|  | ||||
|         return $items; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the SQL query used to retrieve the list of content items. | ||||
|      * | ||||
|      * @param   mixed  $query  A QueryInterface object. [optional] | ||||
|      * | ||||
|      * @return  QueryInterface  A database object. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     protected function getListQuery($query = null) | ||||
|     { | ||||
|         // Check if we can use the supplied SQL query. | ||||
|         return $query instanceof QueryInterface ? $query : $this->db->getQuery(true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the plugin type | ||||
|      * | ||||
|      * @param   integer  $id  The plugin ID | ||||
|      * | ||||
|      * @return  string  The plugin type | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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); | ||||
|  | ||||
|         return $this->db->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get a SQL query to load the published and access states for | ||||
|      * an article and category. | ||||
|      * | ||||
|      * @return  QueryInterface  A database object. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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  QueryInterface  A database object. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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  QueryInterface  A database object. | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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   5.0.0 | ||||
|      * @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); | ||||
|  | ||||
|         return (int) $this->db->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   5.0.0 | ||||
|      */ | ||||
|     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   5.0.0 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     protected function getItemMenuTitle($url) | ||||
|     { | ||||
|         $return = null; | ||||
|  | ||||
|         // Set variables | ||||
|         $user   = $this->getApplication()->getIdentity(); | ||||
|         $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 (isset($params->page_title) && $params->page_title) { | ||||
|             $return = $params->page_title; | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to update index data on access level changes | ||||
|      * | ||||
|      * @param   Table  $row  A Table object | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     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   5.0.0 | ||||
|      */ | ||||
|     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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   5.0.0 | ||||
|      */ | ||||
|     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   5.0.0 | ||||
|      */ | ||||
|     protected function translateState($item, $category = null) | ||||
|     { | ||||
|         // If category is present, factor in its states as well | ||||
|         if ($category !== null && $category == 0) { | ||||
|             $item = 0; | ||||
|         } | ||||
|  | ||||
|         // Translate the state | ||||
|         switch ($item) { | ||||
|             case 1: | ||||
|             case 2: | ||||
|                 // Published and archived items only should return a published state | ||||
|                 return 1; | ||||
|  | ||||
|             default: | ||||
|                 // All other states should return an unpublished state | ||||
|                 return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Debug method to set the used indexer | ||||
|      * | ||||
|      * @param   Indexer  $indexer  Indexer object | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function setIndexer(Indexer $indexer) | ||||
|     { | ||||
|         $this->indexer = $indexer; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Debug method to run a specific plugin to prepare a result object. | ||||
|      * The object is then stored in the indexer object to debug further. | ||||
|      * | ||||
|      * @param   mixed  $id  ID to index | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function debug($id) | ||||
|     { | ||||
|         // Run the setup method. | ||||
|         $this->setup(); | ||||
|  | ||||
|         // Get the item. | ||||
|         $item = $this->getItem($id); | ||||
|  | ||||
|         // Index the item. | ||||
|         $this->index($item); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| /** | ||||
|  * Debugging indexer class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  5.0.0 | ||||
|  * @internal | ||||
|  */ | ||||
| class DebugIndexer extends Indexer | ||||
| { | ||||
|     /** | ||||
|      * The result object from the last call to self::index() | ||||
|      * | ||||
|      * @var Result | ||||
|      * | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     public static $item; | ||||
|  | ||||
|     /** | ||||
|      * Stub for index() in indexer class | ||||
|      * | ||||
|      * @param   Result  $item    Result object to index | ||||
|      * @param   string  $format  Format to index | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function index($item, $format = 'html') | ||||
|     { | ||||
|         self::$item = $item; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										492
									
								
								administrator/components/com_finder/src/Indexer/Helper.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										492
									
								
								administrator/components/com_finder/src/Indexer/Helper.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,492 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Event\Finder\PrepareContentEvent; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Multilanguage; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\CMS\Table\Table; | ||||
| use Joomla\Component\Fields\Administrator\Helper\FieldsHelper; | ||||
| use Joomla\Registry\Registry; | ||||
| use Joomla\String\StringHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Helper class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Helper | ||||
| { | ||||
|     public const CUSTOMFIELDS_DONT_INDEX      = 0; | ||||
|     public const CUSTOMFIELDS_ADD_TO_INDEX    = 1; | ||||
|     public const CUSTOMFIELDS_ADD_TO_TAXONOMY = 2; | ||||
|     public const CUSTOMFIELDS_ADD_TO_BOTH     = 3; | ||||
|  | ||||
|     /** | ||||
|      * 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 Parser::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  Token[]  An array of Token objects. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function tokenize($input, $lang, $phrase = false) | ||||
|     { | ||||
|         static $cache = [], $tuplecount; | ||||
|         static $multilingual; | ||||
|         static $defaultLanguage; | ||||
|  | ||||
|         if (!$tuplecount) { | ||||
|             $params     = ComponentHelper::getParams('com_finder'); | ||||
|             $tuplecount = $params->get('tuplecount', 1); | ||||
|         } | ||||
|  | ||||
|         if (\is_null($multilingual)) { | ||||
|             $multilingual = Multilanguage::isEnabled(); | ||||
|             $config       = ComponentHelper::getParams('com_finder'); | ||||
|  | ||||
|             if ($config->get('language_default', '') == '') { | ||||
|                 $defaultLang = '*'; | ||||
|             } elseif ($config->get('language_default', '') == '-1') { | ||||
|                 $defaultLang = self::getDefaultLanguage(); | ||||
|             } else { | ||||
|                 $defaultLang = $config->get('language_default'); | ||||
|             } | ||||
|  | ||||
|             /* | ||||
|              * The default language always has the language code '*'. | ||||
|              * In order to not overwrite the language code of the language | ||||
|              * object that we are using, we are cloning it here. | ||||
|              */ | ||||
|             $obj                       = Language::getInstance($defaultLang); | ||||
|             $defaultLanguage           = clone $obj; | ||||
|             $defaultLanguage->language = '*'; | ||||
|         } | ||||
|  | ||||
|         if (!$multilingual || $lang == '*') { | ||||
|             $language = $defaultLanguage; | ||||
|         } else { | ||||
|             $language = Language::getInstance($lang); | ||||
|         } | ||||
|  | ||||
|         if (!isset($cache[$lang])) { | ||||
|             $cache[$lang] = []; | ||||
|         } | ||||
|  | ||||
|         $tokens = []; | ||||
|         $terms  = $language->tokenise($input); | ||||
|  | ||||
|         // @todo: array_filter removes any number 0's from the terms. Not sure this is entirely intended | ||||
|         $terms = array_filter($terms); | ||||
|         $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 Token($terms, $language->language, $language->spacer); | ||||
|         } else { | ||||
|             // Create tokens from the terms. | ||||
|             for ($i = 0, $n = \count($terms); $i < $n; $i++) { | ||||
|                 if (isset($cache[$lang][$terms[$i]])) { | ||||
|                     $tokens[] = $cache[$lang][$terms[$i]]; | ||||
|                 } else { | ||||
|                     $token                    = new Token($terms[$i], $language->language); | ||||
|                     $tokens[]                 = $token; | ||||
|                     $cache[$lang][$terms[$i]] = $token; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Create multi-word phrase tokens from the individual words. | ||||
|             if ($tuplecount > 1) { | ||||
|                 for ($i = 0, $n = \count($tokens); $i < $n; $i++) { | ||||
|                     $temp = [$tokens[$i]->term]; | ||||
|  | ||||
|                     // Create tokens for 2 to $tuplecount length phrases | ||||
|                     for ($j = 1; $j < $tuplecount; $j++) { | ||||
|                         if ($i + $j >= $n || !isset($tokens[$i + $j])) { | ||||
|                             break; | ||||
|                         } | ||||
|  | ||||
|                         $temp[] = $tokens[$i + $j]->term; | ||||
|                         $key    = implode('::', $temp); | ||||
|  | ||||
|                         if (isset($cache[$lang][$key])) { | ||||
|                             $tokens[] = $cache[$lang][$key]; | ||||
|                         } else { | ||||
|                             $token              = new Token($temp, $language->language, $language->spacer); | ||||
|                             $token->derived     = true; | ||||
|                             $tokens[]           = $token; | ||||
|                             $cache[$lang][$key] = $token; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Prevent the cache to fill up the memory | ||||
|         while (\count($cache[$lang]) > 1024) { | ||||
|             /** | ||||
|              * We want to cache the most common words/tokens. At the same time | ||||
|              * we don't want to cache too much. The most common words will also | ||||
|              * be early in the text, so we are dropping all terms/tokens which | ||||
|              * have been cached later. | ||||
|              */ | ||||
|             array_pop($cache[$lang]); | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the base word of a token. | ||||
|      * | ||||
|      * @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) | ||||
|     { | ||||
|         static $multilingual; | ||||
|         static $defaultStemmer; | ||||
|  | ||||
|         if (\is_null($multilingual)) { | ||||
|             $multilingual = Multilanguage::isEnabled(); | ||||
|             $config       = ComponentHelper::getParams('com_finder'); | ||||
|  | ||||
|             if ($config->get('language_default', '') == '') { | ||||
|                 $defaultStemmer = Language::getInstance('*'); | ||||
|             } elseif ($config->get('language_default', '') == '-1') { | ||||
|                 $defaultStemmer = Language::getInstance(self::getDefaultLanguage()); | ||||
|             } else { | ||||
|                 $defaultStemmer = Language::getInstance($config->get('language_default')); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!$multilingual || $lang == '*') { | ||||
|             $language = $defaultStemmer; | ||||
|         } else { | ||||
|             $language = Language::getInstance($lang); | ||||
|         } | ||||
|  | ||||
|         return $language->stem($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    = Factory::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([$db->quoteName('title'), $db->quoteName('mime')]) | ||||
|             ->values($db->quote($title) . ', ' . $db->quote($mime ?? '')); | ||||
|         $db->setQuery($query); | ||||
|         $db->execute(); | ||||
|  | ||||
|         // Cache the result | ||||
|         $type        = new \stdClass(); | ||||
|         $type->title = $title; | ||||
|         $type->mime  = $mime ?? ''; | ||||
|         $type->id    = (int) $db->insertid(); | ||||
|  | ||||
|         $types[$title] = $type; | ||||
|  | ||||
|         // Return the new id. | ||||
|         return $type->id; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 = [], $default, $multilingual; | ||||
|  | ||||
|         if (\is_null($multilingual)) { | ||||
|             $multilingual = Multilanguage::isEnabled(); | ||||
|             $config       = ComponentHelper::getParams('com_finder'); | ||||
|  | ||||
|             if ($config->get('language_default', '') == '') { | ||||
|                 $default = '*'; | ||||
|             } elseif ($config->get('language_default', '') == '-1') { | ||||
|                 $default = self::getPrimaryLanguage(self::getDefaultLanguage()); | ||||
|             } else { | ||||
|                 $default = self::getPrimaryLanguage($config->get('language_default')); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!$multilingual || $lang == '*') { | ||||
|             $lang = $default; | ||||
|         } | ||||
|  | ||||
|         // 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. | ||||
|         return \in_array($token, $data[$lang], true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 = Factory::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); | ||||
|  | ||||
|         return $db->loadColumn(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 = ComponentHelper::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(['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] = StringHelper::substr($lang, 0, StringHelper::strpos($lang, '-')); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $data[$lang]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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   Result  $item  The item to index as a Result object. | ||||
|      * | ||||
|      * @return  boolean  True on success, false on failure. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on database error. | ||||
|      */ | ||||
|     public static function getContentExtras(Result $item) | ||||
|     { | ||||
|         $dispatcher = Factory::getApplication()->getDispatcher(); | ||||
|  | ||||
|         // Load the finder plugin group. | ||||
|         PluginHelper::importPlugin('finder', null, true, $dispatcher); | ||||
|  | ||||
|         $dispatcher->dispatch('onPrepareFinderContent', new PrepareContentEvent('onPrepareFinderContent', [ | ||||
|             'subject' => $item, | ||||
|         ])); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add custom fields for the item to the Result object | ||||
|      * | ||||
|      * @param   Result  $item     Result object to add the custom fields to | ||||
|      * @param   string  $context  Context of the item in the custom fields | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public static function addCustomFields(Result $item, $context) | ||||
|     { | ||||
|         if (!ComponentHelper::getParams(strstr($context, '.', true))->get('custom_fields_enable', 1)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $obj     = new \stdClass(); | ||||
|         $obj->id = $item->id; | ||||
|  | ||||
|         $fields = FieldsHelper::getFields($context, $obj, true); | ||||
|  | ||||
|         foreach ($fields as $field) { | ||||
|             $searchindex = $field->params->get('searchindex', 0); | ||||
|  | ||||
|             // We want to add this field to the search index | ||||
|             if ($searchindex == self::CUSTOMFIELDS_ADD_TO_INDEX || $searchindex == self::CUSTOMFIELDS_ADD_TO_BOTH) { | ||||
|                 $name        = 'jsfield_' . $field->name; | ||||
|                 $item->$name = $field->value; | ||||
|                 $item->addInstruction(Indexer::META_CONTEXT, $name); | ||||
|             } | ||||
|  | ||||
|             // We want to add this field as a taxonomy | ||||
|             if ( | ||||
|                 ($searchindex == self::CUSTOMFIELDS_ADD_TO_TAXONOMY || $searchindex == self::CUSTOMFIELDS_ADD_TO_BOTH) | ||||
|                 && $field->value | ||||
|             ) { | ||||
|                 $item->addTaxonomy($field->title, $field->value, $field->state, $field->access, $field->language); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to process content text using the onContentPrepare event trigger. | ||||
|      * | ||||
|      * @param   string    $text    The content to process. | ||||
|      * @param   Registry  $params  The parameters object. [optional] | ||||
|      * @param   ?Result   $item    The item which get prepared. [optional] | ||||
|      * | ||||
|      * @return  string  The processed content. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function prepareContent($text, $params = null, ?Result $item = null) | ||||
|     { | ||||
|         static $loaded; | ||||
|  | ||||
|         // Load the content plugins if necessary. | ||||
|         if (empty($loaded)) { | ||||
|             PluginHelper::importPlugin('content'); | ||||
|             $loaded = true; | ||||
|         } | ||||
|  | ||||
|         // Instantiate the parameter object if necessary. | ||||
|         if (!($params instanceof Registry)) { | ||||
|             $registry = new Registry($params); | ||||
|             $params   = $registry; | ||||
|         } | ||||
|  | ||||
|         // Create a mock content object. | ||||
|         $content       = Table::getInstance('Content'); | ||||
|         $content->text = $text; | ||||
|  | ||||
|         if ($item) { | ||||
|             $content->bind((array) $item); | ||||
|             $content->bind($item->getElements()); | ||||
|         } | ||||
|  | ||||
|         if ($item && !empty($item->context)) { | ||||
|             $content->context = $item->context; | ||||
|         } | ||||
|  | ||||
|         // Fire the onContentPrepare event. | ||||
|         Factory::getApplication()->triggerEvent('onContentPrepare', ['com_finder.indexer', &$content, &$params, 0]); | ||||
|  | ||||
|         return $content->text; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1023
									
								
								administrator/components/com_finder/src/Indexer/Indexer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1023
									
								
								administrator/components/com_finder/src/Indexer/Indexer.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										182
									
								
								administrator/components/com_finder/src/Indexer/Language.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								administrator/components/com_finder/src/Indexer/Language.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,182 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\String\StringHelper; | ||||
| use Wamania\Snowball\NotFoundException; | ||||
| use Wamania\Snowball\Stemmer\Stemmer; | ||||
| use Wamania\Snowball\StemmerFactory; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Language support class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class Language | ||||
| { | ||||
|     /** | ||||
|      * Language support instances container. | ||||
|      * | ||||
|      * @var    Language[] | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected static $instances = []; | ||||
|  | ||||
|     /** | ||||
|      * Language locale of the class | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $language; | ||||
|  | ||||
|     /** | ||||
|      * Spacer to use between terms | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $spacer = ' '; | ||||
|  | ||||
|     /** | ||||
|      * The stemmer object. | ||||
|      * | ||||
|      * @var    Stemmer | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $stemmer = null; | ||||
|  | ||||
|     /** | ||||
|      * Method to construct the language object. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function __construct($locale = null) | ||||
|     { | ||||
|         if ($locale !== null) { | ||||
|             $this->language = $locale; | ||||
|         } | ||||
|  | ||||
|         // Use our generic language handler if no language is set | ||||
|         if ($this->language === null) { | ||||
|             $this->language = '*'; | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             foreach (StemmerFactory::LANGS as $classname => $isoCodes) { | ||||
|                 if (\in_array($this->language, $isoCodes)) { | ||||
|                     $this->stemmer = StemmerFactory::create($this->language); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } catch (NotFoundException $e) { | ||||
|             // We don't have a stemmer for the language | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get a language support object. | ||||
|      * | ||||
|      * @param   string  $language  The language of the support object. | ||||
|      * | ||||
|      * @return  Language  A Language instance. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public static function getInstance($language) | ||||
|     { | ||||
|         if (isset(self::$instances[$language])) { | ||||
|             return self::$instances[$language]; | ||||
|         } | ||||
|  | ||||
|         $locale = '*'; | ||||
|  | ||||
|         if ($language !== '*') { | ||||
|             $locale = Helper::getPrimaryLanguage($language); | ||||
|             $class  = '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Language\\' . ucfirst($locale); | ||||
|  | ||||
|             if (class_exists($class)) { | ||||
|                 self::$instances[$language] = new $class(); | ||||
|  | ||||
|                 return self::$instances[$language]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         self::$instances[$language] = new self($locale); | ||||
|  | ||||
|         return self::$instances[$language]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to tokenise a text string. | ||||
|      * | ||||
|      * @param   string  $input  The input to tokenise. | ||||
|      * | ||||
|      * @return  array  An array of term strings. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function tokenise($input) | ||||
|     { | ||||
|         $quotes = html_entity_decode('‘’'', ENT_QUOTES, 'UTF-8'); | ||||
|  | ||||
|         /* | ||||
|          * 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, 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 = StringHelper::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 = trim($input); | ||||
|  | ||||
|         // Explode the normalized string to get the terms. | ||||
|         $terms = explode(' ', $input); | ||||
|  | ||||
|         return $terms; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to stem a token. | ||||
|      * | ||||
|      * @param   string  $token  The token to stem. | ||||
|      * | ||||
|      * @return  string  The stemmed token. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function stem($token) | ||||
|     { | ||||
|         if ($this->stemmer !== null) { | ||||
|             return $this->stemmer->stem($token); | ||||
|         } | ||||
|  | ||||
|         return $token; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										934
									
								
								administrator/components/com_finder/src/Indexer/Language/El.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										934
									
								
								administrator/components/com_finder/src/Indexer/Language/El.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,934 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  * | ||||
|  * The Greek stemmer was adapted for Joomla! 4 by Nicholas K. Dionysopoulos <nicholas@akeebabackup.com>. This is | ||||
|  * derivative work, based on the Greek stemmer for Drupal, see | ||||
|  * https://github.com/magaras/greek_stemmer/blob/master/mod_stemmer.php | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer\Language; | ||||
|  | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Language; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Greek language support class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class El extends Language | ||||
| { | ||||
|     /** | ||||
|      * Language locale of the class | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $language = 'el'; | ||||
|  | ||||
|     /** | ||||
|      * Method to construct the language object. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function __construct($locale = null) | ||||
|     { | ||||
|         // Override parent constructor since we don't need to load an external stemmer | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to tokenise a text string. It takes into account the odd punctuation commonly used in Greek text, mapping | ||||
|      * it to ASCII punctuation. | ||||
|      * | ||||
|      * Reference: http://www.teicrete.gr/users/kutrulis/Glosika/Stixi.htm | ||||
|      * | ||||
|      * @param string $input The input to tokenise. | ||||
|      * | ||||
|      * @return  array  An array of term strings. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function tokenise($input) | ||||
|     { | ||||
|         // Replace Greek calligraphic double quotes (various styles) to dumb double quotes | ||||
|         $input = str_replace(['“', '”', '„', '«' ,'»'], '"', $input); | ||||
|  | ||||
|         // Replace Greek calligraphic single quotes (various styles) to dumb single quotes | ||||
|         $input = str_replace(['‘','’','‚'], "'", $input); | ||||
|  | ||||
|         // Replace the middle dot (ano teleia) with a comma, adequate for the purpose of stemming | ||||
|         $input = str_replace('·', ',', $input); | ||||
|  | ||||
|         // Dot and dash (τελεία και παύλα), used to denote the end of a context at the end of a paragraph. | ||||
|         $input = str_replace('.–', '.', $input); | ||||
|  | ||||
|         // Ellipsis, two styles (separate dots or single glyph) | ||||
|         $input = str_replace(['...', '…'], '.', $input); | ||||
|  | ||||
|         // Cross. Marks the death date of a person. Removed. | ||||
|         $input = str_replace('†', '', $input); | ||||
|  | ||||
|         // Star. Reference, supposition word (in philology), birth date of a person. | ||||
|         $input = str_replace('*', '', $input); | ||||
|  | ||||
|         // Paragraph. Indicates change of subject. | ||||
|         $input = str_replace('§', '.', $input); | ||||
|  | ||||
|         // Plus/minus. Shows approximation. Not relevant for the stemmer, hence its conversion to a space. | ||||
|         $input = str_replace('±', ' ', $input); | ||||
|  | ||||
|         return parent::tokenise($input); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to stem a token. | ||||
|      * | ||||
|      * @param   string  $token  The token to stem. | ||||
|      * | ||||
|      * @return  string  The stemmed token. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function stem($token) | ||||
|     { | ||||
|         $token = $this->toUpperCase($token, $wCase); | ||||
|  | ||||
|         // Stop-word removal | ||||
|         $stop_words = '/^(ΕΚΟ|ΑΒΑ|ΑΓΑ|ΑΓΗ|ΑΓΩ|ΑΔΗ|ΑΔΩ|ΑΕ|ΑΕΙ|ΑΘΩ|ΑΙ|ΑΙΚ|ΑΚΗ|ΑΚΟΜΑ|ΑΚΟΜΗ|ΑΚΡΙΒΩΣ|ΑΛΑ|ΑΛΗΘΕΙΑ|ΑΛΗΘΙΝΑ|ΑΛΛΑΧΟΥ|ΑΛΛΙΩΣ|ΑΛΛΙΩΤΙΚΑ|' | ||||
|                 . 'ΑΛΛΟΙΩΣ|ΑΛΛΟΙΩΤΙΚΑ|ΑΛΛΟΤΕ|ΑΛΤ|ΑΛΩ|ΑΜΑ|ΑΜΕ|ΑΜΕΣΑ|ΑΜΕΣΩΣ|ΑΜΩ|ΑΝ|ΑΝΑ|ΑΝΑΜΕΣΑ|ΑΝΑΜΕΤΑΞΥ|ΑΝΕΥ|ΑΝΤΙ|ΑΝΤΙΠΕΡΑ|ΑΝΤΙΣ|ΑΝΩ|ΑΝΩΤΕΡΩ|ΑΞΑΦΝΑ|' | ||||
|                 . 'ΑΠ|ΑΠΕΝΑΝΤΙ|ΑΠΟ|ΑΠΟΨΕ|ΑΠΩ|ΑΡΑ|ΑΡΑΓΕ|ΑΡΕ|ΑΡΚ|ΑΡΚΕΤΑ|ΑΡΛ|ΑΡΜ|ΑΡΤ|ΑΡΥ|ΑΡΩ|ΑΣ|ΑΣΑ|ΑΣΟ|ΑΤΑ|ΑΤΕ|ΑΤΗ|ΑΤΙ|ΑΤΜ|ΑΤΟ|ΑΥΡΙΟ|ΑΦΗ|ΑΦΟΤΟΥ|ΑΦΟΥ|' | ||||
|                 . 'ΑΧ|ΑΧΕ|ΑΧΟ|ΑΨΑ|ΑΨΕ|ΑΨΗ|ΑΨΥ|ΑΩΕ|ΑΩΟ|ΒΑΝ|ΒΑΤ|ΒΑΧ|ΒΕΑ|ΒΕΒΑΙΟΤΑΤΑ|ΒΗΞ|ΒΙΑ|ΒΙΕ|ΒΙΗ|ΒΙΟ|ΒΟΗ|ΒΟΩ|ΒΡΕ|ΓΑ|ΓΑΒ|ΓΑΡ|ΓΕΝ|ΓΕΣ||ΓΗ|ΓΗΝ|ΓΙ|ΓΙΑ|' | ||||
|                 . 'ΓΙΕ|ΓΙΝ|ΓΙΟ|ΓΚΙ|ΓΙΑΤΙ|ΓΚΥ|ΓΟΗ|ΓΟΟ|ΓΡΗΓΟΡΑ|ΓΡΙ|ΓΡΥ|ΓΥΗ|ΓΥΡΩ|ΔΑ|ΔΕ|ΔΕΗ|ΔΕΙ|ΔΕΝ|ΔΕΣ|ΔΗ|ΔΗΘΕΝ|ΔΗΛΑΔΗ|ΔΗΩ|ΔΙ|ΔΙΑ|ΔΙΑΡΚΩΣ|ΔΙΟΛΟΥ|ΔΙΣ|' | ||||
|                 . 'ΔΙΧΩΣ|ΔΟΛ|ΔΟΝ|ΔΡΑ|ΔΡΥ|ΔΡΧ|ΔΥΕ|ΔΥΟ|ΔΩ|ΕΑΜ|ΕΑΝ|ΕΑΡ|ΕΘΗ|ΕΙ|ΕΙΔΕΜΗ|ΕΙΘΕ|ΕΙΜΑΙ|ΕΙΜΑΣΤΕ|ΕΙΝΑΙ|ΕΙΣ|ΕΙΣΑΙ|ΕΙΣΑΣΤΕ|ΕΙΣΤΕ|ΕΙΤΕ|ΕΙΧΑ|ΕΙΧΑΜΕ|' | ||||
|                 . 'ΕΙΧΑΝ|ΕΙΧΑΤΕ|ΕΙΧΕ|ΕΙΧΕΣ|ΕΚ|ΕΚΕΙ|ΕΛΑ|ΕΛΙ|ΕΜΠ|ΕΝ|ΕΝΤΕΛΩΣ|ΕΝΤΟΣ|ΕΝΤΩΜΕΤΑΞΥ|ΕΝΩ|ΕΞ|ΕΞΑΦΝΑ|ΕΞΙ|ΕΞΙΣΟΥ|ΕΞΩ|ΕΟΚ|ΕΠΑΝΩ|ΕΠΕΙΔΗ|ΕΠΕΙΤΑ|ΕΠΗ|' | ||||
|                 . 'ΕΠΙ|ΕΠΙΣΗΣ|ΕΠΟΜΕΝΩΣ|ΕΡΑ|ΕΣ|ΕΣΑΣ|ΕΣΕ|ΕΣΕΙΣ|ΕΣΕΝΑ|ΕΣΗ|ΕΣΤΩ|ΕΣΥ|ΕΣΩ|ΕΤΙ|ΕΤΣΙ|ΕΥ|ΕΥΑ|ΕΥΓΕ|ΕΥΘΥΣ|ΕΥΤΥΧΩΣ|ΕΦΕ|ΕΦΕΞΗΣ|ΕΦΤ|ΕΧΕ|ΕΧΕΙ|' | ||||
|                 . 'ΕΧΕΙΣ|ΕΧΕΤΕ|ΕΧΘΕΣ|ΕΧΟΜΕ|ΕΧΟΥΜΕ|ΕΧΟΥΝ|ΕΧΤΕΣ|ΕΧΩ|ΕΩΣ|ΖΕΑ|ΖΕΗ|ΖΕΙ|ΖΕΝ|ΖΗΝ|ΖΩ|Η|ΗΔΗ|ΗΔΥ|ΗΘΗ|ΗΛΟ|ΗΜΙ|ΗΠΑ|ΗΣΑΣΤΕ|ΗΣΟΥΝ|ΗΤΑ|ΗΤΑΝ|ΗΤΑΝΕ|' | ||||
|                 . 'ΗΤΟΙ|ΗΤΤΟΝ|ΗΩ|ΘΑ|ΘΥΕ|ΘΩΡ|Ι|ΙΑ|ΙΒΟ|ΙΔΗ|ΙΔΙΩΣ|ΙΕ|ΙΙ|ΙΙΙ|ΙΚΑ|ΙΛΟ|ΙΜΑ|ΙΝΑ|ΙΝΩ|ΙΞΕ|ΙΞΟ|ΙΟ|ΙΟΙ|ΙΣΑ|ΙΣΑΜΕ|ΙΣΕ|ΙΣΗ|ΙΣΙΑ|ΙΣΟ|ΙΣΩΣ|ΙΩΒ|ΙΩΝ|' | ||||
|                 . 'ΙΩΣ|ΙΑΝ|ΚΑΘ|ΚΑΘΕ|ΚΑΘΕΤΙ|ΚΑΘΟΛΟΥ|ΚΑΘΩΣ|ΚΑΙ|ΚΑΝ|ΚΑΠΟΤΕ|ΚΑΠΟΥ|ΚΑΠΩΣ|ΚΑΤ|ΚΑΤΑ|ΚΑΤΙ|ΚΑΤΙΤΙ|ΚΑΤΟΠΙΝ|ΚΑΤΩ|ΚΑΩ|ΚΒΟ|ΚΕΑ|ΚΕΙ|ΚΕΝ|ΚΙ|ΚΙΜ|' | ||||
|                 . 'ΚΙΟΛΑΣ|ΚΙΤ|ΚΙΧ|ΚΚΕ|ΚΛΙΣΕ|ΚΛΠ|ΚΟΚ|ΚΟΝΤΑ|ΚΟΧ|ΚΤΛ|ΚΥΡ|ΚΥΡΙΩΣ|ΚΩ|ΚΩΝ|ΛΑ|ΛΕΑ|ΛΕΝ|ΛΕΟ|ΛΙΑ|ΛΙΓΑΚΙ|ΛΙΓΟΥΛΑΚΙ|ΛΙΓΟ|ΛΙΓΩΤΕΡΟ|ΛΙΟ|ΛΙΡ|ΛΟΓΩ|' | ||||
|                 . 'ΛΟΙΠΑ|ΛΟΙΠΟΝ|ΛΟΣ|ΛΣ|ΛΥΩ|ΜΑ|ΜΑΖΙ|ΜΑΚΑΡΙ|ΜΑΛΙΣΤΑ|ΜΑΛΛΟΝ|ΜΑΝ|ΜΑΞ|ΜΑΣ|ΜΑΤ|ΜΕ|ΜΕΘΑΥΡΙΟ|ΜΕΙ|ΜΕΙΟΝ|ΜΕΛ|ΜΕΛΕΙ|ΜΕΛΛΕΤΑΙ|ΜΕΜΙΑΣ|ΜΕΝ|ΜΕΣ|' | ||||
|                 . 'ΜΕΣΑ|ΜΕΤ|ΜΕΤΑ|ΜΕΤΑΞΥ|ΜΕΧΡΙ|ΜΗ|ΜΗΔΕ|ΜΗΝ|ΜΗΠΩΣ|ΜΗΤΕ|ΜΙ|ΜΙΞ|ΜΙΣ|ΜΜΕ|ΜΝΑ|ΜΟΒ|ΜΟΛΙΣ|ΜΟΛΟΝΟΤΙ|ΜΟΝΑΧΑ|ΜΟΝΟΜΙΑΣ|ΜΙΑ|ΜΟΥ|ΜΠΑ|ΜΠΟΡΕΙ|' | ||||
|                 . 'ΜΠΟΡΟΥΝ|ΜΠΡΑΒΟ|ΜΠΡΟΣ|ΜΠΩ|ΜΥ|ΜΥΑ|ΜΥΝ|ΝΑ|ΝΑΕ|ΝΑΙ|ΝΑΟ|ΝΔ|ΝΕΐ|ΝΕΑ|ΝΕΕ|ΝΕΟ|ΝΙ|ΝΙΑ|ΝΙΚ|ΝΙΛ|ΝΙΝ|ΝΙΟ|ΝΤΑ|ΝΤΕ|ΝΤΙ|ΝΤΟ|ΝΥΝ|ΝΩΕ|ΝΩΡΙΣ|ΞΑΝΑ|' | ||||
|                 . 'ΞΑΦΝΙΚΑ|ΞΕΩ|ΞΙ|Ο|ΟΑ|ΟΑΠ|ΟΔΟ|ΟΕ|ΟΖΟ|ΟΗΕ|ΟΙ|ΟΙΑ|ΟΙΗ|ΟΚΑ|ΟΛΟΓΥΡΑ|ΟΛΟΝΕΝ|ΟΛΟΤΕΛΑ|ΟΛΩΣΔΙΟΛΟΥ|ΟΜΩΣ|ΟΝ|ΟΝΕ|ΟΝΟ|ΟΠΑ|ΟΠΕ|ΟΠΗ|ΟΠΟ|' | ||||
|                 . 'ΟΠΟΙΑΔΗΠΟΤΕ|ΟΠΟΙΑΝΔΗΠΟΤΕ|ΟΠΟΙΑΣΔΗΠΟΤΕ|ΟΠΟΙΔΗΠΟΤΕ|ΟΠΟΙΕΣΔΗΠΟΤΕ|ΟΠΟΙΟΔΗΠΟΤΕ|ΟΠΟΙΟΝΔΗΠΟΤΕ|ΟΠΟΙΟΣΔΗΠΟΤΕ|ΟΠΟΙΟΥΔΗΠΟΤΕ|ΟΠΟΙΟΥΣΔΗΠΟΤΕ|' | ||||
|                 . 'ΟΠΟΙΩΝΔΗΠΟΤΕ|ΟΠΟΤΕΔΗΠΟΤΕ|ΟΠΟΥ|ΟΠΟΥΔΗΠΟΤΕ|ΟΠΩΣ|ΟΡΑ|ΟΡΕ|ΟΡΗ|ΟΡΟ|ΟΡΦ|ΟΡΩ|ΟΣΑ|ΟΣΑΔΗΠΟΤΕ|ΟΣΕ|ΟΣΕΣΔΗΠΟΤΕ|ΟΣΗΔΗΠΟΤΕ|ΟΣΗΝΔΗΠΟΤΕ|' | ||||
|                 . 'ΟΣΗΣΔΗΠΟΤΕ|ΟΣΟΔΗΠΟΤΕ|ΟΣΟΙΔΗΠΟΤΕ|ΟΣΟΝΔΗΠΟΤΕ|ΟΣΟΣΔΗΠΟΤΕ|ΟΣΟΥΔΗΠΟΤΕ|ΟΣΟΥΣΔΗΠΟΤΕ|ΟΣΩΝΔΗΠΟΤΕ|ΟΤΑΝ|ΟΤΕ|ΟΤΙ|ΟΤΙΔΗΠΟΤΕ|ΟΥ|ΟΥΔΕ|ΟΥΚ|ΟΥΣ|' | ||||
|                 . 'ΟΥΤΕ|ΟΥΦ|ΟΧΙ|ΟΨΑ|ΟΨΕ|ΟΨΗ|ΟΨΙ|ΟΨΟ|ΠΑ|ΠΑΛΙ|ΠΑΝ|ΠΑΝΤΟΤΕ|ΠΑΝΤΟΥ|ΠΑΝΤΩΣ|ΠΑΠ|ΠΑΡ|ΠΑΡΑ|ΠΕΙ|ΠΕΡ|ΠΕΡΑ|ΠΕΡΙ|ΠΕΡΙΠΟΥ|ΠΕΡΣΙ|ΠΕΡΥΣΙ|ΠΕΣ|ΠΙ|' | ||||
|                 . 'ΠΙΑ|ΠΙΘΑΝΟΝ|ΠΙΚ|ΠΙΟ|ΠΙΣΩ|ΠΙΤ|ΠΙΩ|ΠΛΑΙ|ΠΛΕΟΝ|ΠΛΗΝ|ΠΛΩ|ΠΜ|ΠΟΑ|ΠΟΕ|ΠΟΛ|ΠΟΛΥ|ΠΟΠ|ΠΟΤΕ|ΠΟΥ|ΠΟΥΘΕ|ΠΟΥΘΕΝΑ|ΠΡΕΠΕΙ|ΠΡΙ|ΠΡΙΝ|ΠΡΟ|' | ||||
|                 . 'ΠΡΟΚΕΙΜΕΝΟΥ|ΠΡΟΚΕΙΤΑΙ|ΠΡΟΠΕΡΣΙ|ΠΡΟΣ|ΠΡΟΤΟΥ|ΠΡΟΧΘΕΣ|ΠΡΟΧΤΕΣ|ΠΡΩΤΥΤΕΡΑ|ΠΥΑ|ΠΥΞ|ΠΥΟ|ΠΥΡ|ΠΧ|ΠΩ|ΠΩΛ|ΠΩΣ|ΡΑ|ΡΑΙ|ΡΑΠ|ΡΑΣ|ΡΕ|ΡΕΑ|ΡΕΕ|ΡΕΙ|' | ||||
|                 . 'ΡΗΣ|ΡΘΩ|ΡΙΟ|ΡΟ|ΡΟΐ|ΡΟΕ|ΡΟΖ|ΡΟΗ|ΡΟΘ|ΡΟΙ|ΡΟΚ|ΡΟΛ|ΡΟΝ|ΡΟΣ|ΡΟΥ|ΣΑΙ|ΣΑΝ|ΣΑΟ|ΣΑΣ|ΣΕ|ΣΕΙΣ|ΣΕΚ|ΣΕΞ|ΣΕΡ|ΣΕΤ|ΣΕΦ|ΣΗΜΕΡΑ|ΣΙ|ΣΙΑ|ΣΙΓΑ|ΣΙΚ|' | ||||
|                 . 'ΣΙΧ|ΣΚΙ|ΣΟΙ|ΣΟΚ|ΣΟΛ|ΣΟΝ|ΣΟΣ|ΣΟΥ|ΣΡΙ|ΣΤΑ|ΣΤΗ|ΣΤΗΝ|ΣΤΗΣ|ΣΤΙΣ|ΣΤΟ|ΣΤΟΝ|ΣΤΟΥ|ΣΤΟΥΣ|ΣΤΩΝ|ΣΥ|ΣΥΓΧΡΟΝΩΣ|ΣΥΝ|ΣΥΝΑΜΑ|ΣΥΝΕΠΩΣ|ΣΥΝΗΘΩΣ|' | ||||
|                 . 'ΣΧΕΔΟΝ|ΣΩΣΤΑ|ΤΑ|ΤΑΔΕ|ΤΑΚ|ΤΑΝ|ΤΑΟ|ΤΑΥ|ΤΑΧΑ|ΤΑΧΑΤΕ|ΤΕ|ΤΕΙ|ΤΕΛ|ΤΕΛΙΚΑ|ΤΕΛΙΚΩΣ|ΤΕΣ|ΤΕΤ|ΤΖΟ|ΤΗ|ΤΗΛ|ΤΗΝ|ΤΗΣ|ΤΙ|ΤΙΚ|ΤΙΜ|ΤΙΠΟΤΑ|ΤΙΠΟΤΕ|' | ||||
|                 . 'ΤΙΣ|ΤΝΤ|ΤΟ|ΤΟΙ|ΤΟΚ|ΤΟΜ|ΤΟΝ|ΤΟΠ|ΤΟΣ|ΤΟΣ?Ν|ΤΟΣΑ|ΤΟΣΕΣ|ΤΟΣΗ|ΤΟΣΗΝ|ΤΟΣΗΣ|ΤΟΣΟ|ΤΟΣΟΙ|ΤΟΣΟΝ|ΤΟΣΟΣ|ΤΟΣΟΥ|ΤΟΣΟΥΣ|ΤΟΤΕ|ΤΟΥ|ΤΟΥΛΑΧΙΣΤΟ|' | ||||
|                 . 'ΤΟΥΛΑΧΙΣΤΟΝ|ΤΟΥΣ|ΤΣ|ΤΣΑ|ΤΣΕ|ΤΥΧΟΝ|ΤΩ|ΤΩΝ|ΤΩΡΑ|ΥΑΣ|ΥΒΑ|ΥΒΟ|ΥΙΕ|ΥΙΟ|ΥΛΑ|ΥΛΗ|ΥΝΙ|ΥΠ|ΥΠΕΡ|ΥΠΟ|ΥΠΟΨΗ|ΥΠΟΨΙΝ|ΥΣΤΕΡΑ|ΥΦΗ|ΥΨΗ|ΦΑ|ΦΑΐ|ΦΑΕ|' | ||||
|                 . 'ΦΑΝ|ΦΑΞ|ΦΑΣ|ΦΑΩ|ΦΕΖ|ΦΕΙ|ΦΕΤΟΣ|ΦΕΥ|ΦΙ|ΦΙΛ|ΦΙΣ|ΦΟΞ|ΦΠΑ|ΦΡΙ|ΧΑ|ΧΑΗ|ΧΑΛ|ΧΑΝ|ΧΑΦ|ΧΕ|ΧΕΙ|ΧΘΕΣ|ΧΙ|ΧΙΑ|ΧΙΛ|ΧΙΟ|ΧΛΜ|ΧΜ|ΧΟΗ|ΧΟΛ|ΧΡΩ|ΧΤΕΣ|' | ||||
|                 . 'ΧΩΡΙΣ|ΧΩΡΙΣΤΑ|ΨΕΣ|ΨΗΛΑ|ΨΙ|ΨΙΤ|Ω|ΩΑ|ΩΑΣ|ΩΔΕ|ΩΕΣ|ΩΘΩ|ΩΜΑ|ΩΜΕ|ΩΝ|ΩΟ|ΩΟΝ|ΩΟΥ|ΩΣ|ΩΣΑΝ|ΩΣΗ|ΩΣΟΤΟΥ|ΩΣΠΟΥ|ΩΣΤΕ|ΩΣΤΟΣΟ|ΩΤΑ|ΩΧ|ΩΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($stop_words, $token)) { | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Vowels | ||||
|         $v = '(Α|Ε|Η|Ι|Ο|Υ|Ω)'; | ||||
|  | ||||
|         // Vowels without Y | ||||
|         $v2 = '(Α|Ε|Η|Ι|Ο|Ω)'; | ||||
|  | ||||
|         $test1 = true; | ||||
|  | ||||
|         // Step S1. 14 stems | ||||
|         $re       = '/^(.+?)(ΙΖΑ|ΙΖΕΣ|ΙΖΕ|ΙΖΑΜΕ|ΙΖΑΤΕ|ΙΖΑΝ|ΙΖΑΝΕ|ΙΖΩ|ΙΖΕΙΣ|ΙΖΕΙ|ΙΖΟΥΜΕ|ΙΖΕΤΕ|ΙΖΟΥΝ|ΙΖΟΥΝΕ)$/'; | ||||
|         $exceptS1 = '/^(ΑΝΑΜΠΑ|ΕΜΠΑ|ΕΠΑ|ΞΑΝΑΠΑ|ΠΑ|ΠΕΡΙΠΑ|ΑΘΡΟ|ΣΥΝΑΘΡΟ|ΔΑΝΕ)$/'; | ||||
|         $exceptS2 = '/^(ΜΑΡΚ|ΚΟΡΝ|ΑΜΠΑΡ|ΑΡΡ|ΒΑΘΥΡΙ|ΒΑΡΚ|Β|ΒΟΛΒΟΡ|ΓΚΡ|ΓΛΥΚΟΡ|ΓΛΥΚΥΡ|ΙΜΠ|Λ|ΛΟΥ|ΜΑΡ|Μ|ΠΡ|ΜΠΡ|ΠΟΛΥΡ|Π|Ρ|ΠΙΠΕΡΟΡ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= 'I'; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= 'IΖ'; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S2. 7 stems | ||||
|         $re       = '/^(.+?)(ΩΘΗΚΑ|ΩΘΗΚΕΣ|ΩΘΗΚΕ|ΩΘΗΚΑΜΕ|ΩΘΗΚΑΤΕ|ΩΘΗΚΑΝ|ΩΘΗΚΑΝΕ)$/'; | ||||
|         $exceptS1 = '/^(ΑΛ|ΒΙ|ΕΝ|ΥΨ|ΛΙ|ΖΩ|Σ|Χ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= 'ΩΝ'; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S3. 7 stems | ||||
|         $re       = '/^(.+?)(ΙΣΑ|ΙΣΕΣ|ΙΣΕ|ΙΣΑΜΕ|ΙΣΑΤΕ|ΙΣΑΝ|ΙΣΑΝΕ)$/'; | ||||
|         $exceptS1 = '/^(ΑΝΑΜΠΑ|ΑΘΡΟ|ΕΜΠΑ|ΕΣΕ|ΕΣΩΚΛΕ|ΕΠΑ|ΞΑΝΑΠΑ|ΕΠΕ|ΠΕΡΙΠΑ|ΑΘΡΟ|ΣΥΝΑΘΡΟ|ΔΑΝΕ|ΚΛΕ|ΧΑΡΤΟΠΑ|ΕΞΑΡΧΑ|ΜΕΤΕΠΕ|ΑΠΟΚΛΕ|ΑΠΕΚΛΕ|ΕΚΛΕ|ΠΕ|ΠΕΡΙΠΑ)$/'; | ||||
|         $exceptS2 = '/^(ΑΝ|ΑΦ|ΓΕ|ΓΙΓΑΝΤΟΑΦ|ΓΚΕ|ΔΗΜΟΚΡΑΤ|ΚΟΜ|ΓΚ|Μ|Π|ΠΟΥΚΑΜ|ΟΛΟ|ΛΑΡ)$/'; | ||||
|  | ||||
|         if ($token == "ΙΣΑ") { | ||||
|             $token = "ΙΣ"; | ||||
|  | ||||
|             return $token; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= 'Ι'; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= 'ΙΣ'; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S4. 7 stems | ||||
|         $re       = '/^(.+?)(ΙΣΩ|ΙΣΕΙΣ|ΙΣΕΙ|ΙΣΟΥΜΕ|ΙΣΕΤΕ|ΙΣΟΥΝ|ΙΣΟΥΝΕ)$/'; | ||||
|         $exceptS1 = '/^(ΑΝΑΜΠΑ|ΕΜΠΑ|ΕΣΕ|ΕΣΩΚΛΕ|ΕΠΑ|ΞΑΝΑΠΑ|ΕΠΕ|ΠΕΡΙΠΑ|ΑΘΡΟ|ΣΥΝΑΘΡΟ|ΔΑΝΕ|ΚΛΕ|ΧΑΡΤΟΠΑ|ΕΞΑΡΧΑ|ΜΕΤΕΠΕ|ΑΠΟΚΛΕ|ΑΠΕΚΛΕ|ΕΚΛΕ|ΠΕ|ΠΕΡΙΠΑ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= 'Ι'; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S5. 11 stems | ||||
|         $re       = '/^(.+?)(ΙΣΤΟΣ|ΙΣΤΟΥ|ΙΣΤΟ|ΙΣΤΕ|ΙΣΤΟΙ|ΙΣΤΩΝ|ΙΣΤΟΥΣ|ΙΣΤΗ|ΙΣΤΗΣ|ΙΣΤΑ|ΙΣΤΕΣ)$/'; | ||||
|         $exceptS1 = '/^(Μ|Π|ΑΠ|ΑΡ|ΗΔ|ΚΤ|ΣΚ|ΣΧ|ΥΨ|ΦΑ|ΧΡ|ΧΤ|ΑΚΤ|ΑΟΡ|ΑΣΧ|ΑΤΑ|ΑΧΝ|ΑΧΤ|ΓΕΜ|ΓΥΡ|ΕΜΠ|ΕΥΠ|ΕΧΘ|ΗΦΑ|ΚΑΘ|ΚΑΚ|ΚΥΛ|ΛΥΓ|ΜΑΚ|ΜΕΓ|ΤΑΧ|ΦΙΛ|ΧΩΡ)$/'; | ||||
|         $exceptS2 = '/^(ΔΑΝΕ|ΣΥΝΑΘΡΟ|ΚΛΕ|ΣΕ|ΕΣΩΚΛΕ|ΑΣΕ|ΠΛΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= 'ΙΣΤ'; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= 'Ι'; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S6. 6 stems | ||||
|         $re       = '/^(.+?)(ΙΣΜΟ|ΙΣΜΟΙ|ΙΣΜΟΣ|ΙΣΜΟΥ|ΙΣΜΟΥΣ|ΙΣΜΩΝ)$/'; | ||||
|         $exceptS1 = '/^(ΑΓΝΩΣΤΙΚ|ΑΤΟΜΙΚ|ΓΝΩΣΤΙΚ|ΕΘΝΙΚ|ΕΚΛΕΚΤΙΚ|ΣΚΕΠΤΙΚ|ΤΟΠΙΚ)$/'; | ||||
|         $exceptS2 = '/^(ΣΕ|ΜΕΤΑΣΕ|ΜΙΚΡΟΣΕ|ΕΓΚΛΕ|ΑΠΟΚΛΕ)$/'; | ||||
|         $exceptS3 = '/^(ΔΑΝΕ|ΑΝΤΙΔΑΝΕ)$/'; | ||||
|         $exceptS4 = '/^(ΑΛΕΞΑΝΔΡΙΝ|ΒΥΖΑΝΤΙΝ|ΘΕΑΤΡΙΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token = str_replace('ΙΚ', "", $token); | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= "ΙΣΜ"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS3, $token)) { | ||||
|                 $token .= "Ι"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS4, $token)) { | ||||
|                 $token = str_replace('ΙΝ', "", $token); | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S7. 4 stems | ||||
|         $re       = '/^(.+?)(ΑΡΑΚΙ|ΑΡΑΚΙΑ|ΟΥΔΑΚΙ|ΟΥΔΑΚΙΑ)$/'; | ||||
|         $exceptS1 = '/^(Σ|Χ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= "AΡΑΚ"; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S8. 8 stems | ||||
|         $re       = '/^(.+?)(ΑΚΙ|ΑΚΙΑ|ΙΤΣΑ|ΙΤΣΑΣ|ΙΤΣΕΣ|ΙΤΣΩΝ|ΑΡΑΚΙ|ΑΡΑΚΙΑ)$/'; | ||||
|         $exceptS1 = '/^(ΑΝΘΡ|ΒΑΜΒ|ΒΡ|ΚΑΙΜ|ΚΟΝ|ΚΟΡ|ΛΑΒΡ|ΛΟΥΛ|ΜΕΡ|ΜΟΥΣΤ|ΝΑΓΚΑΣ|ΠΛ|Ρ|ΡΥ|Σ|ΣΚ|ΣΟΚ|ΣΠΑΝ|ΤΖ|ΦΑΡΜ|Χ|' | ||||
|                 . 'ΚΑΠΑΚ|ΑΛΙΣΦ|ΑΜΒΡ|ΑΝΘΡ|Κ|ΦΥΛ|ΚΑΤΡΑΠ|ΚΛΙΜ|ΜΑΛ|ΣΛΟΒ|Φ|ΣΦ|ΤΣΕΧΟΣΛΟΒ)$/'; | ||||
|         $exceptS2 = '/^(Β|ΒΑΛ|ΓΙΑΝ|ΓΛ|Ζ|ΗΓΟΥΜΕΝ|ΚΑΡΔ|ΚΟΝ|ΜΑΚΡΥΝ|ΝΥΦ|ΠΑΤΕΡ|Π|ΣΚ|ΤΟΣ|ΤΡΙΠΟΛ)$/'; | ||||
|  | ||||
|         // For words like ΠΛΟΥΣΙΟΚΟΡΙΤΣΑ, ΠΑΛΙΟΚΟΡΙΤΣΑ etc | ||||
|         $exceptS3 = '/(ΚΟΡ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= "ΑΚ"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= "ΙΤΣ"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS3, $token)) { | ||||
|                 $token .= "ΙΤΣ"; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S9. 3 stems | ||||
|         $re       = '/^(.+?)(ΙΔΙΟ|ΙΔΙΑ|ΙΔΙΩΝ)$/'; | ||||
|         $exceptS1 = '/^(ΑΙΦΝ|ΙΡ|ΟΛΟ|ΨΑΛ)$/'; | ||||
|         $exceptS2 = '/(Ε|ΠΑΙΧΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= "ΙΔ"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exceptS2, $token)) { | ||||
|                 $token .= "ΙΔ"; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step S10. 4 stems | ||||
|         $re       = '/^(.+?)(ΙΣΚΟΣ|ΙΣΚΟΥ|ΙΣΚΟ|ΙΣΚΕ)$/'; | ||||
|         $exceptS1 = '/^(Δ|ΙΒ|ΜΗΝ|Ρ|ΦΡΑΓΚ|ΛΥΚ|ΟΒΕΛ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             if (preg_match($exceptS1, $token)) { | ||||
|                 $token .= "ΙΣΚ"; | ||||
|             } | ||||
|  | ||||
|             return $this->toLowerCase($token, $wCase); | ||||
|         } | ||||
|  | ||||
|         // Step 1 | ||||
|         // step1list is used in Step 1. 41 stems | ||||
|         $step1list             = []; | ||||
|         $step1list["ΦΑΓΙΑ"]    = "ΦΑ"; | ||||
|         $step1list["ΦΑΓΙΟΥ"]   = "ΦΑ"; | ||||
|         $step1list["ΦΑΓΙΩΝ"]   = "ΦΑ"; | ||||
|         $step1list["ΣΚΑΓΙΑ"]   = "ΣΚΑ"; | ||||
|         $step1list["ΣΚΑΓΙΟΥ"]  = "ΣΚΑ"; | ||||
|         $step1list["ΣΚΑΓΙΩΝ"]  = "ΣΚΑ"; | ||||
|         $step1list["ΟΛΟΓΙΟΥ"]  = "ΟΛΟ"; | ||||
|         $step1list["ΟΛΟΓΙΑ"]   = "ΟΛΟ"; | ||||
|         $step1list["ΟΛΟΓΙΩΝ"]  = "ΟΛΟ"; | ||||
|         $step1list["ΣΟΓΙΟΥ"]   = "ΣΟ"; | ||||
|         $step1list["ΣΟΓΙΑ"]    = "ΣΟ"; | ||||
|         $step1list["ΣΟΓΙΩΝ"]   = "ΣΟ"; | ||||
|         $step1list["ΤΑΤΟΓΙΑ"]  = "ΤΑΤΟ"; | ||||
|         $step1list["ΤΑΤΟΓΙΟΥ"] = "ΤΑΤΟ"; | ||||
|         $step1list["ΤΑΤΟΓΙΩΝ"] = "ΤΑΤΟ"; | ||||
|         $step1list["ΚΡΕΑΣ"]    = "ΚΡΕ"; | ||||
|         $step1list["ΚΡΕΑΤΟΣ"]  = "ΚΡΕ"; | ||||
|         $step1list["ΚΡΕΑΤΑ"]   = "ΚΡΕ"; | ||||
|         $step1list["ΚΡΕΑΤΩΝ"]  = "ΚΡΕ"; | ||||
|         $step1list["ΠΕΡΑΣ"]    = "ΠΕΡ"; | ||||
|         $step1list["ΠΕΡΑΤΟΣ"]  = "ΠΕΡ"; | ||||
|  | ||||
|         // Added by Spyros. Also at $re in step1 | ||||
|         $step1list["ΠΕΡΑΤΗ"]     = "ΠΕΡ"; | ||||
|         $step1list["ΠΕΡΑΤΑ"]     = "ΠΕΡ"; | ||||
|         $step1list["ΠΕΡΑΤΩΝ"]    = "ΠΕΡ"; | ||||
|         $step1list["ΤΕΡΑΣ"]      = "ΤΕΡ"; | ||||
|         $step1list["ΤΕΡΑΤΟΣ"]    = "ΤΕΡ"; | ||||
|         $step1list["ΤΕΡΑΤΑ"]     = "ΤΕΡ"; | ||||
|         $step1list["ΤΕΡΑΤΩΝ"]    = "ΤΕΡ"; | ||||
|         $step1list["ΦΩΣ"]        = "ΦΩ"; | ||||
|         $step1list["ΦΩΤΟΣ"]      = "ΦΩ"; | ||||
|         $step1list["ΦΩΤΑ"]       = "ΦΩ"; | ||||
|         $step1list["ΦΩΤΩΝ"]      = "ΦΩ"; | ||||
|         $step1list["ΚΑΘΕΣΤΩΣ"]   = "ΚΑΘΕΣΤ"; | ||||
|         $step1list["ΚΑΘΕΣΤΩΤΟΣ"] = "ΚΑΘΕΣΤ"; | ||||
|         $step1list["ΚΑΘΕΣΤΩΤΑ"]  = "ΚΑΘΕΣΤ"; | ||||
|         $step1list["ΚΑΘΕΣΤΩΤΩΝ"] = "ΚΑΘΕΣΤ"; | ||||
|         $step1list["ΓΕΓΟΝΟΣ"]    = "ΓΕΓΟΝ"; | ||||
|         $step1list["ΓΕΓΟΝΟΤΟΣ"]  = "ΓΕΓΟΝ"; | ||||
|         $step1list["ΓΕΓΟΝΟΤΑ"]   = "ΓΕΓΟΝ"; | ||||
|         $step1list["ΓΕΓΟΝΟΤΩΝ"]  = "ΓΕΓΟΝ"; | ||||
|  | ||||
|         $re = '/(.*)(ΦΑΓΙΑ|ΦΑΓΙΟΥ|ΦΑΓΙΩΝ|ΣΚΑΓΙΑ|ΣΚΑΓΙΟΥ|ΣΚΑΓΙΩΝ|ΟΛΟΓΙΟΥ|ΟΛΟΓΙΑ|ΟΛΟΓΙΩΝ|ΣΟΓΙΟΥ|ΣΟΓΙΑ|ΣΟΓΙΩΝ|ΤΑΤΟΓΙΑ|ΤΑΤΟΓΙΟΥ|ΤΑΤΟΓΙΩΝ|ΚΡΕΑΣ|ΚΡΕΑΤΟΣ|' | ||||
|                 . 'ΚΡΕΑΤΑ|ΚΡΕΑΤΩΝ|ΠΕΡΑΣ|ΠΕΡΑΤΟΣ|ΠΕΡΑΤΗ|ΠΕΡΑΤΑ|ΠΕΡΑΤΩΝ|ΤΕΡΑΣ|ΤΕΡΑΤΟΣ|ΤΕΡΑΤΑ|ΤΕΡΑΤΩΝ|ΦΩΣ|ΦΩΤΟΣ|ΦΩΤΑ|ΦΩΤΩΝ|ΚΑΘΕΣΤΩΣ|ΚΑΘΕΣΤΩΤΟΣ|' | ||||
|                 . 'ΚΑΘΕΣΤΩΤΑ|ΚΑΘΕΣΤΩΤΩΝ|ΓΕΓΟΝΟΣ|ΓΕΓΟΝΟΤΟΣ|ΓΕΓΟΝΟΤΑ|ΓΕΓΟΝΟΤΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $stem   = $match[1]; | ||||
|             $suffix = $match[2]; | ||||
|             $token  = $stem . (\array_key_exists($suffix, $step1list) ? $step1list[$suffix] : ''); | ||||
|             $test1  = false; | ||||
|         } | ||||
|  | ||||
|         // Step 2a. 2 stems | ||||
|         $re = '/^(.+?)(ΑΔΕΣ|ΑΔΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1]; | ||||
|             $re    = '/(ΟΚ|ΜΑΜ|ΜΑΝ|ΜΠΑΜΠ|ΠΑΤΕΡ|ΓΙΑΓΙ|ΝΤΑΝΤ|ΚΥΡ|ΘΕΙ|ΠΕΘΕΡ)$/'; | ||||
|  | ||||
|             if (!preg_match($re, $token)) { | ||||
|                 $token .= "ΑΔ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 2b. 2 stems | ||||
|         $re = '/^(.+?)(ΕΔΕΣ|ΕΔΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $exept2 = '/(ΟΠ|ΙΠ|ΕΜΠ|ΥΠ|ΓΗΠ|ΔΑΠ|ΚΡΑΣΠ|ΜΙΛ)$/'; | ||||
|  | ||||
|             if (preg_match($exept2, $token)) { | ||||
|                 $token .= 'ΕΔ'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 2c | ||||
|         $re = '/^(.+?)(ΟΥΔΕΣ|ΟΥΔΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token = $match[1]; | ||||
|  | ||||
|             $exept3 = '/(ΑΡΚ|ΚΑΛΙΑΚ|ΠΕΤΑΛ|ΛΙΧ|ΠΛΕΞ|ΣΚ|Σ|ΦΛ|ΦΡ|ΒΕΛ|ΛΟΥΛ|ΧΝ|ΣΠ|ΤΡΑΓ|ΦΕ)$/'; | ||||
|  | ||||
|             if (preg_match($exept3, $token)) { | ||||
|                 $token .= 'ΟΥΔ'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 2d | ||||
|         $re = '/^(.+?)(ΕΩΣ|ΕΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $test1  = false; | ||||
|             $exept4 = '/^(Θ|Δ|ΕΛ|ΓΑΛ|Ν|Π|ΙΔ|ΠΑΡ)$/'; | ||||
|  | ||||
|             if (preg_match($exept4, $token)) { | ||||
|                 $token .= 'Ε'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 3 | ||||
|         $re = '/^(.+?)(ΙΑ|ΙΟΥ|ΙΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $fp)) { | ||||
|             $stem  = $fp[1]; | ||||
|             $token = $stem; | ||||
|             $re    = '/' . $v . '$/'; | ||||
|             $test1 = false; | ||||
|  | ||||
|             if (preg_match($re, $token)) { | ||||
|                 $token = $stem . 'Ι'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 4 | ||||
|         $re = '/^(.+?)(ΙΚΑ|ΙΚΟ|ΙΚΟΥ|ΙΚΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $test1  = false; | ||||
|             $re     = '/' . $v . '$/'; | ||||
|             $exept5 = '/^(ΑΛ|ΑΔ|ΕΝΔ|ΑΜΑΝ|ΑΜΜΟΧΑΛ|ΗΘ|ΑΝΗΘ|ΑΝΤΙΔ|ΦΥΣ|ΒΡΩΜ|ΓΕΡ|ΕΞΩΔ|ΚΑΛΠ|ΚΑΛΛΙΝ|ΚΑΤΑΔ|ΜΟΥΛ|ΜΠΑΝ|ΜΠΑΓΙΑΤ|ΜΠΟΛ|ΜΠΟΣ|ΝΙΤ|ΞΙΚ|ΣΥΝΟΜΗΛ|ΠΕΤΣ|' | ||||
|                     . 'ΠΙΤΣ|ΠΙΚΑΝΤ|ΠΛΙΑΤΣ|ΠΟΣΤΕΛΝ|ΠΡΩΤΟΔ|ΣΕΡΤ|ΣΥΝΑΔ|ΤΣΑΜ|ΥΠΟΔ|ΦΙΛΟΝ|ΦΥΛΟΔ|ΧΑΣ)$/'; | ||||
|  | ||||
|             if (preg_match($re, $token) || preg_match($exept5, $token)) { | ||||
|                 $token .= 'ΙΚ'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5a | ||||
|         $re  = '/^(.+?)(ΑΜΕ)$/'; | ||||
|         $re2 = '/^(.+?)(ΑΓΑΜΕ|ΗΣΑΜΕ|ΟΥΣΑΜΕ|ΗΚΑΜΕ|ΗΘΗΚΑΜΕ)$/'; | ||||
|  | ||||
|         if ($token == "ΑΓΑΜΕ") { | ||||
|             $token = "ΑΓΑΜ"; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re2, $token)) { | ||||
|             preg_match($re2, $token, $match); | ||||
|             $token = $match[1]; | ||||
|             $test1 = false; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $test1  = false; | ||||
|             $exept6 = '/^(ΑΝΑΠ|ΑΠΟΘ|ΑΠΟΚ|ΑΠΟΣΤ|ΒΟΥΒ|ΞΕΘ|ΟΥΛ|ΠΕΘ|ΠΙΚΡ|ΠΟΤ|ΣΙΧ|Χ)$/'; | ||||
|  | ||||
|             if (preg_match($exept6, $token)) { | ||||
|                 $token .= "ΑΜ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5b | ||||
|         $re2 = '/^(.+?)(ΑΝΕ)$/'; | ||||
|         $re3 = '/^(.+?)(ΑΓΑΝΕ|ΗΣΑΝΕ|ΟΥΣΑΝΕ|ΙΟΝΤΑΝΕ|ΙΟΤΑΝΕ|ΙΟΥΝΤΑΝΕ|ΟΝΤΑΝΕ|ΟΤΑΝΕ|ΟΥΝΤΑΝΕ|ΗΚΑΝΕ|ΗΘΗΚΑΝΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re3, $token)) { | ||||
|             preg_match($re3, $token, $match); | ||||
|             $token = $match[1]; | ||||
|             $test1 = false; | ||||
|             $re3   = '/^(ΤΡ|ΤΣ)$/'; | ||||
|  | ||||
|             if (preg_match($re3, $token)) { | ||||
|                 $token .= "ΑΓΑΝ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re2, $token)) { | ||||
|             preg_match($re2, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $test1  = false; | ||||
|             $re2    = '/' . $v2 . '$/'; | ||||
|             $exept7 = '/^(ΒΕΤΕΡ|ΒΟΥΛΚ|ΒΡΑΧΜ|Γ|ΔΡΑΔΟΥΜ|Θ|ΚΑΛΠΟΥΖ|ΚΑΣΤΕΛ|ΚΟΡΜΟΡ|ΛΑΟΠΛ|ΜΩΑΜΕΘ|Μ|ΜΟΥΣΟΥΛΜ|Ν|ΟΥΛ|Π|ΠΕΛΕΚ|ΠΛ|ΠΟΛΙΣ|ΠΟΡΤΟΛ|ΣΑΡΑΚΑΤΣ|ΣΟΥΛΤ|' | ||||
|                     . 'ΤΣΑΡΛΑΤ|ΟΡΦ|ΤΣΙΓΓ|ΤΣΟΠ|ΦΩΤΟΣΤΕΦ|Χ|ΨΥΧΟΠΛ|ΑΓ|ΟΡΦ|ΓΑΛ|ΓΕΡ|ΔΕΚ|ΔΙΠΛ|ΑΜΕΡΙΚΑΝ|ΟΥΡ|ΠΙΘ|ΠΟΥΡΙΤ|Σ|ΖΩΝΤ|ΙΚ|ΚΑΣΤ|ΚΟΠ|ΛΙΧ|ΛΟΥΘΗΡ|ΜΑΙΝΤ|' | ||||
|                     . 'ΜΕΛ|ΣΙΓ|ΣΠ|ΣΤΕΓ|ΤΡΑΓ|ΤΣΑΓ|Φ|ΕΡ|ΑΔΑΠ|ΑΘΙΓΓ|ΑΜΗΧ|ΑΝΙΚ|ΑΝΟΡΓ|ΑΠΗΓ|ΑΠΙΘ|ΑΤΣΙΓΓ|ΒΑΣ|ΒΑΣΚ|ΒΑΘΥΓΑΛ|ΒΙΟΜΗΧ|ΒΡΑΧΥΚ|ΔΙΑΤ|ΔΙΑΦ|ΕΝΟΡΓ|' | ||||
|                     . 'ΘΥΣ|ΚΑΠΝΟΒΙΟΜΗΧ|ΚΑΤΑΓΑΛ|ΚΛΙΒ|ΚΟΙΛΑΡΦ|ΛΙΒ|ΜΕΓΛΟΒΙΟΜΗΧ|ΜΙΚΡΟΒΙΟΜΗΧ|ΝΤΑΒ|ΞΗΡΟΚΛΙΒ|ΟΛΙΓΟΔΑΜ|ΟΛΟΓΑΛ|ΠΕΝΤΑΡΦ|ΠΕΡΗΦ|ΠΕΡΙΤΡ|ΠΛΑΤ|' | ||||
|                     . 'ΠΟΛΥΔΑΠ|ΠΟΛΥΜΗΧ|ΣΤΕΦ|ΤΑΒ|ΤΕΤ|ΥΠΕΡΗΦ|ΥΠΟΚΟΠ|ΧΑΜΗΛΟΔΑΠ|ΨΗΛΟΤΑΒ)$/'; | ||||
|  | ||||
|             if (preg_match($re2, $token) || preg_match($exept7, $token)) { | ||||
|                 $token .= "ΑΝ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5c | ||||
|         $re3 = '/^(.+?)(ΕΤΕ)$/'; | ||||
|         $re4 = '/^(.+?)(ΗΣΕΤΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re4, $token)) { | ||||
|             preg_match($re4, $token, $match); | ||||
|             $token = $match[1]; | ||||
|             $test1 = false; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re3, $token)) { | ||||
|             preg_match($re3, $token, $match); | ||||
|             $token  = $match[1]; | ||||
|             $test1  = false; | ||||
|             $re3    = '/' . $v2 . '$/'; | ||||
|             $exept8 = '/(ΟΔ|ΑΙΡ|ΦΟΡ|ΤΑΘ|ΔΙΑΘ|ΣΧ|ΕΝΔ|ΕΥΡ|ΤΙΘ|ΥΠΕΡΘ|ΡΑΘ|ΕΝΘ|ΡΟΘ|ΣΘ|ΠΥΡ|ΑΙΝ|ΣΥΝΔ|ΣΥΝ|ΣΥΝΘ|ΧΩΡ|ΠΟΝ|ΒΡ|ΚΑΘ|ΕΥΘ|ΕΚΘ|ΝΕΤ|ΡΟΝ|ΑΡΚ|ΒΑΡ|ΒΟΛ|ΩΦΕΛ)$/'; | ||||
|             $exept9 = '/^(ΑΒΑΡ|ΒΕΝ|ΕΝΑΡ|ΑΒΡ|ΑΔ|ΑΘ|ΑΝ|ΑΠΛ|ΒΑΡΟΝ|ΝΤΡ|ΣΚ|ΚΟΠ|ΜΠΟΡ|ΝΙΦ|ΠΑΓ|ΠΑΡΑΚΑΛ|ΣΕΡΠ|ΣΚΕΛ|ΣΥΡΦ|ΤΟΚ|Υ|Δ|ΕΜ|ΘΑΡΡ|Θ)$/'; | ||||
|  | ||||
|             if (preg_match($re3, $token) || preg_match($exept8, $token) || preg_match($exept9, $token)) { | ||||
|                 $token .= "ΕΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5d | ||||
|         $re = '/^(.+?)(ΟΝΤΑΣ|ΩΝΤΑΣ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept10 = '/^(ΑΡΧ)$/'; | ||||
|             $exept11 = '/(ΚΡΕ)$/'; | ||||
|  | ||||
|             if (preg_match($exept10, $token)) { | ||||
|                 $token .= "ΟΝΤ"; | ||||
|             } | ||||
|  | ||||
|             if (preg_match($exept11, $token)) { | ||||
|                 $token .= "ΩΝΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5e | ||||
|         $re = '/^(.+?)(ΟΜΑΣΤΕ|ΙΟΜΑΣΤΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept11 = '/^(ΟΝ)$/'; | ||||
|  | ||||
|             if (preg_match($exept11, $token)) { | ||||
|                 $token .= "ΟΜΑΣΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5f | ||||
|         $re  = '/^(.+?)(ΕΣΤΕ)$/'; | ||||
|         $re2 = '/^(.+?)(ΙΕΣΤΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re2, $token)) { | ||||
|             preg_match($re2, $token, $match); | ||||
|             $token = $match[1]; | ||||
|             $test1 = false; | ||||
|             $re2   = '/^(Π|ΑΠ|ΣΥΜΠ|ΑΣΥΜΠ|ΑΚΑΤΑΠ|ΑΜΕΤΑΜΦ)$/'; | ||||
|  | ||||
|             if (preg_match($re2, $token)) { | ||||
|                 $token .= "ΙΕΣΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept12 = '/^(ΑΛ|ΑΡ|ΕΚΤΕΛ|Ζ|Μ|Ξ|ΠΑΡΑΚΑΛ|ΠΡΟ|ΝΙΣ)$/'; | ||||
|  | ||||
|             if (preg_match($exept12, $token)) { | ||||
|                 $token .= "ΕΣΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5g | ||||
|         $re  = '/^(.+?)(ΗΚΑ|ΗΚΕΣ|ΗΚΕ)$/'; | ||||
|         $re2 = '/^(.+?)(ΗΘΗΚΑ|ΗΘΗΚΕΣ|ΗΘΗΚΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re2, $token)) { | ||||
|             preg_match($re2, $token, $match); | ||||
|             $token = $match[1]; | ||||
|             $test1 = false; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept13 = '/(ΣΚΩΛ|ΣΚΟΥΛ|ΝΑΡΘ|ΣΦ|ΟΘ|ΠΙΘ)$/'; | ||||
|             $exept14 = '/^(ΔΙΑΘ|Θ|ΠΑΡΑΚΑΤΑΘ|ΠΡΟΣΘ|ΣΥΝΘ|)$/'; | ||||
|  | ||||
|             if (preg_match($exept13, $token) || preg_match($exept14, $token)) { | ||||
|                 $token .= "ΗΚ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5h | ||||
|         $re = '/^(.+?)(ΟΥΣΑ|ΟΥΣΕΣ|ΟΥΣΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept15 = '/^(ΦΑΡΜΑΚ|ΧΑΔ|ΑΓΚ|ΑΝΑΡΡ|ΒΡΟΜ|ΕΚΛΙΠ|ΛΑΜΠΙΔ|ΛΕΧ|Μ|ΠΑΤ|Ρ|Λ|ΜΕΔ|ΜΕΣΑΖ|ΥΠΟΤΕΙΝ|ΑΜ|ΑΙΘ|ΑΝΗΚ|ΔΕΣΠΟΖ|ΕΝΔΙΑΦΕΡ|ΔΕ|ΔΕΥΤΕΡΕΥ|ΚΑΘΑΡΕΥ|ΠΛΕ|ΤΣΑ)$/'; | ||||
|             $exept16 = '/(ΠΟΔΑΡ|ΒΛΕΠ|ΠΑΝΤΑΧ|ΦΡΥΔ|ΜΑΝΤΙΛ|ΜΑΛΛ|ΚΥΜΑΤ|ΛΑΧ|ΛΗΓ|ΦΑΓ|ΟΜ|ΠΡΩΤ)$/'; | ||||
|  | ||||
|             if (preg_match($exept15, $token) || preg_match($exept16, $token)) { | ||||
|                 $token .= "ΟΥΣ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5i | ||||
|         $re = '/^(.+?)(ΑΓΑ|ΑΓΕΣ|ΑΓΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept17 = '/^(ΨΟΦ|ΝΑΥΛΟΧ)$/'; | ||||
|             $exept20 = '/(ΚΟΛΛ)$/'; | ||||
|             $exept18 = '/^(ΑΒΑΣΤ|ΠΟΛΥΦ|ΑΔΗΦ|ΠΑΜΦ|Ρ|ΑΣΠ|ΑΦ|ΑΜΑΛ|ΑΜΑΛΛΙ|ΑΝΥΣΤ|ΑΠΕΡ|ΑΣΠΑΡ|ΑΧΑΡ|ΔΕΡΒΕΝ|ΔΡΟΣΟΠ|ΞΕΦ|ΝΕΟΠ|ΝΟΜΟΤ|ΟΛΟΠ|ΟΜΟΤ|ΠΡΟΣΤ|ΠΡΟΣΩΠΟΠ|' | ||||
|                 . 'ΣΥΜΠ|ΣΥΝΤ|Τ|ΥΠΟΤ|ΧΑΡ|ΑΕΙΠ|ΑΙΜΟΣΤ|ΑΝΥΠ|ΑΠΟΤ|ΑΡΤΙΠ|ΔΙΑΤ|ΕΝ|ΕΠΙΤ|ΚΡΟΚΑΛΟΠ|ΣΙΔΗΡΟΠ|Λ|ΝΑΥ|ΟΥΛΑΜ|ΟΥΡ|Π|ΤΡ|Μ)$/'; | ||||
|             $exept19 = '/(ΟΦ|ΠΕΛ|ΧΟΡΤ|ΛΛ|ΣΦ|ΡΠ|ΦΡ|ΠΡ|ΛΟΧ|ΣΜΗΝ)$/'; | ||||
|  | ||||
|             if ( | ||||
|                 (preg_match($exept18, $token) || preg_match($exept19, $token)) | ||||
|                 && !(preg_match($exept17, $token) || preg_match($exept20, $token)) | ||||
|             ) { | ||||
|                 $token .= "ΑΓ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5j | ||||
|         $re = '/^(.+?)(ΗΣΕ|ΗΣΟΥ|ΗΣΑ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept21 = '/^(Ν|ΧΕΡΣΟΝ|ΔΩΔΕΚΑΝ|ΕΡΗΜΟΝ|ΜΕΓΑΛΟΝ|ΕΠΤΑΝ)$/'; | ||||
|  | ||||
|             if (preg_match($exept21, $token)) { | ||||
|                 $token .= "ΗΣ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5k | ||||
|         $re = '/^(.+?)(ΗΣΤΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept22 = '/^(ΑΣΒ|ΣΒ|ΑΧΡ|ΧΡ|ΑΠΛ|ΑΕΙΜΝ|ΔΥΣΧΡ|ΕΥΧΡ|ΚΟΙΝΟΧΡ|ΠΑΛΙΜΨ)$/'; | ||||
|  | ||||
|             if (preg_match($exept22, $token)) { | ||||
|                 $token .= "ΗΣΤ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5l | ||||
|         $re = '/^(.+?)(ΟΥΝΕ|ΗΣΟΥΝΕ|ΗΘΟΥΝΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept23 = '/^(Ν|Ρ|ΣΠΙ|ΣΤΡΑΒΟΜΟΥΤΣ|ΚΑΚΟΜΟΥΤΣ|ΕΞΩΝ)$/'; | ||||
|  | ||||
|             if (preg_match($exept23, $token)) { | ||||
|                 $token .= "ΟΥΝ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 5m | ||||
|         $re = '/^(.+?)(ΟΥΜΕ|ΗΣΟΥΜΕ|ΗΘΟΥΜΕ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token   = $match[1]; | ||||
|             $test1   = false; | ||||
|             $exept24 = '/^(ΠΑΡΑΣΟΥΣ|Φ|Χ|ΩΡΙΟΠΛ|ΑΖ|ΑΛΛΟΣΟΥΣ|ΑΣΟΥΣ)$/'; | ||||
|  | ||||
|             if (preg_match($exept24, $token)) { | ||||
|                 $token .= "ΟΥΜ"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 6 | ||||
|         $re  = '/^(.+?)(ΜΑΤΑ|ΜΑΤΩΝ|ΜΑΤΟΣ)$/'; | ||||
|         $re2 = '/^(.+?)(Α|ΑΓΑΤΕ|ΑΓΑΝ|ΑΕΙ|ΑΜΑΙ|ΑΝ|ΑΣ|ΑΣΑΙ|ΑΤΑΙ|ΑΩ|Ε|ΕΙ|ΕΙΣ|ΕΙΤΕ|ΕΣΑΙ|ΕΣ|ΕΤΑΙ|Ι|ΙΕΜΑΙ|ΙΕΜΑΣΤΕ|ΙΕΤΑΙ|ΙΕΣΑΙ|ΙΕΣΑΣΤΕ|ΙΟΜΑΣΤΑΝ|ΙΟΜΟΥΝ|' | ||||
|                 . 'ΙΟΜΟΥΝΑ|ΙΟΝΤΑΝ|ΙΟΝΤΟΥΣΑΝ|ΙΟΣΑΣΤΑΝ|ΙΟΣΑΣΤΕ|ΙΟΣΟΥΝ|ΙΟΣΟΥΝΑ|ΙΟΤΑΝ|ΙΟΥΜΑ|ΙΟΥΜΑΣΤΕ|ΙΟΥΝΤΑΙ|ΙΟΥΝΤΑΝ|Η|ΗΔΕΣ|ΗΔΩΝ|ΗΘΕΙ|ΗΘΕΙΣ|ΗΘΕΙΤΕ|' | ||||
|                 . 'ΗΘΗΚΑΤΕ|ΗΘΗΚΑΝ|ΗΘΟΥΝ|ΗΘΩ|ΗΚΑΤΕ|ΗΚΑΝ|ΗΣ|ΗΣΑΝ|ΗΣΑΤΕ|ΗΣΕΙ|ΗΣΕΣ|ΗΣΟΥΝ|ΗΣΩ|Ο|ΟΙ|ΟΜΑΙ|ΟΜΑΣΤΑΝ|ΟΜΟΥΝ|ΟΜΟΥΝΑ|ΟΝΤΑΙ|ΟΝΤΑΝ|ΟΝΤΟΥΣΑΝ|ΟΣ|' | ||||
|                 . 'ΟΣΑΣΤΑΝ|ΟΣΑΣΤΕ|ΟΣΟΥΝ|ΟΣΟΥΝΑ|ΟΤΑΝ|ΟΥ|ΟΥΜΑΙ|ΟΥΜΑΣΤΕ|ΟΥΝ|ΟΥΝΤΑΙ|ΟΥΝΤΑΝ|ΟΥΣ|ΟΥΣΑΝ|ΟΥΣΑΤΕ|Υ|ΥΣ|Ω|ΩΝ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token, $match)) { | ||||
|             $token = $match[1] . "ΜΑ"; | ||||
|         } | ||||
|  | ||||
|         if (preg_match($re2, $token) && $test1) { | ||||
|             preg_match($re2, $token, $match); | ||||
|             $token = $match[1]; | ||||
|         } | ||||
|  | ||||
|         // Step 7 (ΠΑΡΑΘΕΤΙΚΑ) | ||||
|         $re = '/^(.+?)(ΕΣΤΕΡ|ΕΣΤΑΤ|ΟΤΕΡ|ΟΤΑΤ|ΥΤΕΡ|ΥΤΑΤ|ΩΤΕΡ|ΩΤΑΤ)$/'; | ||||
|  | ||||
|         if (preg_match($re, $token)) { | ||||
|             preg_match($re, $token, $match); | ||||
|             $token = $match[1]; | ||||
|         } | ||||
|  | ||||
|         return $this->toLowerCase($token, $wCase); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts the token to uppercase, suppressing accents and diaeresis. The array $wCase contains a special map of | ||||
|      * the uppercase rule used to convert each character at each position. | ||||
|      * | ||||
|      * @param   string  $token   Token to process | ||||
|      * @param   array   &$wCase  Map of uppercase rules | ||||
|      * | ||||
|      * @return  string | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     protected function toUpperCase($token, &$wCase) | ||||
|     { | ||||
|         $wCase       = array_fill(0, mb_strlen($token, 'UTF-8'), 0); | ||||
|         $caseConvert = [ | ||||
|             "α" => 'Α', | ||||
|             "β" => 'Β', | ||||
|             "γ" => 'Γ', | ||||
|             "δ" => 'Δ', | ||||
|             "ε" => 'Ε', | ||||
|             "ζ" => 'Ζ', | ||||
|             "η" => 'Η', | ||||
|             "θ" => 'Θ', | ||||
|             "ι" => 'Ι', | ||||
|             "κ" => 'Κ', | ||||
|             "λ" => 'Λ', | ||||
|             "μ" => 'Μ', | ||||
|             "ν" => 'Ν', | ||||
|             "ξ" => 'Ξ', | ||||
|             "ο" => 'Ο', | ||||
|             "π" => 'Π', | ||||
|             "ρ" => 'Ρ', | ||||
|             "σ" => 'Σ', | ||||
|             "τ" => 'Τ', | ||||
|             "υ" => 'Υ', | ||||
|             "φ" => 'Φ', | ||||
|             "χ" => 'Χ', | ||||
|             "ψ" => 'Ψ', | ||||
|             "ω" => 'Ω', | ||||
|             "ά" => 'Α', | ||||
|             "έ" => 'Ε', | ||||
|             "ή" => 'Η', | ||||
|             "ί" => 'Ι', | ||||
|             "ό" => 'Ο', | ||||
|             "ύ" => 'Υ', | ||||
|             "ώ" => 'Ω', | ||||
|             "ς" => 'Σ', | ||||
|             "ϊ" => 'Ι', | ||||
|             "ϋ" => 'Ι', | ||||
|             "ΐ" => 'Ι', | ||||
|             "ΰ" => 'Υ', | ||||
|         ]; | ||||
|         $newToken    = ''; | ||||
|  | ||||
|         for ($i = 0; $i < mb_strlen($token); $i++) { | ||||
|             $char    = mb_substr($token, $i, 1); | ||||
|             $isLower = \array_key_exists($char, $caseConvert); | ||||
|  | ||||
|             if (!$isLower) { | ||||
|                 $newToken .= $char; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $upperCase = $caseConvert[$char]; | ||||
|             $newToken .= $upperCase; | ||||
|  | ||||
|             $wCase[$i] = 1; | ||||
|  | ||||
|             if (\in_array($char, ['ά', 'έ', 'ή', 'ί', 'ό', 'ύ', 'ώ', 'ς'])) { | ||||
|                 $wCase[$i] = 2; | ||||
|             } | ||||
|  | ||||
|             if (\in_array($char, ['ϊ', 'ϋ'])) { | ||||
|                 $wCase[$i] = 3; | ||||
|             } | ||||
|  | ||||
|             if (\in_array($char, ['ΐ', 'ΰ'])) { | ||||
|                 $wCase[$i] = 4; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $newToken; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts the suppressed uppercase token back to lowercase, using the $wCase map to add back the accents, | ||||
|      * diaeresis and handle the special case of final sigma (different lowercase glyph than the regular sigma, only | ||||
|      * used at the end of words). | ||||
|      * | ||||
|      * @param   string  $token  Token to process | ||||
|      * @param   array   $wCase  Map of lowercase rules | ||||
|      * | ||||
|      * @return  string | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     protected function toLowerCase($token, $wCase) | ||||
|     { | ||||
|         $newToken    = ''; | ||||
|  | ||||
|         for ($i = 0; $i < mb_strlen($token); $i++) { | ||||
|             $char    = mb_substr($token, $i, 1); | ||||
|  | ||||
|             // Is $wCase not set at this position? We assume no case conversion ever took place. | ||||
|             if (!isset($wCase[$i])) { | ||||
|                 $newToken .= $char; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // The character was not case-converted | ||||
|             if ($wCase[$i] == 0) { | ||||
|                 $newToken .= $char; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Case 1: Unaccented letter | ||||
|             if ($wCase[$i] == 1) { | ||||
|                 $newToken .= mb_strtolower($char); | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Case 2: Vowel with accent (tonos); or the special case of final sigma | ||||
|             if ($wCase[$i] == 2) { | ||||
|                 $charMap = [ | ||||
|                     'Α' => 'ά', | ||||
|                     'Ε' => 'έ', | ||||
|                     'Η' => 'ή', | ||||
|                     'Ι' => 'ί', | ||||
|                     'Ο' => 'ό', | ||||
|                     'Υ' => 'ύ', | ||||
|                     'Ω' => 'ώ', | ||||
|                     'Σ' => 'ς', | ||||
|                 ]; | ||||
|  | ||||
|                 $newToken .= $charMap[$char]; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Case 3: vowels with diaeresis (dialytika) | ||||
|             if ($wCase[$i] == 3) { | ||||
|                 $charMap = [ | ||||
|                     'Ι' => 'ϊ', | ||||
|                     'Υ' => 'ϋ', | ||||
|                 ]; | ||||
|  | ||||
|                 $newToken .= $charMap[$char]; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Case 4: vowels with both diaeresis (dialytika) and accent (tonos) | ||||
|             if ($wCase[$i] == 4) { | ||||
|                 $charMap = [ | ||||
|                     'Ι' => 'ΐ', | ||||
|                     'Υ' => 'ΰ', | ||||
|                 ]; | ||||
|  | ||||
|                 $newToken .= $charMap[$char]; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // This should never happen! | ||||
|             $newToken .= $char; | ||||
|         } | ||||
|  | ||||
|         return $newToken; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,71 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer\Language; | ||||
|  | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Language; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Chinese (simplified) language support class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class Zh extends Language | ||||
| { | ||||
|     /** | ||||
|      * Language locale of the class | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $language = 'zh'; | ||||
|  | ||||
|     /** | ||||
|      * Spacer between terms | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $spacer = ''; | ||||
|  | ||||
|     /** | ||||
|      * Method to construct the language object. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function __construct($locale = null) | ||||
|     { | ||||
|         // Override parent constructor since we don't need to load an external stemmer | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to tokenise a text string. | ||||
|      * | ||||
|      * @param   string  $input  The input to tokenise. | ||||
|      * | ||||
|      * @return  array  An array of term strings. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function tokenise($input) | ||||
|     { | ||||
|         // We first add whitespace around each Chinese character, so that our later code can easily split on this. | ||||
|         $input = preg_replace('#\p{Han}#mui', ' $0 ', $input); | ||||
|  | ||||
|         // Now we split up the input into individual terms | ||||
|         $terms = parent::tokenise($input); | ||||
|  | ||||
|         return $terms; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										125
									
								
								administrator/components/com_finder/src/Indexer/Parser.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								administrator/components/com_finder/src/Indexer/Parser.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Filter\InputFilter; | ||||
| use Joomla\CMS\Language\Text; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Parser base class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| abstract class Parser | ||||
| { | ||||
|     /** | ||||
|      * Parser support instances container. | ||||
|      * | ||||
|      * @var    Parser[] | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected static $instances = []; | ||||
|  | ||||
|     /** | ||||
|      * Method to get a parser, creating it if necessary. | ||||
|      * | ||||
|      * @param   string  $format  The type of parser to load. | ||||
|      * | ||||
|      * @return  Parser  A Parser instance. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \Exception on invalid parser. | ||||
|      */ | ||||
|     public static function getInstance($format) | ||||
|     { | ||||
|         $format = InputFilter::getInstance()->clean($format, 'cmd'); | ||||
|  | ||||
|         // Only create one parser for each format. | ||||
|         if (isset(self::$instances[$format])) { | ||||
|             return self::$instances[$format]; | ||||
|         } | ||||
|  | ||||
|         // Setup the adapter for the parser. | ||||
|         $class = '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Parser\\' . ucfirst($format); | ||||
|  | ||||
|         // Check if a parser exists for the format. | ||||
|         if (class_exists($class)) { | ||||
|             self::$instances[$format] = new $class(); | ||||
|  | ||||
|             return self::$instances[$format]; | ||||
|         } | ||||
|  | ||||
|         // Throw invalid format exception. | ||||
|         throw new \Exception(Text::sprintf('COM_FINDER_INDEXER_INVALID_PARSER', $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) | ||||
|     { | ||||
|         // If the input is less than 2KB we can parse it in one go. | ||||
|         if (\strlen($input) <= 2048) { | ||||
|             return $this->process($input); | ||||
|         } | ||||
|  | ||||
|         // Input is longer than 2Kb so parse it in chunks of 2Kb or less. | ||||
|         $start  = 0; | ||||
|         $end    = \strlen($input); | ||||
|         $chunk  = 2048; | ||||
|         $return = null; | ||||
|  | ||||
|         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 (but include it in the string). | ||||
|             if ($ls !== false) { | ||||
|                 $string = substr($string, 0, $ls + 1); | ||||
|             } | ||||
|  | ||||
|             // Adjust the start position for the next iteration. | ||||
|             $start += $ls !== false ? $ls + 1 : $chunk; | ||||
|  | ||||
|             // Parse the chunk. | ||||
|             $return .= $this->process($string); | ||||
|         } | ||||
|  | ||||
|         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); | ||||
| } | ||||
							
								
								
									
										158
									
								
								administrator/components/com_finder/src/Indexer/Parser/Html.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								administrator/components/com_finder/src/Indexer/Parser/Html.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * HTML Parser class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Html extends Parser | ||||
| { | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         // Strip invalid UTF-8 characters. | ||||
|         $oldSetting = \ini_get('mbstring.substitute_character'); | ||||
|         ini_set('mbstring.substitute_character', 'none'); | ||||
|         $input = mb_convert_encoding($input, 'UTF-8', 'UTF-8'); | ||||
|         ini_set('mbstring.substitute_character', $oldSetting); | ||||
|  | ||||
|         // Remove anything between <head> and </head> tags.  Do this first | ||||
|         // because there might be <script> or <style> tags nested inside. | ||||
|         $input = $this->removeBlocks($input, '<head>', '</head>'); | ||||
|  | ||||
|         // Convert <style> and <noscript> tags to <script> tags | ||||
|         // so we can remove them efficiently. | ||||
|         $search = [ | ||||
|             '<style', '</style', | ||||
|             '<noscript', '</noscript', | ||||
|         ]; | ||||
|         $replace = [ | ||||
|             '<script', '</script', | ||||
|             '<script', '</script', | ||||
|         ]; | ||||
|         $input = str_replace($search, $replace, $input); | ||||
|  | ||||
|         // Strip all script blocks. | ||||
|         $input = $this->removeBlocks($input, '<script', '</script>'); | ||||
|  | ||||
|         // Decode HTML entities. | ||||
|         $input = html_entity_decode($input, ENT_QUOTES, 'UTF-8'); | ||||
|  | ||||
|         // Convert entities equivalent to spaces to actual spaces. | ||||
|         $input = str_replace([' ', ' '], ' ', $input); | ||||
|  | ||||
|         // Add a space before both the OPEN and CLOSE tags of BLOCK and LINE BREAKING elements, | ||||
|         // e.g. 'all<h1><em>m</em>obile  List</h1>' will become 'all mobile  List' | ||||
|         $input = preg_replace('/(<|<\/)(' . | ||||
|             'address|article|aside|blockquote|br|canvas|dd|div|dl|dt|' . | ||||
|             'fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|li|' . | ||||
|             'main|nav|noscript|ol|output|p|pre|section|table|tfoot|ul|video' . | ||||
|             ')\b/i', ' $1$2', $input); | ||||
|  | ||||
|         // Strip HTML tags. | ||||
|         $input = strip_tags($input); | ||||
|  | ||||
|         return parent::parse($input); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         // Replace any amount of white space with a single space. | ||||
|         return preg_replace('#\s+#u', ' ', $input); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove blocks of text between a start and an end tag. | ||||
|      * Each block removed is effectively replaced by a single space. | ||||
|      * | ||||
|      * Note: The start tag and the end tag must be different. | ||||
|      * Note: Blocks must not be nested. | ||||
|      * Note: This method will function correctly with multi-byte strings. | ||||
|      * | ||||
|      * @param   string  $input     String to be processed. | ||||
|      * @param   string  $startTag  String representing the start tag. | ||||
|      * @param   string  $endTag    String representing the end tag. | ||||
|      * | ||||
|      * @return  string with blocks removed. | ||||
|      * | ||||
|      * @since   3.4 | ||||
|      */ | ||||
|     private function removeBlocks($input, $startTag, $endTag) | ||||
|     { | ||||
|         $return         = ''; | ||||
|         $offset         = 0; | ||||
|         $startTagLength = \strlen($startTag); | ||||
|         $endTagLength   = \strlen($endTag); | ||||
|  | ||||
|         // Find the first start tag. | ||||
|         $start = stripos($input, $startTag); | ||||
|  | ||||
|         // If no start tags were found, return the string unchanged. | ||||
|         if ($start === false) { | ||||
|             return $input; | ||||
|         } | ||||
|  | ||||
|         // Look for all blocks defined by the start and end tags. | ||||
|         while ($start !== false) { | ||||
|             // Accumulate the substring up to the start tag. | ||||
|             $return .= substr($input, $offset, $start - $offset) . ' '; | ||||
|  | ||||
|             // Look for an end tag corresponding to the start tag. | ||||
|             $end = stripos($input, $endTag, $start + $startTagLength); | ||||
|  | ||||
|             // If no corresponding end tag, leave the string alone. | ||||
|             if ($end === false) { | ||||
|                 // Fix the offset so part of the string is not duplicated. | ||||
|                 $offset = $start; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             // Advance the start position. | ||||
|             $offset = $end + $endTagLength; | ||||
|  | ||||
|             // Look for the next start tag and loop. | ||||
|             $start = stripos($input, $startTag, $offset); | ||||
|         } | ||||
|  | ||||
|         // Add in the final substring after the last end tag. | ||||
|         $return .= substr($input, $offset); | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * RTF Parser class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Rtf extends Parser | ||||
| { | ||||
|     /** | ||||
|      * 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[^}]*}#mi', '', $input); | ||||
|  | ||||
|         // Remove control characters. | ||||
|         $input = str_replace(['{', '}', "\\\n"], [' ', ' ', "\n"], $input); | ||||
|         $input = preg_replace('#\\\([^;]+?);#m', ' ', $input); | ||||
|         $input = preg_replace('#\\\[\'a-zA-Z0-9]+#mi', ' ', $input); | ||||
|  | ||||
|         return $input; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Parser; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Text Parser class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Txt extends Parser | ||||
| { | ||||
|     /** | ||||
|      * 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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1340
									
								
								administrator/components/com_finder/src/Indexer/Query.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1340
									
								
								administrator/components/com_finder/src/Indexer/Query.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										582
									
								
								administrator/components/com_finder/src/Indexer/Result.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								administrator/components/com_finder/src/Indexer/Result.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,582 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Tree\ImmutableNodeInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Result implements \Serializable | ||||
| { | ||||
|     /** | ||||
|      * An array of extra result properties. | ||||
|      * | ||||
|      * @var    array | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     protected $elements = []; | ||||
|  | ||||
|     /** | ||||
|      * 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 = [ | ||||
|         Indexer::TITLE_CONTEXT => ['title', 'subtitle', 'id'], | ||||
|         Indexer::TEXT_CONTEXT  => ['summary', 'body'], | ||||
|         Indexer::META_CONTEXT  => ['meta', 'list_price', 'sale_price'], | ||||
|         Indexer::PATH_CONTEXT  => ['path', 'alias'], | ||||
|         Indexer::MISC_CONTEXT  => ['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 = []; | ||||
|  | ||||
|     /** | ||||
|      * 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 = ComponentHelper::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->setElement($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) | ||||
|     { | ||||
|         return $this->getElement($name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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]; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to retrieve all elements. | ||||
|      * | ||||
|      * @return  array  The elements | ||||
|      * | ||||
|      * @since   3.8.3 | ||||
|      */ | ||||
|     public function getElements() | ||||
|     { | ||||
|         return $this->elements; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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. | ||||
|         // Check if the property exists in the group. | ||||
|         if (\array_key_exists($group, $this->instructions) && !\in_array($property, $this->instructions[$group], true)) { | ||||
|             // 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])) { | ||||
|             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] | ||||
|      * @param   string   $language  The language of the taxonomy. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function addTaxonomy($branch, $title, $state = 1, $access = 1, $language = '*') | ||||
|     { | ||||
|         // We can't add taxonomies with empty titles | ||||
|         if (!trim($title)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Filter the input. | ||||
|         $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,_]+#mui', ' ', $branch); | ||||
|  | ||||
|         // Create the taxonomy node. | ||||
|         $node           = new \stdClass(); | ||||
|         $node->title    = $title; | ||||
|         $node->state    = (int) $state; | ||||
|         $node->access   = (int) $access; | ||||
|         $node->language = $language; | ||||
|         $node->nested   = false; | ||||
|  | ||||
|         // Add the node to the taxonomy branch. | ||||
|         $this->taxonomy[$branch][] = $node; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to add a nested taxonomy map for an item. | ||||
|      * | ||||
|      * @param   string                  $branch       The title of the taxonomy branch to add the node to. | ||||
|      * @param   ImmutableNodeInterface  $contentNode  The node object. | ||||
|      * @param   integer                 $state        The published state of the taxonomy node. [optional] | ||||
|      * @param   integer                 $access       The access level of the taxonomy node. [optional] | ||||
|      * @param   string                  $language     The language of the taxonomy. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function addNestedTaxonomy($branch, ImmutableNodeInterface $contentNode, $state = 1, $access = 1, $language = '*') | ||||
|     { | ||||
|         // We can't add taxonomies with empty titles | ||||
|         if (!trim($contentNode->title)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Filter the input. | ||||
|         $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,_]+#mui', ' ', $branch); | ||||
|  | ||||
|         // Create the taxonomy node. | ||||
|         $node           = new \stdClass(); | ||||
|         $node->title    = $contentNode->title; | ||||
|         $node->state    = (int) $state; | ||||
|         $node->access   = (int) $access; | ||||
|         $node->language = $language; | ||||
|         $node->nested   = true; | ||||
|         $node->node     = $contentNode; | ||||
|  | ||||
|         // Add the node to the taxonomy branch. | ||||
|         $this->taxonomy[$branch][] = $node; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to set the item language | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   3.0 | ||||
|      */ | ||||
|     public function setLanguage() | ||||
|     { | ||||
|         if ($this->language == '') { | ||||
|             $this->language = $this->defaultLanguage; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Helper function to serialise the data of a Result object | ||||
|      * | ||||
|      * @return  string  The serialised data | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function serialize() | ||||
|     { | ||||
|         return serialize($this->__serialize()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Helper function to unserialise the data for this object | ||||
|      * | ||||
|      * @param   string  $serialized  Serialised data to unserialise | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function unserialize($serialized): void | ||||
|     { | ||||
|         $this->__unserialize(unserialize($serialized)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Magic method used for serializing. | ||||
|      * | ||||
|      * @since  4.1.3 | ||||
|      */ | ||||
|     public function __serialize(): array | ||||
|     { | ||||
|         $taxonomy = []; | ||||
|  | ||||
|         foreach ($this->taxonomy as $branch => $nodes) { | ||||
|             $taxonomy[$branch] = []; | ||||
|  | ||||
|             foreach ($nodes as $node) { | ||||
|                 if ($node->nested) { | ||||
|                     $n = clone $node; | ||||
|                     unset($n->node); | ||||
|                     $taxonomy[$branch][] = $n; | ||||
|                 } else { | ||||
|                     $taxonomy[$branch][] = $node; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // This order must match EXACTLY the order of the $properties in the self::__unserialize method | ||||
|         return [ | ||||
|             $this->access, | ||||
|             $this->defaultLanguage, | ||||
|             $this->description, | ||||
|             $this->elements, | ||||
|             $this->end_date, | ||||
|             $this->instructions, | ||||
|             $this->language, | ||||
|             $this->list_price, | ||||
|             $this->publish_end_date, | ||||
|             $this->publish_start_date, | ||||
|             $this->published, | ||||
|             $this->route, | ||||
|             $this->sale_price, | ||||
|             $this->start_date, | ||||
|             $this->state, | ||||
|             $taxonomy, | ||||
|             $this->title, | ||||
|             $this->type_id, | ||||
|             $this->url, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Magic method used for unserializing. | ||||
|      * | ||||
|      * @since  4.1.3 | ||||
|      */ | ||||
|     public function __unserialize(array $serialized): void | ||||
|     { | ||||
|         // This order must match EXACTLY the order of the array in the self::__serialize method | ||||
|         $properties = [ | ||||
|             'access', | ||||
|             'defaultLanguage', | ||||
|             'description', | ||||
|             'elements', | ||||
|             'end_date', | ||||
|             'instructions', | ||||
|             'language', | ||||
|             'list_price', | ||||
|             'publish_end_date', | ||||
|             'publish_start_date', | ||||
|             'published', | ||||
|             'route', | ||||
|             'sale_price', | ||||
|             'start_date', | ||||
|             'state', | ||||
|             'taxonomy', | ||||
|             'title', | ||||
|             'type_id', | ||||
|             'url', | ||||
|         ]; | ||||
|  | ||||
|         foreach ($properties as $k => $v) { | ||||
|             $this->$v = $serialized[$k]; | ||||
|         } | ||||
|  | ||||
|         foreach ($this->taxonomy as $nodes) { | ||||
|             foreach ($nodes as $node) { | ||||
|                 $curTaxonomy  = Taxonomy::getTaxonomy($node->id); | ||||
|                 $node->state  = $curTaxonomy->state; | ||||
|                 $node->access = $curTaxonomy->access; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										514
									
								
								administrator/components/com_finder/src/Indexer/Taxonomy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								administrator/components/com_finder/src/Indexer/Taxonomy.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,514 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Tree\NodeInterface; | ||||
| use Joomla\Component\Finder\Administrator\Table\MapTable; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Taxonomy base class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Taxonomy | ||||
| { | ||||
|     /** | ||||
|      * An internal cache of taxonomy data. | ||||
|      * | ||||
|      * @var    object[] | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public static $taxonomies = []; | ||||
|  | ||||
|     /** | ||||
|      * An internal cache of branch data. | ||||
|      * | ||||
|      * @var    object[] | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public static $branches = []; | ||||
|  | ||||
|     /** | ||||
|      * An internal cache of taxonomy node data for inserting it. | ||||
|      * | ||||
|      * @var    object[] | ||||
|      * @since  2.5 | ||||
|      */ | ||||
|     public static $nodes = []; | ||||
|  | ||||
|     /** | ||||
|      * 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  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function addBranch($title, $state = 1, $access = 1) | ||||
|     { | ||||
|         $node            = new \stdClass(); | ||||
|         $node->title     = $title; | ||||
|         $node->access    = $access; | ||||
|         $node->parent_id = 1; | ||||
|         $node->language  = '*'; | ||||
|  | ||||
|         return self::storeNode($node, 1); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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] | ||||
|      * @param   string   $language  The language of the node. [optional] | ||||
|      * | ||||
|      * @return  integer  The id of the node. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function addNode($branch, $title, $state = 1, $access = 1, $language = '*') | ||||
|     { | ||||
|         if ($state != 1) { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         // Get the branch id, insert it if it does not exist. | ||||
|         $branchId = static::addBranch($branch); | ||||
|  | ||||
|         $node            = new \stdClass(); | ||||
|         $node->title     = $title; | ||||
|         $node->access    = $access; | ||||
|         $node->parent_id = $branchId; | ||||
|         $node->language  = $language; | ||||
|  | ||||
|         return self::storeNode($node, $branchId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to add a nested node to the taxonomy tree. | ||||
|      * | ||||
|      * @param   string         $branch    The title of the branch to store the node in. | ||||
|      * @param   NodeInterface  $node      The source-node of the taxonomy node. | ||||
|      * @param   integer        $state     The published state of the node. [optional] | ||||
|      * @param   integer        $access    The access state of the node. [optional] | ||||
|      * @param   string         $language  The language of the node. [optional] | ||||
|      * @param   integer        $branchId  ID of a branch if known. [optional] | ||||
|      * | ||||
|      * @return  integer  The id of the node. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public static function addNestedNode($branch, NodeInterface $node, $state = 1, $access = 1, $language = '*', $branchId = null) | ||||
|     { | ||||
|         if ($state != 1) { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         if (!$branchId) { | ||||
|             // Get the branch id, insert it if it does not exist. | ||||
|             $branchId = static::addBranch($branch); | ||||
|         } | ||||
|  | ||||
|         $parent = $node->getParent(); | ||||
|  | ||||
|         $pstate    = $node->state ?? ($node->published ?? $state); | ||||
|         $paccess   = $node->access ?? $access; | ||||
|         $planguage = $node->language ?? $language; | ||||
|  | ||||
|         if ($parent && $parent->title != 'ROOT') { | ||||
|             $parentId = self::addNestedNode($branch, $parent, $pstate, $paccess, $planguage, $branchId); | ||||
|         } else { | ||||
|             $parentId = $branchId; | ||||
|         } | ||||
|  | ||||
|         if (!$parentId) { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         $temp            = new \stdClass(); | ||||
|         $temp->title     = $node->title; | ||||
|         $temp->access    = $access; | ||||
|         $temp->parent_id = $parentId; | ||||
|         $temp->language  = $language; | ||||
|  | ||||
|         return self::storeNode($temp, $parentId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * A helper method to store a node in the taxonomy | ||||
|      * | ||||
|      * @param   object   $node      The node data to include | ||||
|      * @param   integer  $parentId  The parent id of the node to add. | ||||
|      * | ||||
|      * @return  integer  The id of the inserted node. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      * @throws  \RuntimeException | ||||
|      */ | ||||
|     protected static function storeNode($node, $parentId) | ||||
|     { | ||||
|         // Check to see if the node is in the cache. | ||||
|         if (isset(static::$nodes[$parentId . ':' . $node->title])) { | ||||
|             return static::$nodes[$parentId . ':' . $node->title]->id; | ||||
|         } | ||||
|  | ||||
|         // Check to see if the node is in the table. | ||||
|         $db    = Factory::getDbo(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select('*') | ||||
|             ->from($db->quoteName('#__finder_taxonomy')) | ||||
|             ->where($db->quoteName('parent_id') . ' = ' . $db->quote($parentId)) | ||||
|             ->where($db->quoteName('title') . ' = ' . $db->quote($node->title)) | ||||
|             ->where($db->quoteName('language') . ' = ' . $db->quote($node->language)); | ||||
|  | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         // Get the result. | ||||
|         $result = $db->loadObject(); | ||||
|  | ||||
|         // Check if the database matches the input data. | ||||
|         if ((bool) $result && $result->access == $node->access) { | ||||
|             // The data matches, add the item to the cache. | ||||
|             static::$nodes[$parentId . ':' . $node->title] = $result; | ||||
|  | ||||
|             return static::$nodes[$parentId . ':' . $node->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. | ||||
|          * @todo: use factory? | ||||
|          */ | ||||
|         $nodeTable = new MapTable($db); | ||||
|  | ||||
|         if (empty($result)) { | ||||
|             // Prepare the node object. | ||||
|             $nodeTable->title    = $node->title; | ||||
|             $nodeTable->access   = (int) $node->access; | ||||
|             $nodeTable->language = $node->language; | ||||
|             $nodeTable->setLocation((int) $parentId, 'last-child'); | ||||
|         } else { | ||||
|             // Prepare the node object. | ||||
|             $nodeTable->id       = (int) $result->id; | ||||
|             $nodeTable->title    = $result->title; | ||||
|             $nodeTable->access   = (int) $result->access; | ||||
|             $nodeTable->language = $node->language; | ||||
|             $nodeTable->setLocation($result->parent_id, 'last-child'); | ||||
|         } | ||||
|  | ||||
|         // Check the data. | ||||
|         if (!$nodeTable->check()) { | ||||
|             $error = $nodeTable->getError(); | ||||
|  | ||||
|             if ($error instanceof \Exception) { | ||||
|                 // \Joomla\CMS\Table\NestedTable sets errors of exceptions, so in this case we can pass on more | ||||
|                 // information | ||||
|                 throw new \RuntimeException( | ||||
|                     $error->getMessage(), | ||||
|                     $error->getCode(), | ||||
|                     $error | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             // Standard string returned. Probably from the \Joomla\CMS\Table\Table class | ||||
|             throw new \RuntimeException($error, 500); | ||||
|         } | ||||
|  | ||||
|         // Store the data. | ||||
|         if (!$nodeTable->store()) { | ||||
|             $error = $nodeTable->getError(); | ||||
|  | ||||
|             if ($error instanceof \Exception) { | ||||
|                 // \Joomla\CMS\Table\NestedTable sets errors of exceptions, so in this case we can pass on more | ||||
|                 // information | ||||
|                 throw new \RuntimeException( | ||||
|                     $error->getMessage(), | ||||
|                     $error->getCode(), | ||||
|                     $error | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             // Standard string returned. Probably from the \Joomla\CMS\Table\Table class | ||||
|             throw new \RuntimeException($error, 500); | ||||
|         } | ||||
|  | ||||
|         $nodeTable->rebuildPath($nodeTable->id); | ||||
|  | ||||
|         // Add the node to the cache. | ||||
|         static::$nodes[$parentId . ':' . $nodeTable->title] = (object) $nodeTable->getProperties(); | ||||
|  | ||||
|         return static::$nodes[$parentId . ':' . $nodeTable->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  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function addMap($linkId, $nodeId) | ||||
|     { | ||||
|         // Insert the map. | ||||
|         $db = Factory::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(); | ||||
|  | ||||
|         if (!$id) { | ||||
|             $map          = new \stdClass(); | ||||
|             $map->link_id = (int) $linkId; | ||||
|             $map->node_id = (int) $nodeId; | ||||
|             $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  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function getBranchTitles() | ||||
|     { | ||||
|         $db = Factory::getDbo(); | ||||
|  | ||||
|         // Set user variables | ||||
|         $groups = implode(',', Factory::getUser()->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); | ||||
|  | ||||
|         return $db->loadColumn(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function getNodeByTitle($branch, $title) | ||||
|     { | ||||
|         $db = Factory::getDbo(); | ||||
|  | ||||
|         // Set user variables | ||||
|         $groups = implode(',', Factory::getUser()->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. | ||||
|         $query->setLimit(1); | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         return $db->loadObject(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove map entries for a link. | ||||
|      * | ||||
|      * @param   integer  $linkId  The link to remove. | ||||
|      * | ||||
|      * @return  boolean  True on success. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function removeMaps($linkId) | ||||
|     { | ||||
|         // Delete the maps. | ||||
|         $db    = Factory::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 maps | ||||
|      * | ||||
|      * @return  integer  The number of deleted rows. | ||||
|      * | ||||
|      * @since   4.2.0 | ||||
|      * @throws  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function removeOrphanMaps() | ||||
|     { | ||||
|         // Delete all orphaned maps | ||||
|         $db     = Factory::getDbo(); | ||||
|         $query2 = $db->getQuery(true) | ||||
|             ->select($db->quoteName('link_id')) | ||||
|             ->from($db->quoteName('#__finder_links')); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->delete($db->quoteName('#__finder_taxonomy_map')) | ||||
|             ->where($db->quoteName('link_id') . ' NOT IN (' . $query2 . ')'); | ||||
|         $db->setQuery($query); | ||||
|         $db->execute(); | ||||
|         $count = $db->getAffectedRows(); | ||||
|  | ||||
|         return $count; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to remove orphaned taxonomy nodes and branches. | ||||
|      * | ||||
|      * @return  integer  The number of deleted rows. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      * @throws  \RuntimeException on database error. | ||||
|      */ | ||||
|     public static function removeOrphanNodes() | ||||
|     { | ||||
|         // Delete all orphaned nodes. | ||||
|         $affectedRows = 0; | ||||
|         $db           = Factory::getDbo(); | ||||
|         $nodeTable    = new MapTable($db); | ||||
|         $query        = $db->getQuery(true); | ||||
|  | ||||
|         $query->select($db->quoteName('t.id')) | ||||
|             ->from($db->quoteName('#__finder_taxonomy', 't')) | ||||
|             ->join('LEFT', $db->quoteName('#__finder_taxonomy_map', 'm') . ' ON ' . $db->quoteName('m.node_id') . '=' . $db->quoteName('t.id')) | ||||
|             ->where($db->quoteName('t.parent_id') . ' > 1 ') | ||||
|             ->where('t.lft + 1 = t.rgt') | ||||
|             ->where($db->quoteName('m.link_id') . ' IS NULL'); | ||||
|  | ||||
|         do { | ||||
|             $db->setQuery($query); | ||||
|             $nodes = $db->loadColumn(); | ||||
|  | ||||
|             foreach ($nodes as $node) { | ||||
|                 $nodeTable->delete($node); | ||||
|                 $affectedRows++; | ||||
|             } | ||||
|         } while ($nodes); | ||||
|  | ||||
|         return $affectedRows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a taxonomy based on its id or all taxonomies | ||||
|      * | ||||
|      * @param   integer  $id  Id of the taxonomy | ||||
|      * | ||||
|      * @return  object|object[]  A taxonomy object or an array of all taxonomies | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public static function getTaxonomy($id = 0) | ||||
|     { | ||||
|         if (!\count(self::$taxonomies)) { | ||||
|             $db    = Factory::getDbo(); | ||||
|             $query = $db->getQuery(true); | ||||
|  | ||||
|             $query->select(['id','parent_id','lft','rgt','level','path','title','alias','state','access','language']) | ||||
|                 ->from($db->quoteName('#__finder_taxonomy')) | ||||
|                 ->order($db->quoteName('lft')); | ||||
|  | ||||
|             $db->setQuery($query); | ||||
|             self::$taxonomies = $db->loadObjectList('id'); | ||||
|         } | ||||
|  | ||||
|         if ($id == 0) { | ||||
|             return self::$taxonomies; | ||||
|         } | ||||
|  | ||||
|         if (isset(self::$taxonomies[$id])) { | ||||
|             return self::$taxonomies[$id]; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a taxonomy branch object based on its title or all branches | ||||
|      * | ||||
|      * @param   string  $title  Title of the branch | ||||
|      * | ||||
|      * @return  object|object[]  The object with the branch data or an array of all branches | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public static function getBranch($title = '') | ||||
|     { | ||||
|         if (!\count(self::$branches)) { | ||||
|             $taxonomies = self::getTaxonomy(); | ||||
|  | ||||
|             foreach ($taxonomies as $t) { | ||||
|                 if ($t->level == 1) { | ||||
|                     self::$branches[$t->title] = $t; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($title == '') { | ||||
|             return self::$branches; | ||||
|         } | ||||
|  | ||||
|         if (isset(self::$branches[$title])) { | ||||
|             return self::$branches[$title]; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										186
									
								
								administrator/components/com_finder/src/Indexer/Token.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								administrator/components/com_finder/src/Indexer/Token.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,186 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Indexer; | ||||
|  | ||||
| use Joomla\String\StringHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Token class for the Finder indexer package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Token | ||||
| { | ||||
|     /** | ||||
|      * 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; | ||||
|  | ||||
|     /** | ||||
|      * The container for matches. | ||||
|      * | ||||
|      * @var    array | ||||
|      * @since  3.8.12 | ||||
|      */ | ||||
|     public $matches = []; | ||||
|  | ||||
|     /** | ||||
|      * Is derived token (from individual words) | ||||
|      * | ||||
|      * @var    boolean | ||||
|      * @since  3.8.12 | ||||
|      */ | ||||
|     public $derived; | ||||
|  | ||||
|     /** | ||||
|      * The suggested term | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  3.8.12 | ||||
|      */ | ||||
|     public $suggestion; | ||||
|  | ||||
|     /** | ||||
|      * The token required flag | ||||
|      * | ||||
|      * @var    boolean | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $required; | ||||
|  | ||||
|     /** | ||||
|      * 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 = ' ') | ||||
|     { | ||||
|         if (!$lang) { | ||||
|             $this->language = '*'; | ||||
|         } else { | ||||
|             $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. | ||||
|             $langs         = array_fill(0, \count($term), $lang); | ||||
|             $this->term    = implode($spacer, $term); | ||||
|             $this->stem    = implode($spacer, array_map([Helper::class, 'stem'], $term, $langs)); | ||||
|             $this->numeric = false; | ||||
|             $this->common  = false; | ||||
|             $this->phrase  = true; | ||||
|             $this->length  = StringHelper::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 = (min($this->length, 30) / 30) + 1; | ||||
|             $this->weight = round($this->weight, 4); | ||||
|         } else { | ||||
|             // Populate the token instance. | ||||
|             $this->term    = $term; | ||||
|             $this->stem    = Helper::stem($this->term, $lang); | ||||
|             $this->numeric = (is_numeric($this->term) || (bool) preg_match('#^[0-9,.\-\+]+$#', $this->term)); | ||||
|             $this->common  = $this->numeric ? false : Helper::isCommon($this->term, $lang); | ||||
|             $this->phrase  = false; | ||||
|             $this->length  = StringHelper::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 = min($this->length, 15) / 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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										154
									
								
								administrator/components/com_finder/src/Model/FilterModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								administrator/components/com_finder/src/Model/FilterModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Form\Form; | ||||
| use Joomla\CMS\MVC\Model\AdminModel; | ||||
| use Joomla\Component\Finder\Administrator\Table\FilterTable; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filter model class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FilterModel extends AdminModel | ||||
| { | ||||
|     /** | ||||
|      * 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  $clientId  No longer used, will be removed without replacement | ||||
|      *                              @deprecated   4.3 will be removed in 6.0 | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function cleanCache($group = 'com_finder', $clientId = 0) | ||||
|     { | ||||
|         parent::cleanCache($group); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the filter data. | ||||
|      * | ||||
|      * @return  FilterTable|boolean  The filter data or false on a failure. | ||||
|      * | ||||
|      * @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 = []; | ||||
|         } | ||||
|  | ||||
|         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  Form|boolean  A Form object on success, false on failure | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getForm($data = [], $loadData = true) | ||||
|     { | ||||
|         // Get the form. | ||||
|         $form = $this->loadForm('com_finder.filter', 'filter', ['control' => 'jform', 'load_data' => $loadData]); | ||||
|  | ||||
|         if (empty($form)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return $form; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 = Factory::getApplication()->getUserState('com_finder.edit.filter.data', []); | ||||
|  | ||||
|         if (empty($data)) { | ||||
|             $data = $this->getItem(); | ||||
|         } | ||||
|  | ||||
|         $this->preprocessData('com_finder.filter', $data); | ||||
|  | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the total indexed items | ||||
|      * | ||||
|      * @return  integer  The count of indexed items | ||||
|      * | ||||
|      * @since  3.5 | ||||
|      */ | ||||
|     public function getTotal() | ||||
|     { | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select('MAX(link_id)') | ||||
|             ->from('#__finder_links'); | ||||
|  | ||||
|         return $db->setQuery($query)->loadResult(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										138
									
								
								administrator/components/com_finder/src/Model/FiltersModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								administrator/components/com_finder/src/Model/FiltersModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\MVC\Factory\MVCFactoryInterface; | ||||
| use Joomla\CMS\MVC\Model\ListModel; | ||||
| use Joomla\Database\QueryInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filters model class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FiltersModel extends ListModel | ||||
| { | ||||
|     /** | ||||
|      * Constructor. | ||||
|      * | ||||
|      * @param   array                 $config   An optional associative array of configuration settings. | ||||
|      * @param   ?MVCFactoryInterface  $factory  The factory. | ||||
|      * | ||||
|      * @see     \Joomla\CMS\MVC\Model\BaseDatabaseModel | ||||
|      * @since   3.7 | ||||
|      */ | ||||
|     public function __construct($config = [], ?MVCFactoryInterface $factory = null) | ||||
|     { | ||||
|         if (empty($config['filter_fields'])) { | ||||
|             $config['filter_fields'] = [ | ||||
|                 '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, $factory); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build an SQL query to load the list data. | ||||
|      * | ||||
|      * @return  QueryInterface | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function getListQuery() | ||||
|     { | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true); | ||||
|  | ||||
|         // Select all fields from the table. | ||||
|         $query->select('a.*') | ||||
|             ->from($db->quoteName('#__finder_filters', 'a')); | ||||
|  | ||||
|         // Join over the users for the checked out user. | ||||
|         $query->select($db->quoteName('uc.name', 'editor')) | ||||
|             ->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')); | ||||
|  | ||||
|         // Join over the users for the author. | ||||
|         $query->select($db->quoteName('ua.name', 'user_name')) | ||||
|             ->join('LEFT', $db->quoteName('#__users', 'ua') . ' ON ' . $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')); | ||||
|  | ||||
|         // Check for a search filter. | ||||
|         if ($search = $this->getState('filter.search')) { | ||||
|             $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%')); | ||||
|             $query->where($db->quoteName('a.title') . ' LIKE ' . $search); | ||||
|         } | ||||
|  | ||||
|         // If the model is set to check item state, add to the query. | ||||
|         $state = $this->getState('filter.state'); | ||||
|  | ||||
|         if (is_numeric($state)) { | ||||
|             $query->where($db->quoteName('a.state') . ' = ' . (int) $state); | ||||
|         } | ||||
|  | ||||
|         // Add the list ordering clause. | ||||
|         $query->order($db->escape($this->getState('list.ordering', 'a.title') . ' ' . $db->escape($this->getState('list.direction', 'ASC')))); | ||||
|  | ||||
|         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 = 'a.title', $direction = 'asc') | ||||
|     { | ||||
|         // Load the parameters. | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|         $this->setState('params', $params); | ||||
|  | ||||
|         // List state information. | ||||
|         parent::populateState($ordering, $direction); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										460
									
								
								administrator/components/com_finder/src/Model/IndexModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										460
									
								
								administrator/components/com_finder/src/Model/IndexModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,460 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Factory\MVCFactoryInterface; | ||||
| use Joomla\CMS\MVC\Model\ListModel; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\Database\QueryInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Index model class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class IndexModel extends ListModel | ||||
| { | ||||
|     /** | ||||
|      * 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'; | ||||
|  | ||||
|     /** | ||||
|      * The event to trigger after purging the data. | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $event_after_purge = 'onFinderIndexAfterPurge'; | ||||
|  | ||||
|     /** | ||||
|      * Constructor. | ||||
|      * | ||||
|      * @param   array                 $config   An optional associative array of configuration settings. | ||||
|      * @param   ?MVCFactoryInterface  $factory  The factory. | ||||
|      * | ||||
|      * @see     \Joomla\CMS\MVC\Model\BaseDatabaseModel | ||||
|      * @since   3.7 | ||||
|      */ | ||||
|     public function __construct($config = [], ?MVCFactoryInterface $factory = null) | ||||
|     { | ||||
|         if (empty($config['filter_fields'])) { | ||||
|             $config['filter_fields'] = [ | ||||
|                 'state', 'published', 'l.published', | ||||
|                 'title', 'l.title', | ||||
|                 'type', 'type_id', 'l.type_id', | ||||
|                 't.title', 't_title', | ||||
|                 'url', 'l.url', | ||||
|                 'language', 'l.language', | ||||
|                 'indexdate', 'l.indexdate', | ||||
|                 'content_map', | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|         parent::__construct($config, $factory); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         return $this->getCurrentUser()->authorise('core.delete', $this->option); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to test whether a record can have its state changed. | ||||
|      * | ||||
|      * @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) | ||||
|     { | ||||
|         return $this->getCurrentUser()->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) | ||||
|     { | ||||
|         $pks   = (array) $pks; | ||||
|         $table = $this->getTable(); | ||||
|  | ||||
|         // Include the content plugins for the on delete events. | ||||
|         PluginHelper::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 = Factory::getApplication()->triggerEvent($this->event_before_delete, [$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. | ||||
|                     Factory::getApplication()->triggerEvent($this->event_after_delete, [$context, $table]); | ||||
|                 } else { | ||||
|                     // Prune items that you can't change. | ||||
|                     unset($pks[$i]); | ||||
|                     $error = $this->getError(); | ||||
|  | ||||
|                     if ($error) { | ||||
|                         $this->setError($error); | ||||
|                     } else { | ||||
|                         $this->setError(Text::_('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  QueryInterface | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function getListQuery() | ||||
|     { | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select('l.*') | ||||
|             ->select($db->quoteName('t.title', 't_title')) | ||||
|             ->from($db->quoteName('#__finder_links', 'l')) | ||||
|             ->join('INNER', $db->quoteName('#__finder_types', 't') . ' ON ' . $db->quoteName('t.id') . ' = ' . $db->quoteName('l.type_id')); | ||||
|  | ||||
|         // Check the type filter. | ||||
|         $type = $this->getState('filter.type'); | ||||
|  | ||||
|         // Join over the language | ||||
|         $query->select('la.title AS language_title, la.image AS language_image') | ||||
|             ->join('LEFT', $db->quoteName('#__languages') . ' AS la ON la.lang_code = l.language'); | ||||
|  | ||||
|         if (is_numeric($type)) { | ||||
|             $query->where($db->quoteName('l.type_id') . ' = ' . (int) $type); | ||||
|         } | ||||
|  | ||||
|         // Check the map filter. | ||||
|         $contentMapId = $this->getState('filter.content_map'); | ||||
|  | ||||
|         if (is_numeric($contentMapId)) { | ||||
|             $query->join('INNER', $db->quoteName('#__finder_taxonomy_map', 'm') . ' ON ' . $db->quoteName('m.link_id') . ' = ' . $db->quoteName('l.link_id')) | ||||
|                 ->where($db->quoteName('m.node_id') . ' = ' . (int) $contentMapId); | ||||
|         } | ||||
|  | ||||
|         // Check for state filter. | ||||
|         $state = $this->getState('filter.state'); | ||||
|  | ||||
|         if (is_numeric($state)) { | ||||
|             $query->where($db->quoteName('l.published') . ' = ' . (int) $state); | ||||
|         } | ||||
|  | ||||
|         // Filter on the language. | ||||
|         if ($language = $this->getState('filter.language')) { | ||||
|             $query->where($db->quoteName('l.language') . ' = ' . $db->quote($language)); | ||||
|         } | ||||
|  | ||||
|         // Check the search phrase. | ||||
|         $search = $this->getState('filter.search'); | ||||
|  | ||||
|         if (!empty($search)) { | ||||
|             $search      = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%')); | ||||
|             $orSearchSql = $db->quoteName('l.title') . ' LIKE ' . $search . ' OR ' . $db->quoteName('l.url') . ' LIKE ' . $search; | ||||
|  | ||||
|             // Filter by indexdate only if $search doesn't contains non-ascii characters | ||||
|             if (!preg_match('/[^\x00-\x7F]/', $search)) { | ||||
|                 $orSearchSql .= ' OR ' . $query->castAsChar($db->quoteName('l.indexdate')) . ' LIKE ' . $search; | ||||
|             } | ||||
|  | ||||
|             $query->where('(' . $orSearchSql . ')'); | ||||
|         } | ||||
|  | ||||
|         // Handle the list ordering. | ||||
|         $listOrder = $this->getState('list.ordering', 'l.title'); | ||||
|         $listDir   = $this->getState('list.direction', 'ASC'); | ||||
|  | ||||
|         if ($listOrder === 't.title') { | ||||
|             $ordering = $db->quoteName('t.title') . ' ' . $db->escape($listDir) . ', ' . $db->quoteName('l.title') . ' ' . $db->escape($listDir); | ||||
|         } else { | ||||
|             $ordering = $db->escape($listOrder) . ' ' . $db->escape($listDir); | ||||
|         } | ||||
|  | ||||
|         $query->order($ordering); | ||||
|  | ||||
|         return $query; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the state of the Smart Search Plugins. | ||||
|      * | ||||
|      * @return  array  Array of relevant plugins and whether they are enabled or not. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getPluginState() | ||||
|     { | ||||
|         $db    = $this->getDatabase(); | ||||
|         $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); | ||||
|  | ||||
|         return $db->loadObjectList('name'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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'); | ||||
|         $id .= ':' . $this->getState('filter.content_map'); | ||||
|  | ||||
|         return parent::getStoreId($id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the total of indexed items. | ||||
|      * | ||||
|      * @return  integer  The total of indexed items. | ||||
|      * | ||||
|      * @since   3.6.0 | ||||
|      */ | ||||
|     public function getTotalIndexed() | ||||
|     { | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select('COUNT(link_id)') | ||||
|             ->from($db->quoteName('#__finder_links')); | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         return (int) $db->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a Table 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  \Joomla\CMS\Table\Table  A database object | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getTable($type = 'Link', $prefix = 'Administrator', $config = []) | ||||
|     { | ||||
|         return parent::getTable($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->getDatabase(); | ||||
|  | ||||
|         // Truncate the links table. | ||||
|         $db->truncateTable('#__finder_links'); | ||||
|  | ||||
|         // Truncate the links terms tables. | ||||
|         $db->truncateTable('#__finder_links_terms'); | ||||
|  | ||||
|         // Truncate the terms table. | ||||
|         $db->truncateTable('#__finder_terms'); | ||||
|  | ||||
|         // Truncate the taxonomy map table. | ||||
|         $db->truncateTable('#__finder_taxonomy_map'); | ||||
|  | ||||
|         // Truncate the taxonomy table and insert the root node. | ||||
|         $db->truncateTable('#__finder_taxonomy'); | ||||
|         $root = (object) [ | ||||
|             'id'        => 1, | ||||
|             'parent_id' => 0, | ||||
|             'lft'       => 0, | ||||
|             'rgt'       => 1, | ||||
|             'level'     => 0, | ||||
|             'path'      => '', | ||||
|             'title'     => 'ROOT', | ||||
|             'alias'     => 'root', | ||||
|             'state'     => 1, | ||||
|             'access'    => 1, | ||||
|             'language'  => '*', | ||||
|         ]; | ||||
|         $db->insertObject('#__finder_taxonomy', $root); | ||||
|  | ||||
|         // Truncate the tokens tables. | ||||
|         $db->truncateTable('#__finder_tokens'); | ||||
|  | ||||
|         // Truncate the tokens aggregate table. | ||||
|         $db->truncateTable('#__finder_tokens_aggregate'); | ||||
|  | ||||
|         // Include the finder plugins for the on purge events. | ||||
|         PluginHelper::importPlugin('finder'); | ||||
|         Factory::getApplication()->triggerEvent($this->event_after_purge); | ||||
|  | ||||
|         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 = 'l.title', $direction = 'asc') | ||||
|     { | ||||
|         // Load the parameters. | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|         $this->setState('params', $params); | ||||
|  | ||||
|         // List state information. | ||||
|         parent::populateState($ordering, $direction); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         $user  = $this->getCurrentUser(); | ||||
|         $table = $this->getTable(); | ||||
|         $pks   = (array) $pks; | ||||
|  | ||||
|         // Include the content plugins for the change of state event. | ||||
|         PluginHelper::importPlugin('content'); | ||||
|  | ||||
|         // Access checks. | ||||
|         foreach ($pks as $i => $pk) { | ||||
|             $table->reset(); | ||||
|  | ||||
|             if ($table->load($pk) && !$this->canEditState($table)) { | ||||
|                 // Prune items that you can't change. | ||||
|                 unset($pks[$i]); | ||||
|                 $this->setError(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); | ||||
|  | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Attempt to change the state of the records. | ||||
|         if (!$table->publish($pks, $value, $user->id)) { | ||||
|             $this->setError($table->getError()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $context = $this->option . '.' . $this->name; | ||||
|  | ||||
|         // Trigger the onContentChangeState event. | ||||
|         $result = Factory::getApplication()->triggerEvent('onContentChangeState', [$context, $pks, $value]); | ||||
|  | ||||
|         if (\in_array(false, $result, true)) { | ||||
|             $this->setError($table->getError()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Clear the component's cache | ||||
|         $this->cleanCache(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Form\Form; | ||||
| use Joomla\CMS\MVC\Model\FormModel; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Indexer model class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class IndexerModel extends FormModel | ||||
| { | ||||
|     /** | ||||
|      * Method for getting a form. | ||||
|      * | ||||
|      * @param   array    $data      Data for the form. | ||||
|      * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not. | ||||
|      * | ||||
|      * @return  Form | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      * | ||||
|      * @throws \Exception | ||||
|      */ | ||||
|     public function getForm($data = [], $loadData = true) | ||||
|     { | ||||
|         // Get the form. | ||||
|         $form = $this->loadForm('com_finder.indexer', 'indexer', ['control' => '', 'load_data' => $loadData]); | ||||
|  | ||||
|         if (empty($form)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return $form; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										107
									
								
								administrator/components/com_finder/src/Model/ItemModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								administrator/components/com_finder/src/Model/ItemModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\MVC\Model\BaseDatabaseModel; | ||||
| use Joomla\Database\ParameterType; | ||||
|  | ||||
| /** | ||||
|  * Index Item model class for Finder. | ||||
|  * | ||||
|  * @since  5.0.0 | ||||
|  */ | ||||
| class ItemModel extends BaseDatabaseModel | ||||
| { | ||||
|     /** | ||||
|      * Stock method to auto-populate the model state. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     protected function populateState() | ||||
|     { | ||||
|         // Get the pk of the record from the request. | ||||
|         $pk = Factory::getApplication()->getInput()->getInt('id'); | ||||
|         $this->setState('item.link_id', $pk); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a finder link object | ||||
|      * | ||||
|      * @return  object | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function getItem() | ||||
|     { | ||||
|         $link_id = (int) $this->getState('item.link_id'); | ||||
|         $db      = $this->getDatabase(); | ||||
|         $query   = $db->getQuery(true) | ||||
|             ->select('*') | ||||
|             ->from($db->quoteName('#__finder_links', 'l')) | ||||
|             ->where($db->quoteName('l.link_id') . ' = :link_id') | ||||
|             ->bind(':link_id', $link_id, ParameterType::INTEGER); | ||||
|  | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         return $db->loadObject(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get terms associated with a finder link | ||||
|      * | ||||
|      * @return  object[] | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function getTerms() | ||||
|     { | ||||
|         $link_id = (int) $this->getState('item.link_id'); | ||||
|         $db      = $this->getDatabase(); | ||||
|         $query   = $db->getQuery(true) | ||||
|             ->select('t.*, l.*') | ||||
|             ->from($db->quoteName('#__finder_links_terms', 'l')) | ||||
|             ->leftJoin($db->quoteName('#__finder_terms', 't') . ' ON ' . $db->quoteName('t.term_id') . ' = ' . $db->quoteName('l.term_id')) | ||||
|             ->where($db->quoteName('l.link_id') . ' = :link_id') | ||||
|             ->order('l.weight') | ||||
|             ->bind(':link_id', $link_id, ParameterType::INTEGER); | ||||
|  | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         return $db->loadObjectList(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get taxonomies associated with a finder link | ||||
|      * | ||||
|      * @return  \stdClass[] | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function getTaxonomies() | ||||
|     { | ||||
|         $link_id = (int) $this->getState('item.link_id'); | ||||
|         $db      = $this->getDatabase(); | ||||
|         $query   = $db->getQuery(true) | ||||
|             ->select('t.*, m.*') | ||||
|             ->from($db->quoteName('#__finder_taxonomy_map', 'm')) | ||||
|             ->leftJoin($db->quoteName('#__finder_taxonomy', 't') . ' ON ' . $db->quoteName('t.id') . ' = ' . $db->quoteName('m.node_id')) | ||||
|             ->where($db->quoteName('m.link_id') . ' = :link_id') | ||||
|             ->order('t.title') | ||||
|             ->bind(':link_id', $link_id, ParameterType::INTEGER); | ||||
|  | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         return $db->loadObjectList(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										398
									
								
								administrator/components/com_finder/src/Model/MapsModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								administrator/components/com_finder/src/Model/MapsModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,398 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\Factory\MVCFactoryInterface; | ||||
| use Joomla\CMS\MVC\Model\ListModel; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\Database\DatabaseQuery; | ||||
| use Joomla\Database\QueryInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Maps model for the Finder package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class MapsModel extends ListModel | ||||
| { | ||||
|     /** | ||||
|      * Constructor. | ||||
|      * | ||||
|      * @param   array                 $config   An optional associative array of configuration settings. | ||||
|      * @param   ?MVCFactoryInterface  $factory  The factory. | ||||
|      * | ||||
|      * @see     \Joomla\CMS\MVC\Model\BaseDatabaseModel | ||||
|      * @since   3.7 | ||||
|      */ | ||||
|     public function __construct($config = [], ?MVCFactoryInterface $factory = null) | ||||
|     { | ||||
|         if (empty($config['filter_fields'])) { | ||||
|             $config['filter_fields'] = [ | ||||
|                 'state', 'a.state', | ||||
|                 'title', 'a.title', | ||||
|                 'branch', | ||||
|                 'branch_title', 'd.branch_title', | ||||
|                 'level', 'd.level', | ||||
|                 'language', 'a.language', | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|         parent::__construct($config, $factory); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         return $this->getCurrentUser()->authorise('core.delete', $this->option); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to test whether a record can have its state changed. | ||||
|      * | ||||
|      * @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) | ||||
|     { | ||||
|         return $this->getCurrentUser()->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) | ||||
|     { | ||||
|         $pks   = (array) $pks; | ||||
|         $table = $this->getTable(); | ||||
|  | ||||
|         // Include the content plugins for the on delete events. | ||||
|         PluginHelper::importPlugin('content'); | ||||
|  | ||||
|         // Iterate the items to check if all of them exist. | ||||
|         foreach ($pks as $i => $pk) { | ||||
|             if (!$table->load($pk)) { | ||||
|                 // Item is not in the table. | ||||
|                 $this->setError($table->getError()); | ||||
|  | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 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 = Factory::getApplication()->triggerEvent('onContentBeforeDelete', [$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. | ||||
|                     Factory::getApplication()->triggerEvent('onContentAfterDelete', [$context, $table]); | ||||
|                 } else { | ||||
|                     // Prune items that you can't change. | ||||
|                     unset($pks[$i]); | ||||
|                     $error = $this->getError(); | ||||
|  | ||||
|                     if ($error) { | ||||
|                         $this->setError($error); | ||||
|                     } else { | ||||
|                         $this->setError(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Clear the component's cache | ||||
|         $this->cleanCache(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build an SQL query to load the list data. | ||||
|      * | ||||
|      * @return  QueryInterface | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function getListQuery() | ||||
|     { | ||||
|         $db = $this->getDatabase(); | ||||
|  | ||||
|         // Select all fields from the table. | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select('a.id, a.parent_id, a.lft, a.rgt, a.level, a.path, a.title, a.alias, a.state, a.access, a.language') | ||||
|             ->from($db->quoteName('#__finder_taxonomy', 'a')) | ||||
|             ->where('a.parent_id != 0'); | ||||
|  | ||||
|         // Join to get the branch title | ||||
|         $query->select([$db->quoteName('b.id', 'branch_id'), $db->quoteName('b.title', 'branch_title')]) | ||||
|             ->leftJoin($db->quoteName('#__finder_taxonomy', 'b') . ' ON b.level = 1 AND b.lft <= a.lft AND a.rgt <= b.rgt'); | ||||
|  | ||||
|         // Join to get the map links. | ||||
|         $stateQuery = $db->getQuery(true) | ||||
|             ->select('m.node_id') | ||||
|             ->select('COUNT(NULLIF(l.published, 0)) AS count_published') | ||||
|             ->select('COUNT(NULLIF(l.published, 1)) AS count_unpublished') | ||||
|             ->from($db->quoteName('#__finder_taxonomy_map', 'm')) | ||||
|             ->leftJoin($db->quoteName('#__finder_links', 'l') . ' ON l.link_id = m.link_id') | ||||
|             ->group('m.node_id'); | ||||
|  | ||||
|         $query->select('COALESCE(s.count_published, 0) AS count_published'); | ||||
|         $query->select('COALESCE(s.count_unpublished, 0) AS count_unpublished'); | ||||
|         $query->leftJoin('(' . $stateQuery . ') AS s ON s.node_id = a.id'); | ||||
|  | ||||
|         // If the model is set to check item state, add to the query. | ||||
|         $state = $this->getState('filter.state'); | ||||
|  | ||||
|         if (is_numeric($state)) { | ||||
|             $query->where('a.state = ' . (int) $state); | ||||
|         } | ||||
|  | ||||
|         // Filter over level. | ||||
|         $level = $this->getState('filter.level'); | ||||
|  | ||||
|         if (is_numeric($level) && (int) $level === 1) { | ||||
|             $query->where('a.parent_id = 1'); | ||||
|         } | ||||
|  | ||||
|         // Filter the maps over the branch if set. | ||||
|         $branchId = $this->getState('filter.branch'); | ||||
|  | ||||
|         if (is_numeric($branchId)) { | ||||
|             $query->where('a.parent_id = ' . (int) $branchId); | ||||
|         } | ||||
|  | ||||
|         // Filter the maps over the search string if set. | ||||
|         if ($search = $this->getState('filter.search')) { | ||||
|             $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%')); | ||||
|             $query->where('a.title LIKE ' . $search); | ||||
|         } | ||||
|  | ||||
|         // Add the list ordering clause. | ||||
|         $query->order($db->escape($this->getState('list.ordering', 'branch_title, a.lft')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); | ||||
|  | ||||
|         return $query; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a record count for the query. | ||||
|      * | ||||
|      * @param   \Joomla\Database\DatabaseQuery|string | ||||
|      * | ||||
|      * @return  integer  Number of rows for query. | ||||
|      * | ||||
|      * @since   3.0 | ||||
|      */ | ||||
|     protected function _getListCount($query) | ||||
|     { | ||||
|         $query = clone $query; | ||||
|         $query->clear('select')->clear('join')->clear('order')->clear('limit')->clear('offset')->select('COUNT(*)'); | ||||
|  | ||||
|         return (int) $this->getDatabase()->setQuery($query)->loadResult(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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.branch'); | ||||
|         $id .= ':' . $this->getState('filter.level'); | ||||
|  | ||||
|         return parent::getStoreId($id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a Table 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  \Joomla\CMS\Table\Table  A database object | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getTable($type = 'Map', $prefix = 'Administrator', $config = []) | ||||
|     { | ||||
|         return parent::getTable($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 = 'branch_title, a.lft', $direction = 'ASC') | ||||
|     { | ||||
|         // Load the parameters. | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|         $this->setState('params', $params); | ||||
|  | ||||
|         // List state information. | ||||
|         parent::populateState($ordering, $direction); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     { | ||||
|         $user  = $this->getCurrentUser(); | ||||
|         $table = $this->getTable(); | ||||
|         $pks   = (array) $pks; | ||||
|  | ||||
|         // Include the content plugins for the change of state event. | ||||
|         PluginHelper::importPlugin('content'); | ||||
|  | ||||
|         // Access checks. | ||||
|         foreach ($pks as $i => $pk) { | ||||
|             $table->reset(); | ||||
|  | ||||
|             if ($table->load($pk) && !$this->canEditState($table)) { | ||||
|                 // Prune items that you can't change. | ||||
|                 unset($pks[$i]); | ||||
|                 $this->setError(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED')); | ||||
|  | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Attempt to change the state of the records. | ||||
|         if (!$table->publish($pks, $value, $user->id)) { | ||||
|             $this->setError($table->getError()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $context = $this->option . '.' . $this->name; | ||||
|  | ||||
|         // Trigger the onContentChangeState event. | ||||
|         $result = Factory::getApplication()->triggerEvent('onContentChangeState', [$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->getDatabase(); | ||||
|         $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')); | ||||
|         $db->setQuery($query); | ||||
|         $db->execute(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Manipulate the query to be used to evaluate if this is an Empty State to provide specific conditions for this extension. | ||||
|      * | ||||
|      * @return DatabaseQuery | ||||
|      * | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     protected function getEmptyStateQuery() | ||||
|     { | ||||
|         $query = parent::getEmptyStateQuery(); | ||||
|  | ||||
|         $title = 'ROOT'; | ||||
|  | ||||
|         $query->where($this->getDatabase()->quoteName('title') . ' <> :title') | ||||
|             ->bind(':title', $title); | ||||
|  | ||||
|         return $query; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										174
									
								
								administrator/components/com_finder/src/Model/SearchesModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								administrator/components/com_finder/src/Model/SearchesModel.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\MVC\Factory\MVCFactoryInterface; | ||||
| use Joomla\CMS\MVC\Model\ListModel; | ||||
| use Joomla\Database\QueryInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Methods supporting a list of search terms. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class SearchesModel extends ListModel | ||||
| { | ||||
|     /** | ||||
|      * Constructor. | ||||
|      * | ||||
|      * @param   array                 $config   An optional associative array of configuration settings. | ||||
|      * @param   ?MVCFactoryInterface  $factory  The factory. | ||||
|      * | ||||
|      * @see     \Joomla\CMS\MVC\Model\BaseDatabaseModel | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function __construct($config = [], ?MVCFactoryInterface $factory = null) | ||||
|     { | ||||
|         if (empty($config['filter_fields'])) { | ||||
|             $config['filter_fields'] = [ | ||||
|                 'searchterm', 'a.searchterm', | ||||
|                 'hits', 'a.hits', | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|         parent::__construct($config, $factory); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to auto-populate the model state. | ||||
|      * | ||||
|      * Note. Calling getState in this method will result in recursion. | ||||
|      * | ||||
|      * @param   string  $ordering   An optional ordering field. | ||||
|      * @param   string  $direction  An optional direction (asc|desc). | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     protected function populateState($ordering = 'a.hits', $direction = 'asc') | ||||
|     { | ||||
|         // Special state for toggle results button. | ||||
|         $this->setState('show_results', $this->getUserStateFromRequest($this->context . '.show_results', 'show_results', 1, 'int')); | ||||
|  | ||||
|         // Load the parameters. | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|         $this->setState('params', $params); | ||||
|  | ||||
|         // List state information. | ||||
|         parent::populateState($ordering, $direction); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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. | ||||
|      * | ||||
|      * @return  string  A store id. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     protected function getStoreId($id = '') | ||||
|     { | ||||
|         // Compile the store id. | ||||
|         $id .= ':' . $this->getState('show_results'); | ||||
|         $id .= ':' . $this->getState('filter.search'); | ||||
|  | ||||
|         return parent::getStoreId($id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build an SQL query to load the list data. | ||||
|      * | ||||
|      * @return  QueryInterface | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     protected function getListQuery() | ||||
|     { | ||||
|         // Create a new query object. | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true); | ||||
|  | ||||
|         // Select the required fields from the table. | ||||
|         $query->select( | ||||
|             $this->getState( | ||||
|                 'list.select', | ||||
|                 'a.*' | ||||
|             ) | ||||
|         ); | ||||
|         $query->from($db->quoteName('#__finder_logging', 'a')); | ||||
|  | ||||
|         // Filter by search in title | ||||
|         if ($search = $this->getState('filter.search')) { | ||||
|             $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%')); | ||||
|             $query->where($db->quoteName('a.searchterm') . ' LIKE ' . $search); | ||||
|         } | ||||
|  | ||||
|         // Add the list ordering clause. | ||||
|         $query->order($db->escape($this->getState('list.ordering', 'a.hits')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); | ||||
|  | ||||
|         return $query; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Override the parent getItems to inject optional data. | ||||
|      * | ||||
|      * @return  mixed  An array of objects on success, false on failure. | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function getItems() | ||||
|     { | ||||
|         $items = parent::getItems(); | ||||
|  | ||||
|         foreach ($items as $item) { | ||||
|             if (\is_resource($item->query)) { | ||||
|                 $item->query = unserialize(stream_get_contents($item->query)); | ||||
|             } else { | ||||
|                 $item->query = unserialize($item->query); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $items; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to reset the search log table. | ||||
|      * | ||||
|      * @return  boolean | ||||
|      * | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function reset() | ||||
|     { | ||||
|         $db = $this->getDatabase(); | ||||
|  | ||||
|         try { | ||||
|             $db->truncateTable('#__finder_logging'); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             $this->setError($e->getMessage()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,87 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Model; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\MVC\Model\BaseDatabaseModel; | ||||
| use Joomla\CMS\Object\CMSObject; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Statistics model class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class StatisticsModel extends BaseDatabaseModel | ||||
| { | ||||
|     /** | ||||
|      * Method to get the component statistics | ||||
|      * | ||||
|      * @return  CMSObject The component statistics | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function getData() | ||||
|     { | ||||
|         // Initialise | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true); | ||||
|         $data  = new CMSObject(); | ||||
|  | ||||
|         $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(); | ||||
|  | ||||
|         $lang    = Factory::getLanguage(); | ||||
|         $plugins = PluginHelper::getPlugin('finder'); | ||||
|  | ||||
|         foreach ($plugins as $plugin) { | ||||
|             $lang->load('plg_finder_' . $plugin->name . '.sys', JPATH_ADMINISTRATOR) | ||||
|             || $lang->load('plg_finder_' . $plugin->name . '.sys', JPATH_PLUGINS . '/finder/' . $plugin->name); | ||||
|         } | ||||
|  | ||||
|         return $data; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										189
									
								
								administrator/components/com_finder/src/Response/Response.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								administrator/components/com_finder/src/Response/Response.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,189 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Response; | ||||
|  | ||||
| use Joomla\CMS\Component\ComponentHelper; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\Log\Log; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Finder Indexer JSON Response Class | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Response | ||||
| { | ||||
|     /** | ||||
|      * The buffer | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $buffer; | ||||
|  | ||||
|     /** | ||||
|      * The memory | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $memory; | ||||
|  | ||||
|     /** | ||||
|      * If it has an error | ||||
|      * | ||||
|      * @var    bool | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $error; | ||||
|  | ||||
|     /** | ||||
|      * The header | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $header; | ||||
|  | ||||
|     /** | ||||
|      * The message | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $message; | ||||
|  | ||||
|     /** | ||||
|      * The batch size | ||||
|      * | ||||
|      * @var    int | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $batchSize; | ||||
|  | ||||
|     /** | ||||
|      * The batch offset | ||||
|      * | ||||
|      * @var    int | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $batchOffset; | ||||
|  | ||||
|     /** | ||||
|      * The total items | ||||
|      * | ||||
|      * @var    int | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $totalItems; | ||||
|  | ||||
|     /** | ||||
|      * The plugin state | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $pluginState; | ||||
|  | ||||
|     /** | ||||
|      * The start time | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $startTime; | ||||
|  | ||||
|     /** | ||||
|      * The end time | ||||
|      * | ||||
|      * @var    string | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $endTime; | ||||
|  | ||||
|     /** | ||||
|      * The start | ||||
|      * | ||||
|      * @var    int | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $start; | ||||
|  | ||||
|     /** | ||||
|      * The complete | ||||
|      * | ||||
|      * @var    int | ||||
|      * @since  4.3.0 | ||||
|      */ | ||||
|     public $complete; | ||||
|  | ||||
|     /** | ||||
|      * Class Constructor | ||||
|      * | ||||
|      * @param   mixed  $state  The processing state for the indexer | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function __construct($state) | ||||
|     { | ||||
|         $params = ComponentHelper::getParams('com_finder'); | ||||
|  | ||||
|         if ($params->get('enable_logging', '0')) { | ||||
|             $options['format']    = '{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}'; | ||||
|             $options['text_file'] = 'indexer.php'; | ||||
|             Log::addLogger($options); | ||||
|         } | ||||
|  | ||||
|         // Check if we are dealing with an error. | ||||
|         if ($state instanceof \Exception) { | ||||
|             // Log the error | ||||
|             try { | ||||
|                 Log::add($state->getMessage(), Log::ERROR); | ||||
|             } catch (\RuntimeException $exception) { | ||||
|                 // Informational log only | ||||
|             } | ||||
|  | ||||
|             // Prepare the error response. | ||||
|             $this->error   = true; | ||||
|             $this->header  = Text::_('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->pluginState = $state->pluginState; | ||||
|  | ||||
|             $this->startTime = $state->startTime; | ||||
|             $this->endTime   = Factory::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  = Text::_('COM_FINDER_INDEXER_HEADER_COMPLETE'); | ||||
|                 $this->message = Text::_('COM_FINDER_INDEXER_MESSAGE_COMPLETE'); | ||||
|             } elseif ($this->totalItems <= 0) { | ||||
|                 $this->header  = Text::_('COM_FINDER_INDEXER_HEADER_OPTIMIZE'); | ||||
|                 $this->message = Text::_('COM_FINDER_INDEXER_MESSAGE_OPTIMIZE'); | ||||
|             } else { | ||||
|                 $this->header  = Text::_('COM_FINDER_INDEXER_HEADER_RUNNING'); | ||||
|                 $this->message = Text::_('COM_FINDER_INDEXER_MESSAGE_RUNNING'); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										530
									
								
								administrator/components/com_finder/src/Service/HTML/Filter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								administrator/components/com_finder/src/Service/HTML/Filter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,530 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Service\HTML; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Multilanguage; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Query; | ||||
| use Joomla\Database\DatabaseAwareTrait; | ||||
| use Joomla\Database\ParameterType; | ||||
| use Joomla\Filter\OutputFilter; | ||||
| use Joomla\Registry\Registry; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filter HTML Behaviors for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Filter | ||||
| { | ||||
|     use DatabaseAwareTrait; | ||||
|  | ||||
|     /** | ||||
|      * Method to generate filters using the slider widget and decorated | ||||
|      * with the FinderFilter JavaScript behaviors. | ||||
|      * | ||||
|      * @param   array  $options  An array of configuration options. [optional] | ||||
|      * | ||||
|      * @return  mixed  A rendered HTML widget on success, null otherwise. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function slider($options = []) | ||||
|     { | ||||
|         $db     = $this->getDatabase(); | ||||
|         $query  = $db->getQuery(true); | ||||
|         $user   = Factory::getUser(); | ||||
|         $groups = implode(',', $user->getAuthorisedViewLevels()); | ||||
|         $html   = ''; | ||||
|         $filter = null; | ||||
|  | ||||
|         // Get the configuration options. | ||||
|         $filterId    = $options['filter_id'] ?? null; | ||||
|         $activeNodes = \array_key_exists('selected_nodes', $options) ? $options['selected_nodes'] : []; | ||||
|         $classSuffix = \array_key_exists('class_suffix', $options) ? $options['class_suffix'] : ''; | ||||
|  | ||||
|         // Load the predefined filter if specified. | ||||
|         if (!empty($filterId)) { | ||||
|             $query->select('f.data, f.params') | ||||
|                 ->from($db->quoteName('#__finder_filters') . ' AS f') | ||||
|                 ->where('f.filter_id = ' . (int) $filterId); | ||||
|  | ||||
|             // Load the filter data. | ||||
|             $db->setQuery($query); | ||||
|  | ||||
|             try { | ||||
|                 $filter = $db->loadObject(); | ||||
|             } catch (\RuntimeException $e) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             // Initialize the filter parameters. | ||||
|             if ($filter) { | ||||
|                 $filter->params = new Registry($filter->params); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Build the query to get the branch data and the number of child nodes. | ||||
|         $query->clear() | ||||
|             ->select('t.*, count(c.id) AS children') | ||||
|             ->from($db->quoteName('#__finder_taxonomy') . ' AS t') | ||||
|             ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id') | ||||
|             ->where('t.parent_id = 1') | ||||
|             ->where('t.state = 1') | ||||
|             ->where('t.access IN (' . $groups . ')') | ||||
|             ->group('t.id, t.parent_id, t.state, t.access, t.title, c.parent_id') | ||||
|             ->order('t.lft, t.title'); | ||||
|  | ||||
|         // Limit the branch children to a predefined filter. | ||||
|         if ($filter) { | ||||
|             $query->where('c.id IN(' . $filter->data . ')'); | ||||
|         } | ||||
|  | ||||
|         // Load the branches. | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         try { | ||||
|             $branches = $db->loadObjectList('id'); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // Check that we have at least one branch. | ||||
|         if (\count($branches) === 0) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         $branch_keys = array_keys($branches); | ||||
|         $html .= HTMLHelper::_('bootstrap.startAccordion', 'accordion', ['active' => 'accordion-' . $branch_keys[0]]); | ||||
|  | ||||
|         // Load plugin language files. | ||||
|         LanguageHelper::loadPluginLanguage(); | ||||
|  | ||||
|         // Iterate through the branches and build the branch groups. | ||||
|         foreach ($branches as $bk => $bv) { | ||||
|             // If the multi-lang plugin is enabled then drop the language branch. | ||||
|             if ($bv->title === 'Language' && Multilanguage::isEnabled()) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Build the query to get the child nodes for this branch. | ||||
|             $query->clear() | ||||
|                 ->select('t.*') | ||||
|                 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') | ||||
|                 ->where('t.lft > ' . (int) $bv->lft) | ||||
|                 ->where('t.rgt < ' . (int) $bv->rgt) | ||||
|                 ->where('t.state = 1') | ||||
|                 ->where('t.access IN (' . $groups . ')') | ||||
|                 ->order('t.lft, t.title'); | ||||
|  | ||||
|             // Self-join to get the parent title. | ||||
|             $query->select('e.title AS parent_title') | ||||
|                 ->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id')); | ||||
|  | ||||
|             // Load the branches. | ||||
|             $db->setQuery($query); | ||||
|  | ||||
|             try { | ||||
|                 $nodes = $db->loadObjectList('id'); | ||||
|             } catch (\RuntimeException $e) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             // Translate node titles if possible. | ||||
|             $lang = Factory::getLanguage(); | ||||
|  | ||||
|             foreach ($nodes as $nv) { | ||||
|                 if (trim($nv->parent_title, '*') === 'Language') { | ||||
|                     $title = LanguageHelper::branchLanguageTitle($nv->title); | ||||
|                 } else { | ||||
|                     $key   = LanguageHelper::branchPlural($nv->title); | ||||
|                     $title = $lang->hasKey($key) ? Text::_($key) : $nv->title; | ||||
|                 } | ||||
|  | ||||
|                 $nv->title = $title; | ||||
|             } | ||||
|  | ||||
|             // Adding slides | ||||
|             $html .= HTMLHelper::_( | ||||
|                 'bootstrap.addSlide', | ||||
|                 'accordion', | ||||
|                 Text::sprintf( | ||||
|                     'COM_FINDER_FILTER_BRANCH_LABEL', | ||||
|                     Text::_(LanguageHelper::branchSingular($bv->title)) . ' - ' . \count($nodes) | ||||
|                 ), | ||||
|                 'accordion-' . $bk | ||||
|             ); | ||||
|  | ||||
|             // Populate the toggle button. | ||||
|             $html .= '<button class="btn btn-secondary js-filter" type="button" data-id="tax-' . $bk . '"><span class="icon-square" aria-hidden="true"></span> ' | ||||
|                 . Text::_('JGLOBAL_SELECTION_INVERT') . '</button><hr>'; | ||||
|  | ||||
|             // Populate the group with nodes. | ||||
|             foreach ($nodes as $nk => $nv) { | ||||
|                 // Determine if the node should be checked. | ||||
|                 $checked = \in_array($nk, $activeNodes) ? ' checked="checked"' : ''; | ||||
|  | ||||
|                 // Build a node. | ||||
|                 $html .= '<div class="form-check">'; | ||||
|                 $html .= '<label class="form-check-label">'; | ||||
|                 $html .= '<input type="checkbox" class="form-check-input selector filter-node' . $classSuffix | ||||
|                     . ' tax-' . $bk . '" value="' . $nk . '" name="t[]"' . $checked . '> ' . str_repeat('—', $nv->level - 2) . $nv->title; | ||||
|                 $html .= '</label>'; | ||||
|                 $html .= '</div>'; | ||||
|             } | ||||
|  | ||||
|             $html .= HTMLHelper::_('bootstrap.endSlide'); | ||||
|         } | ||||
|  | ||||
|         $html .= HTMLHelper::_('bootstrap.endAccordion'); | ||||
|  | ||||
|         return $html; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to generate filters using select box dropdown controls. | ||||
|      * | ||||
|      * @param   Query     $idxQuery  A Query object. | ||||
|      * @param   Registry  $options   An array of options. | ||||
|      * | ||||
|      * @return  string|null  A rendered HTML widget on success, null otherwise. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function select($idxQuery, $options) | ||||
|     { | ||||
|         $user   = Factory::getUser(); | ||||
|         $groups = implode(',', $user->getAuthorisedViewLevels()); | ||||
|         $filter = null; | ||||
|  | ||||
|         // Get the configuration options. | ||||
|         $classSuffix = $options->get('class_suffix', null); | ||||
|         $showDates   = $options->get('show_date_filters', false); | ||||
|  | ||||
|         // Try to load the results from cache. | ||||
|         $cache   = Factory::getCache('com_finder', ''); | ||||
|         $cacheId = 'filter_select_' . serialize([$idxQuery->filter, $options, $groups, Factory::getLanguage()->getTag()]); | ||||
|  | ||||
|         // Check the cached results. | ||||
|         if ($cache->contains($cacheId)) { | ||||
|             $branches = $cache->get($cacheId); | ||||
|         } else { | ||||
|             $db    = $this->getDatabase(); | ||||
|             $query = $db->getQuery(true); | ||||
|  | ||||
|             // Load the predefined filter if specified. | ||||
|             if (!empty($idxQuery->filter)) { | ||||
|                 $query->select('f.data, ' . $db->quoteName('f.params')) | ||||
|                     ->from($db->quoteName('#__finder_filters') . ' AS f') | ||||
|                     ->where('f.filter_id = ' . (int) $idxQuery->filter); | ||||
|  | ||||
|                 // Load the filter data. | ||||
|                 $db->setQuery($query); | ||||
|  | ||||
|                 try { | ||||
|                     $filter = $db->loadObject(); | ||||
|                 } catch (\RuntimeException $e) { | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
|                 // Initialize the filter parameters. | ||||
|                 if ($filter) { | ||||
|                     $filter->params = new Registry($filter->params); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Build the query to get the branch data and the number of child nodes. | ||||
|             $query->clear() | ||||
|                 ->select('t.*, count(c.id) AS children') | ||||
|                 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') | ||||
|                 ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id') | ||||
|                 ->where('t.parent_id = 1') | ||||
|                 ->where('t.state = 1') | ||||
|                 ->where('t.access IN (' . $groups . ')') | ||||
|                 ->where('c.state = 1') | ||||
|                 ->where('c.access IN (' . $groups . ')') | ||||
|                 ->group($db->quoteName('t.id')) | ||||
|                 ->group($db->quoteName('t.parent_id')) | ||||
|                 ->group('t.title, t.state, t.access, t.lft') | ||||
|                 ->order('t.lft, t.title'); | ||||
|  | ||||
|             // Limit the branch children to a predefined filter. | ||||
|             if (!empty($filter->data)) { | ||||
|                 $query->where('c.id IN(' . $filter->data . ')'); | ||||
|             } | ||||
|  | ||||
|             // Load the branches. | ||||
|             $db->setQuery($query); | ||||
|  | ||||
|             try { | ||||
|                 $branches = $db->loadObjectList('id'); | ||||
|             } catch (\RuntimeException $e) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             // Check that we have at least one branch. | ||||
|             if (\count($branches) === 0) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             // Iterate through the branches and build the branch groups. | ||||
|             foreach ($branches as $bk => $bv) { | ||||
|                 // If the multi-lang plugin is enabled then drop the language branch. | ||||
|                 if ($bv->title === 'Language' && Multilanguage::isEnabled()) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // Build the query to get the child nodes for this branch. | ||||
|                 $query->clear() | ||||
|                     ->select('t.*') | ||||
|                     ->from($db->quoteName('#__finder_taxonomy') . ' AS t') | ||||
|                     ->where('t.lft > :lft') | ||||
|                     ->where('t.rgt < :rgt') | ||||
|                     ->where('t.state = 1') | ||||
|                     ->whereIn('t.access', $user->getAuthorisedViewLevels()) | ||||
|                     ->order('t.level, t.parent_id, t.title') | ||||
|                     ->bind(':lft', $bv->lft, ParameterType::INTEGER) | ||||
|                     ->bind(':rgt', $bv->rgt, ParameterType::INTEGER); | ||||
|  | ||||
|                 // Apply multilanguage filter | ||||
|                 if (Multilanguage::isEnabled()) { | ||||
|                     $language = [Factory::getLanguage()->getTag(), '*']; | ||||
|                     $query->whereIn($db->quoteName('t.language'), $language, ParameterType::STRING); | ||||
|                 } | ||||
|  | ||||
|                 // Self-join to get the parent title. | ||||
|                 $query->select('e.title AS parent_title') | ||||
|                     ->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id')); | ||||
|  | ||||
|                 // Limit the nodes to a predefined filter. | ||||
|                 if (!empty($filter->data)) { | ||||
|                     $query->whereIn('t.id', explode(",", $filter->data)); | ||||
|                 } | ||||
|  | ||||
|                 // Load the branches. | ||||
|                 $db->setQuery($query); | ||||
|  | ||||
|                 try { | ||||
|                     $bv->nodes = $db->loadObjectList('id'); | ||||
|                 } catch (\RuntimeException $e) { | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
|                 // Translate branch nodes if possible. | ||||
|                 $language = Factory::getLanguage(); | ||||
|                 $root     = []; | ||||
|  | ||||
|                 foreach ($bv->nodes as $node_id => $node) { | ||||
|                     if (trim($node->parent_title, '*') === 'Language') { | ||||
|                         $title = LanguageHelper::branchLanguageTitle($node->title); | ||||
|                     } else { | ||||
|                         $key   = LanguageHelper::branchPlural($node->title); | ||||
|                         $title = $language->hasKey($key) ? Text::_($key) : $node->title; | ||||
|                     } | ||||
|  | ||||
|                     if ($node->level > 2) { | ||||
|                         $node->title = str_repeat('-', $node->level - 2) . $title; | ||||
|                     } else { | ||||
|                         $node->title = $title; | ||||
|                         $root[]      = $branches[$bk]->nodes[$node_id]; | ||||
|                     } | ||||
|  | ||||
|                     if ($node->parent_id && isset($branches[$bk]->nodes[$node->parent_id])) { | ||||
|                         if (!isset($branches[$bk]->nodes[$node->parent_id]->children)) { | ||||
|                             $branches[$bk]->nodes[$node->parent_id]->children = []; | ||||
|                         } | ||||
|                         $branches[$bk]->nodes[$node->parent_id]->children[] = $node; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 $branches[$bk]->nodes = $this->reduce($root); | ||||
|  | ||||
|                 // Add the Search All option to the branch. | ||||
|                 array_unshift($bv->nodes, ['id' => null, 'title' => Text::_('COM_FINDER_FILTER_SELECT_ALL_LABEL')]); | ||||
|             } | ||||
|  | ||||
|             // Store the data in cache. | ||||
|             $cache->store($branches, $cacheId); | ||||
|         } | ||||
|  | ||||
|         $html = ''; | ||||
|  | ||||
|         // Add the dates if enabled. | ||||
|         if ($showDates) { | ||||
|             $html .= HTMLHelper::_('filter.dates', $idxQuery, $options); | ||||
|         } | ||||
|  | ||||
|         $html .= '<div class="filter-branch' . $classSuffix . '">'; | ||||
|  | ||||
|         // Iterate through all branches and build code. | ||||
|         foreach ($branches as $bv) { | ||||
|             // If the multi-lang plugin is enabled then drop the language branch. | ||||
|             if ($bv->title === 'Language' && Multilanguage::isEnabled()) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $active = null; | ||||
|  | ||||
|             // Check if the branch is in the filter. | ||||
|             if (\array_key_exists($bv->title, $idxQuery->filters)) { | ||||
|                 // Get the request filters. | ||||
|                 $temp   = Factory::getApplication()->getInput()->request->get('t', [], 'array'); | ||||
|  | ||||
|                 // Search for active nodes in the branch and get the active node. | ||||
|                 $active = array_intersect($temp, $idxQuery->filters[$bv->title]); | ||||
|                 $active = \count($active) === 1 ? array_shift($active) : null; | ||||
|             } | ||||
|  | ||||
|             // Build a node. | ||||
|             $html .= '<div class="control-group">'; | ||||
|             $html .= '<div class="control-label">'; | ||||
|             $html .= '<label for="tax-' . OutputFilter::stringURLSafe($bv->title) . '">'; | ||||
|             $html .= Text::sprintf('COM_FINDER_FILTER_BRANCH_LABEL', Text::_(LanguageHelper::branchSingular($bv->title))); | ||||
|             $html .= '</label>'; | ||||
|             $html .= '</div>'; | ||||
|             $html .= '<div class="controls">'; | ||||
|             $html .= HTMLHelper::_( | ||||
|                 'select.genericlist', | ||||
|                 $bv->nodes, | ||||
|                 't[]', | ||||
|                 'class="form-select advancedSelect"', | ||||
|                 'id', | ||||
|                 'title', | ||||
|                 $active, | ||||
|                 'tax-' . OutputFilter::stringURLSafe($bv->title) | ||||
|             ); | ||||
|             $html .= '</div>'; | ||||
|             $html .= '</div>'; | ||||
|         } | ||||
|  | ||||
|         $html .= '</div>'; | ||||
|  | ||||
|         return $html; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to generate fields for filtering dates | ||||
|      * | ||||
|      * @param   Query     $idxQuery  A Query object. | ||||
|      * @param   Registry  $options   An array of options. | ||||
|      * | ||||
|      * @return  string  A rendered HTML widget. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function dates($idxQuery, $options) | ||||
|     { | ||||
|         $html = ''; | ||||
|  | ||||
|         // Get the configuration options. | ||||
|         $classSuffix = $options->get('class_suffix', null); | ||||
|         $loadMedia   = $options->get('load_media', true); | ||||
|         $showDates   = $options->get('show_date_filters', false); | ||||
|  | ||||
|         if (!empty($showDates)) { | ||||
|             // Build the date operators options. | ||||
|             $operators   = []; | ||||
|             $operators[] = HTMLHelper::_('select.option', 'before', Text::_('COM_FINDER_FILTER_DATE_BEFORE')); | ||||
|             $operators[] = HTMLHelper::_('select.option', 'exact', Text::_('COM_FINDER_FILTER_DATE_EXACTLY')); | ||||
|             $operators[] = HTMLHelper::_('select.option', 'after', Text::_('COM_FINDER_FILTER_DATE_AFTER')); | ||||
|  | ||||
|             // Load the CSS/JS resources. | ||||
|             if ($loadMedia) { | ||||
|                 /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ | ||||
|                 $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); | ||||
|                 $wa->useStyle('com_finder.dates'); | ||||
|             } | ||||
|  | ||||
|             // Open the widget. | ||||
|             $html .= '<ul id="finder-filter-select-dates">'; | ||||
|  | ||||
|             // Start date filter. | ||||
|             $attribs['class'] = 'input-medium'; | ||||
|             $html .= '<li class="filter-date float-start' . $classSuffix . '">'; | ||||
|             $html .= '<label for="filter_date1" class="hasTooltip" title ="' . Text::_('COM_FINDER_FILTER_DATE1_DESC') . '">'; | ||||
|             $html .= Text::_('COM_FINDER_FILTER_DATE1'); | ||||
|             $html .= '</label>'; | ||||
|             $html .= '<br>'; | ||||
|             $html .= '<label for="finder-filter-w1" class="visually-hidden">'; | ||||
|             $html .= Text::_('COM_FINDER_FILTER_DATE1_OPERATOR'); | ||||
|             $html .= '</label>'; | ||||
|             $html .= HTMLHelper::_( | ||||
|                 'select.genericlist', | ||||
|                 $operators, | ||||
|                 'w1', | ||||
|                 'class="inputbox filter-date-operator advancedSelect form-select w-auto mb-2"', | ||||
|                 'value', | ||||
|                 'text', | ||||
|                 $idxQuery->when1, | ||||
|                 'finder-filter-w1' | ||||
|             ); | ||||
|             $html .= HTMLHelper::_('calendar', $idxQuery->date1, 'd1', 'filter_date1', '%Y-%m-%d', $attribs); | ||||
|             $html .= '</li>'; | ||||
|  | ||||
|             // End date filter. | ||||
|             $html .= '<li class="filter-date float-end' . $classSuffix . '">'; | ||||
|             $html .= '<label for="filter_date2" class="hasTooltip" title ="' . Text::_('COM_FINDER_FILTER_DATE2_DESC') . '">'; | ||||
|             $html .= Text::_('COM_FINDER_FILTER_DATE2'); | ||||
|             $html .= '</label>'; | ||||
|             $html .= '<br>'; | ||||
|             $html .= '<label for="finder-filter-w2" class="visually-hidden">'; | ||||
|             $html .= Text::_('COM_FINDER_FILTER_DATE2_OPERATOR'); | ||||
|             $html .= '</label>'; | ||||
|             $html .= HTMLHelper::_( | ||||
|                 'select.genericlist', | ||||
|                 $operators, | ||||
|                 'w2', | ||||
|                 'class="inputbox filter-date-operator advancedSelect form-select w-auto mb-2"', | ||||
|                 'value', | ||||
|                 'text', | ||||
|                 $idxQuery->when2, | ||||
|                 'finder-filter-w2' | ||||
|             ); | ||||
|             $html .= HTMLHelper::_('calendar', $idxQuery->date2, 'd2', 'filter_date2', '%Y-%m-%d', $attribs); | ||||
|             $html .= '</li>'; | ||||
|  | ||||
|             // Close the widget. | ||||
|             $html .= '</ul>'; | ||||
|         } | ||||
|  | ||||
|         return $html; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to flatten a tree to a sorted array | ||||
|      * | ||||
|      * @param   \stdClass[]  $array | ||||
|      * | ||||
|      * @return  \stdClass[]  Flat array of all nodes of a tree with the children after each parent | ||||
|      * | ||||
|      * @since   5.1.0 | ||||
|      */ | ||||
|     private function reduce(array $array) | ||||
|     { | ||||
|         $return = []; | ||||
|  | ||||
|         foreach ($array as $item) { | ||||
|             $return[] = $item; | ||||
|             if (isset($item->children)) { | ||||
|                 $return = array_merge($return, $this->reduce($item->children)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										131
									
								
								administrator/components/com_finder/src/Service/HTML/Finder.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								administrator/components/com_finder/src/Service/HTML/Finder.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Service\HTML; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
| use Joomla\Database\DatabaseAwareTrait; | ||||
| use Joomla\Utilities\ArrayHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * HTML behavior class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Finder | ||||
| { | ||||
|     use DatabaseAwareTrait; | ||||
|  | ||||
|     /** | ||||
|      * Creates a list of types to filter on. | ||||
|      * | ||||
|      * @return  array  An array containing the types that can be selected. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function typeslist() | ||||
|     { | ||||
|         // Load the finder types. | ||||
|         $db    = $this->getDatabase(); | ||||
|         $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 = []; | ||||
|  | ||||
|         $lang = Factory::getLanguage(); | ||||
|  | ||||
|         foreach ($rows as $row) { | ||||
|             $key       = $lang->hasKey(LanguageHelper::branchPlural($row->text)) ? LanguageHelper::branchPlural($row->text) : $row->text; | ||||
|             $options[] = HTMLHelper::_('select.option', $row->value, Text::sprintf('COM_FINDER_ITEM_X_ONLY', Text::_($key))); | ||||
|         } | ||||
|  | ||||
|         return $options; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a list of maps. | ||||
|      * | ||||
|      * @return  array  An array containing the maps that can be selected. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function mapslist() | ||||
|     { | ||||
|         // Load the finder types. | ||||
|         $db    = $this->getDatabase(); | ||||
|         $query = $db->getQuery(true) | ||||
|             ->select($db->quoteName('title', 'text')) | ||||
|             ->select($db->quoteName('id', 'value')) | ||||
|             ->from($db->quoteName('#__finder_taxonomy')) | ||||
|             ->where($db->quoteName('parent_id') . ' = 1'); | ||||
|         $db->setQuery($query); | ||||
|  | ||||
|         try { | ||||
|             $branches = $db->loadObjectList(); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); | ||||
|         } | ||||
|  | ||||
|         // Translate. | ||||
|         $lang = Factory::getLanguage(); | ||||
|  | ||||
|         foreach ($branches as $branch) { | ||||
|             $key                    = LanguageHelper::branchPlural($branch->text); | ||||
|             $branch->translatedText = $lang->hasKey($key) ? Text::_($key) : $branch->text; | ||||
|         } | ||||
|  | ||||
|         // Order by title. | ||||
|         $branches = ArrayHelper::sortObjects($branches, 'translatedText', 1, true, true); | ||||
|  | ||||
|         // Compile the options. | ||||
|         $options   = []; | ||||
|         $options[] = HTMLHelper::_('select.option', '', Text::_('COM_FINDER_MAPS_SELECT_BRANCH')); | ||||
|  | ||||
|         // Convert the values to options. | ||||
|         foreach ($branches as $branch) { | ||||
|             $options[] = HTMLHelper::_('select.option', $branch->value, $branch->translatedText); | ||||
|         } | ||||
|  | ||||
|         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() | ||||
|     { | ||||
|         return [ | ||||
|             HTMLHelper::_('select.option', '1', Text::sprintf('COM_FINDER_ITEM_X_ONLY', Text::_('JPUBLISHED'))), | ||||
|             HTMLHelper::_('select.option', '0', Text::sprintf('COM_FINDER_ITEM_X_ONLY', Text::_('JUNPUBLISHED'))), | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										156
									
								
								administrator/components/com_finder/src/Service/HTML/Query.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								administrator/components/com_finder/src/Service/HTML/Query.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Service\HTML; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
| use Joomla\Component\Finder\Administrator\Indexer\Query as IndexerQuery; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Query HTML behavior class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class Query | ||||
| { | ||||
|     /** | ||||
|      * Method to get the explained (human-readable) search query. | ||||
|      * | ||||
|      * @param   IndexerQuery  $query  A IndexerQuery object to explain. | ||||
|      * | ||||
|      * @return  mixed  String if there is data to explain, null otherwise. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function explained(IndexerQuery $query) | ||||
|     { | ||||
|         $parts = []; | ||||
|  | ||||
|         // Process the required tokens. | ||||
|         foreach ($query->included as $token) { | ||||
|             if ($token->required && (!isset($token->derived) || $token->derived == false)) { | ||||
|                 $parts[] = '<span class="query-required">' . Text::sprintf('COM_FINDER_QUERY_TOKEN_REQUIRED', $token->term) . '</span>'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Process the optional tokens. | ||||
|         foreach ($query->included as $token) { | ||||
|             if (!$token->required && (!isset($token->derived) || $token->derived == false)) { | ||||
|                 $parts[] = '<span class="query-optional">' . Text::sprintf('COM_FINDER_QUERY_TOKEN_OPTIONAL', $token->term) . '</span>'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Process the excluded tokens. | ||||
|         foreach ($query->excluded as $token) { | ||||
|             if (!isset($token->derived) || $token->derived === false) { | ||||
|                 $parts[] = '<span class="query-excluded">' . Text::sprintf('COM_FINDER_QUERY_TOKEN_EXCLUDED', $token->term) . '</span>'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Process the start date. | ||||
|         if ($query->date1) { | ||||
|             $date          = Factory::getDate($query->date1)->format(Text::_('DATE_FORMAT_LC')); | ||||
|             $datecondition = Text::_('COM_FINDER_QUERY_DATE_CONDITION_' . strtoupper($query->when1)); | ||||
|             $parts[]       = '<span class="query-start-date">' . Text::sprintf('COM_FINDER_QUERY_START_DATE', $datecondition, $date) . '</span>'; | ||||
|         } | ||||
|  | ||||
|         // Process the end date. | ||||
|         if ($query->date2) { | ||||
|             $date          = Factory::getDate($query->date2)->format(Text::_('DATE_FORMAT_LC')); | ||||
|             $datecondition = Text::_('COM_FINDER_QUERY_DATE_CONDITION_' . strtoupper($query->when2)); | ||||
|             $parts[]       = '<span class="query-end-date">' . Text::sprintf('COM_FINDER_QUERY_END_DATE', $datecondition, $date) . '</span>'; | ||||
|         } | ||||
|  | ||||
|         // Process the taxonomy filters. | ||||
|         if (!empty($query->filters)) { | ||||
|             // Get the filters in the request. | ||||
|             $t = Factory::getApplication()->getInput()->request->get('t', [], 'array'); | ||||
|  | ||||
|             // Process the taxonomy branches. | ||||
|             foreach ($query->filters as $branch => $nodes) { | ||||
|                 // Process the taxonomy nodes. | ||||
|                 $lang = Factory::getLanguage(); | ||||
|  | ||||
|                 foreach ($nodes as $title => $id) { | ||||
|                     // Translate the title for Types | ||||
|                     $key = LanguageHelper::branchPlural($title); | ||||
|  | ||||
|                     if ($lang->hasKey($key)) { | ||||
|                         $title = Text::_($key); | ||||
|                     } | ||||
|  | ||||
|                     // Don't include the node if it is not in the request. | ||||
|                     if (!\in_array($id, $t)) { | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     // Add the node to the explanation. | ||||
|                     $parts[] = '<span class="query-taxonomy">' | ||||
|                         . Text::sprintf('COM_FINDER_QUERY_TAXONOMY_NODE', $title, Text::_(LanguageHelper::branchSingular($branch))) | ||||
|                         . '</span>'; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Build the interpreted query. | ||||
|         return \count($parts) ? implode(Text::_('COM_FINDER_QUERY_TOKEN_GLUE'), $parts) : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to get the suggested search query. | ||||
|      * | ||||
|      * @param   IndexerQuery  $query  A IndexerQuery object. | ||||
|      * | ||||
|      * @return  mixed  String if there is a suggestion, false otherwise. | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public static function suggested(IndexerQuery $query) | ||||
|     { | ||||
|         $suggested = false; | ||||
|  | ||||
|         // Check if the query input is empty. | ||||
|         if (empty($query->input)) { | ||||
|             return $suggested; | ||||
|         } | ||||
|  | ||||
|         // Check if there were any ignored or included keywords. | ||||
|         if (\count($query->ignored) || \count($query->included)) { | ||||
|             $suggested = $query->input; | ||||
|  | ||||
|             // Replace the ignored keyword suggestions. | ||||
|             foreach (array_reverse($query->ignored) as $token) { | ||||
|                 if (isset($token->suggestion)) { | ||||
|                     $suggested = str_ireplace($token->term, $token->suggestion, $suggested); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Replace the included keyword suggestions. | ||||
|             foreach (array_reverse($query->included) as $token) { | ||||
|                 if (isset($token->suggestion)) { | ||||
|                     $suggested = str_ireplace($token->term, $token->suggestion, $suggested); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Check if we made any changes. | ||||
|             if ($suggested == $query->input) { | ||||
|                 $suggested = false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $suggested; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										173
									
								
								administrator/components/com_finder/src/Table/FilterTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								administrator/components/com_finder/src/Table/FilterTable.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Table; | ||||
|  | ||||
| use Joomla\CMS\Application\ApplicationHelper; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\Table\Table; | ||||
| use Joomla\CMS\User\CurrentUserInterface; | ||||
| use Joomla\CMS\User\CurrentUserTrait; | ||||
| use Joomla\Database\DatabaseDriver; | ||||
| use Joomla\Event\DispatcherInterface; | ||||
| use Joomla\Registry\Registry; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filter table class for the Finder package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class FilterTable extends Table implements CurrentUserInterface | ||||
| { | ||||
|     use CurrentUserTrait; | ||||
|  | ||||
|     /** | ||||
|      * Indicates that columns fully support the NULL value in the database | ||||
|      * | ||||
|      * @var    boolean | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $_supportNullValue = true; | ||||
|  | ||||
|     /** | ||||
|      * Ensure the params are json encoded in the bind method | ||||
|      * | ||||
|      * @var    array | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $_jsonEncode = ['params']; | ||||
|  | ||||
|     /** | ||||
|      * Constructor | ||||
|      * | ||||
|      * @param   DatabaseDriver        $db          Database connector object | ||||
|      * @param   ?DispatcherInterface  $dispatcher  Event dispatcher for this table | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null) | ||||
|     { | ||||
|         parent::__construct('#__finder_filters', 'filter_id', $db, $dispatcher); | ||||
|  | ||||
|         $this->setColumnAlias('published', 'state'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to perform sanity checks on the \Joomla\CMS\Table\Table 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() | ||||
|     { | ||||
|         try { | ||||
|             parent::check(); | ||||
|         } catch (\Exception $e) { | ||||
|             $this->setError($e->getMessage()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (trim($this->alias) === '') { | ||||
|             $this->alias = $this->title; | ||||
|         } | ||||
|  | ||||
|         $this->alias = ApplicationHelper::stringURLSafe($this->alias); | ||||
|  | ||||
|         if (trim(str_replace('-', '', $this->alias)) === '') { | ||||
|             $this->alias = Factory::getDate()->format('Y-m-d-H-i-s'); | ||||
|         } | ||||
|  | ||||
|         $params = new Registry($this->params); | ||||
|  | ||||
|         $d1 = $params->get('d1', ''); | ||||
|         $d2 = $params->get('d2', ''); | ||||
|  | ||||
|         // Check the end date is not earlier than the start date. | ||||
|         if (!empty($d1) && !empty($d2) && $d2 < $d1) { | ||||
|             // Swap the dates. | ||||
|             $params->set('d1', $d2); | ||||
|             $params->set('d2', $d1); | ||||
|             $this->params = (string) $params; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to store a row in the database from the \Joomla\CMS\Table\Table 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 | ||||
|      * \Joomla\CMS\Table\Table 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 = true) | ||||
|     { | ||||
|         $date   = Factory::getDate()->toSql(); | ||||
|         $userId = $this->getCurrentUser()->id; | ||||
|  | ||||
|         // Set created date if not set. | ||||
|         if (!(int) $this->created) { | ||||
|             $this->created = $date; | ||||
|         } | ||||
|  | ||||
|         if ($this->filter_id) { | ||||
|             // Existing item | ||||
|             $this->modified_by = $userId; | ||||
|             $this->modified    = $date; | ||||
|         } else { | ||||
|             if (empty($this->created_by)) { | ||||
|                 $this->created_by = $userId; | ||||
|             } | ||||
|  | ||||
|             if (!(int) $this->modified) { | ||||
|                 $this->modified = $this->created; | ||||
|             } | ||||
|  | ||||
|             if (empty($this->modified_by)) { | ||||
|                 $this->modified_by = $this->created_by; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (\is_array($this->data)) { | ||||
|             $this->map_count = \count($this->data); | ||||
|             $this->data      = implode(',', $this->data); | ||||
|         } else { | ||||
|             $this->map_count = 0; | ||||
|             $this->data      = implode(',', []); | ||||
|         } | ||||
|  | ||||
|         // Verify that the alias is unique | ||||
|         $table = new self($this->getDbo(), $this->getDispatcher()); | ||||
|  | ||||
|         if ($table->load(['alias' => $this->alias]) && ($table->filter_id != $this->filter_id || $this->filter_id == 0)) { | ||||
|             $this->setError(Text::_('COM_FINDER_FILTER_ERROR_UNIQUE_ALIAS')); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return parent::store($updateNulls); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										63
									
								
								administrator/components/com_finder/src/Table/LinkTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								administrator/components/com_finder/src/Table/LinkTable.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Table; | ||||
|  | ||||
| use Joomla\CMS\Table\Table; | ||||
| use Joomla\Database\DatabaseDriver; | ||||
| use Joomla\Event\DispatcherInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Link table class for the Finder package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class LinkTable extends Table | ||||
| { | ||||
|     /** | ||||
|      * Indicates that columns fully support the NULL value in the database | ||||
|      * | ||||
|      * @var    boolean | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $_supportNullValue = true; | ||||
|  | ||||
|     /** | ||||
|      * Constructor | ||||
|      * | ||||
|      * @param   DatabaseDriver        $db          Database connector object | ||||
|      * @param   ?DispatcherInterface  $dispatcher  Event dispatcher for this table | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null) | ||||
|     { | ||||
|         parent::__construct('#__finder_links', 'link_id', $db, $dispatcher); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Overloaded store function | ||||
|      * | ||||
|      * @param   boolean  $updateNulls  True to update fields even if they are null. | ||||
|      * | ||||
|      * @return  mixed  False on failure, positive integer on success. | ||||
|      * | ||||
|      * @see     Table::store() | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function store($updateNulls = true) | ||||
|     { | ||||
|         return parent::store($updateNulls); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										80
									
								
								administrator/components/com_finder/src/Table/MapTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								administrator/components/com_finder/src/Table/MapTable.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\Table; | ||||
|  | ||||
| use Joomla\CMS\Application\ApplicationHelper; | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\Table\Nested; | ||||
| use Joomla\Database\DatabaseDriver; | ||||
| use Joomla\Event\DispatcherInterface; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Map table class for the Finder package. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class MapTable extends Nested | ||||
| { | ||||
|     /** | ||||
|      * Constructor | ||||
|      * | ||||
|      * @param   DatabaseDriver        $db          Database connector object | ||||
|      * @param   ?DispatcherInterface  $dispatcher  Event dispatcher for this table | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null) | ||||
|     { | ||||
|         parent::__construct('#__finder_taxonomy', 'id', $db, $dispatcher); | ||||
|  | ||||
|         $this->setColumnAlias('published', 'state'); | ||||
|         $this->access = (int) Factory::getApplication()->get('access'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Override check function | ||||
|      * | ||||
|      * @return  boolean | ||||
|      * | ||||
|      * @see     Table::check() | ||||
|      * @since   4.0.0 | ||||
|      */ | ||||
|     public function check() | ||||
|     { | ||||
|         try { | ||||
|             parent::check(); | ||||
|         } catch (\Exception $e) { | ||||
|             $this->setError($e->getMessage()); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Check for a title. | ||||
|         if (trim($this->title) == '') { | ||||
|             $this->setError(Text::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_CATEGORY')); | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $this->alias = ApplicationHelper::stringURLSafe($this->title, $this->language); | ||||
|  | ||||
|         if (trim($this->alias) == '') { | ||||
|             $this->alias = md5(serialize($this->getProperties())); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										186
									
								
								administrator/components/com_finder/src/View/Filter/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								administrator/components/com_finder/src/View/Filter/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,186 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Filter; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Helper\ContentHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Toolbar\Toolbar; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filter view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * The filter object | ||||
|      * | ||||
|      * @var    \Joomla\Component\Finder\Administrator\Table\FilterTable | ||||
|      * | ||||
|      * @since  3.6.2 | ||||
|      */ | ||||
|     protected $filter; | ||||
|  | ||||
|     /** | ||||
|      * The Form object | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Form\Form | ||||
|      * | ||||
|      * @since  3.6.2 | ||||
|      */ | ||||
|     protected $form; | ||||
|  | ||||
|     /** | ||||
|      * The active item | ||||
|      * | ||||
|      * @var    \stdClass | ||||
|      * | ||||
|      * @since  3.6.2 | ||||
|      */ | ||||
|     protected $item; | ||||
|  | ||||
|     /** | ||||
|      * The model state | ||||
|      * | ||||
|      * @var    \Joomla\Registry\Registry | ||||
|      * | ||||
|      * @since  3.6.2 | ||||
|      */ | ||||
|     protected $state; | ||||
|  | ||||
|     /** | ||||
|      * The total indexed items | ||||
|      * | ||||
|      * @var    integer | ||||
|      * | ||||
|      * @since  3.8.0 | ||||
|      */ | ||||
|     protected $total; | ||||
|  | ||||
|     /** | ||||
|      * Array of fieldsets not to display | ||||
|      * | ||||
|      * @var    string[] | ||||
|      * | ||||
|      * @since  5.2.0 | ||||
|      */ | ||||
|     public $ignore_fieldsets = []; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @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'); | ||||
|         $this->total  = $this->get('Total'); | ||||
|  | ||||
|         // Check for errors. | ||||
|         if (\count($errors = $this->get('Errors'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         // Configure the toolbar. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         Factory::getApplication()->getInput()->set('hidemainmenu', true); | ||||
|  | ||||
|         $isNew      = ($this->item->filter_id == 0); | ||||
|         $checkedOut = !(\is_null($this->item->checked_out) || $this->item->checked_out == $this->getCurrentUser()->id); | ||||
|         $canDo      = ContentHelper::getActions('com_finder'); | ||||
|         $toolbar    = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         // Configure the toolbar. | ||||
|         ToolbarHelper::title( | ||||
|             $isNew ? Text::_('COM_FINDER_FILTER_NEW_TOOLBAR_TITLE') : Text::_('COM_FINDER_FILTER_EDIT_TOOLBAR_TITLE'), | ||||
|             'zoom-in finder' | ||||
|         ); | ||||
|  | ||||
|         // Set the actions for new and existing records. | ||||
|         if ($isNew) { | ||||
|             // For new records, check the create permission. | ||||
|             if ($canDo->get('core.create')) { | ||||
|                 $toolbar->apply('filter.apply'); | ||||
|                 $saveGroup = $toolbar->dropdownButton('save-group'); | ||||
|                 $saveGroup->configure( | ||||
|                     function (Toolbar $childBar) { | ||||
|                         $childBar->save('filter.save'); | ||||
|                         $childBar->save2new('filter.save2new'); | ||||
|                     } | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             $toolbar->cancel('filter.cancel', 'JTOOLBAR_CANCEL'); | ||||
|         } else { | ||||
|             // Can't save the record if it's checked out. | ||||
|             // Since it's an existing record, check the edit permission. | ||||
|             if (!$checkedOut && $canDo->get('core.edit')) { | ||||
|                 $toolbar->apply('filter.apply'); | ||||
|             } | ||||
|  | ||||
|             $saveGroup = $toolbar->dropdownButton('save-group'); | ||||
|             $saveGroup->configure( | ||||
|                 function (Toolbar $childBar) use ($checkedOut, $canDo) { | ||||
|                     // Can't save the record if it's checked out. | ||||
|                     // Since it's an existing record, check the edit permission. | ||||
|                     if (!$checkedOut && $canDo->get('core.edit')) { | ||||
|                         $childBar->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')) { | ||||
|                             $childBar->save2new('filter.save2new'); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     // If an existing item, can save as a copy | ||||
|                     if ($canDo->get('core.create')) { | ||||
|                         $childBar->save2copy('filter.save2copy'); | ||||
|                     } | ||||
|                 } | ||||
|             ); | ||||
|  | ||||
|             $toolbar->cancel('filter.cancel'); | ||||
|         } | ||||
|  | ||||
|         $toolbar->divider(); | ||||
|         $toolbar->help('Smart_Search:_New_or_Edit_Filter'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,183 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Filters; | ||||
|  | ||||
| use Joomla\CMS\Helper\ContentHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Toolbar\Button\DropdownButton; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Filters view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * An array of items | ||||
|      * | ||||
|      * @var    array | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $items; | ||||
|  | ||||
|     /** | ||||
|      * The pagination object | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Pagination\Pagination | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $pagination; | ||||
|  | ||||
|     /** | ||||
|      * The model state | ||||
|      * | ||||
|      * @var   \Joomla\Registry\Registry | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $state; | ||||
|  | ||||
|     /** | ||||
|      * The total number of items | ||||
|      * | ||||
|      * @var  integer | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $total; | ||||
|  | ||||
|     /** | ||||
|      * Form object for search filters | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Form\Form | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $filterForm; | ||||
|  | ||||
|     /** | ||||
|      * The active search filters | ||||
|      * | ||||
|      * @var    array | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $activeFilters; | ||||
|  | ||||
|     /** | ||||
|      * @var    boolean | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     private $isEmptyState = false; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @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'); | ||||
|         $this->filterForm    = $this->get('FilterForm'); | ||||
|         $this->activeFilters = $this->get('ActiveFilters'); | ||||
|  | ||||
|         if (\count($this->items) === 0 && $this->isEmptyState = $this->get('IsEmptyState')) { | ||||
|             $this->setLayout('emptystate'); | ||||
|         } | ||||
|  | ||||
|         // Check for errors. | ||||
|         if (\count($errors = $this->get('Errors'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         // Configure the toolbar. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         $canDo   = ContentHelper::getActions('com_finder'); | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_FILTERS_TOOLBAR_TITLE'), 'search-plus finder'); | ||||
|  | ||||
|         if ($canDo->get('core.create')) { | ||||
|             $toolbar->addNew('filter.add'); | ||||
|             $toolbar->divider(); | ||||
|         } | ||||
|  | ||||
|         if ($this->isEmptyState === false) { | ||||
|             if ($canDo->get('core.edit.state')) { | ||||
|                 /** @var DropdownButton $dropdown */ | ||||
|                 $dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS') | ||||
|                     ->toggleSplit(false) | ||||
|                     ->icon('icon-ellipsis-h') | ||||
|                     ->buttonClass('btn btn-action') | ||||
|                     ->listCheck(true); | ||||
|  | ||||
|                 $childBar = $dropdown->getChildToolbar(); | ||||
|  | ||||
|                 $childBar->publish('filters.publish')->listCheck(true); | ||||
|                 $childBar->unpublish('filters.unpublish')->listCheck(true); | ||||
|                 $childBar->checkin('filters.checkin')->listCheck(true); | ||||
|             } | ||||
|  | ||||
|             if ($canDo->get('core.delete')) { | ||||
|                 $toolbar->standardButton('delete', 'JTOOLBAR_DELETE', 'filters.delete') | ||||
|                     ->listCheck(true); | ||||
|                 $toolbar->divider(); | ||||
|             } | ||||
|  | ||||
|             $toolbar->divider(); | ||||
|             $toolbar->popupButton('bars', 'COM_FINDER_STATISTICS') | ||||
|                 ->url('index.php?option=com_finder&view=statistics&tmpl=component') | ||||
|                 ->iframeWidth(550) | ||||
|                 ->iframeHeight(350) | ||||
|                 ->title(Text::_('COM_FINDER_STATISTICS_TITLE')) | ||||
|                 ->icon('icon-bars'); | ||||
|             $toolbar->divider(); | ||||
|         } | ||||
|  | ||||
|         if ($canDo->get('core.admin') || $canDo->get('core.options')) { | ||||
|             $toolbar->preferences('com_finder'); | ||||
|         } | ||||
|  | ||||
|         $toolbar->help('Smart_Search:_Search_Filters'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										263
									
								
								administrator/components/com_finder/src/View/Index/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								administrator/components/com_finder/src/View/Index/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,263 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Index; | ||||
|  | ||||
| use Joomla\CMS\Helper\ContentHelper; | ||||
| use Joomla\CMS\Language\Multilanguage; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Plugin\PluginHelper; | ||||
| use Joomla\CMS\Toolbar\Button\DropdownButton; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
| use Joomla\Component\Finder\Administrator\Helper\FinderHelper; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Index view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * An array of items | ||||
|      * | ||||
|      * @var  array | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $items; | ||||
|  | ||||
|     /** | ||||
|      * The pagination object | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Pagination\Pagination | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $pagination; | ||||
|  | ||||
|     /** | ||||
|      * The state of core Smart Search plugins | ||||
|      * | ||||
|      * @var  array | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $pluginState; | ||||
|  | ||||
|     /** | ||||
|      * The id of the content - finder plugin in mysql | ||||
|      * | ||||
|      * @var    integer | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $finderPluginId = 0; | ||||
|  | ||||
|     /** | ||||
|      * The model state | ||||
|      * | ||||
|      * @var    mixed | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $state; | ||||
|  | ||||
|     /** | ||||
|      * The total number of items | ||||
|      * | ||||
|      * @var    integer | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $total; | ||||
|  | ||||
|     /** | ||||
|      * Form object for search filters | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Form\Form | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $filterForm; | ||||
|  | ||||
|     /** | ||||
|      * The active search filters | ||||
|      * | ||||
|      * @var    array | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $activeFilters; | ||||
|  | ||||
|     /** | ||||
|      * @var mixed | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     private $isEmptyState = false; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function display($tpl = null) | ||||
|     { | ||||
|         // Load plugin language files. | ||||
|         LanguageHelper::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'); | ||||
|         $this->filterForm    = $this->get('FilterForm'); | ||||
|         $this->activeFilters = $this->get('ActiveFilters'); | ||||
|  | ||||
|         if ($this->get('TotalIndexed') === 0 && $this->isEmptyState = $this->get('IsEmptyState')) { | ||||
|             $this->setLayout('emptystate'); | ||||
|         } | ||||
|  | ||||
|         // We do not need to filter by language when multilingual is disabled | ||||
|         if (!Multilanguage::isEnabled()) { | ||||
|             unset($this->activeFilters['language']); | ||||
|             $this->filterForm->removeField('language', 'filter'); | ||||
|         } | ||||
|  | ||||
|         // Check for errors. | ||||
|         if (\count($errors = $this->get('Errors'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         // Check that the content - finder plugin is enabled | ||||
|         if (!PluginHelper::isEnabled('content', 'finder')) { | ||||
|             $this->finderPluginId = FinderHelper::getFinderPluginId(); | ||||
|         } | ||||
|  | ||||
|         // Configure the toolbar. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         $canDo   = ContentHelper::getActions('com_finder'); | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_INDEX_TOOLBAR_TITLE'), 'search-plus finder'); | ||||
|  | ||||
|         if (JDEBUG) { | ||||
|             $dropdown = $toolbar->dropdownButton('indexing-group'); | ||||
|             $dropdown->text('COM_FINDER_INDEX') | ||||
|                 ->toggleSplit(false) | ||||
|                 ->icon('icon-archive') | ||||
|                 ->buttonClass('btn btn-action'); | ||||
|  | ||||
|             $childBar = $dropdown->getChildToolbar(); | ||||
|  | ||||
|             $childBar->popupButton('index', 'COM_FINDER_INDEX') | ||||
|                 ->popupType('iframe') | ||||
|                 ->textHeader(Text::_('COM_FINDER_HEADING_INDEXER')) | ||||
|                 ->url('index.php?option=com_finder&view=indexer&tmpl=component') | ||||
|                 ->modalWidth('800px') | ||||
|                 ->modalHeight('400px') | ||||
|                 ->icon('icon-archive') | ||||
|                 ->title(Text::_('COM_FINDER_HEADING_INDEXER')); | ||||
|  | ||||
|             $childBar->linkButton('indexdebug', 'COM_FINDER_INDEX_TOOLBAR_INDEX_DEBUGGING') | ||||
|                 ->url('index.php?option=com_finder&view=indexer&layout=debug') | ||||
|                 ->icon('icon-tools'); | ||||
|         } else { | ||||
|             $toolbar->popupButton('index', 'COM_FINDER_INDEX') | ||||
|                 ->popupType('iframe') | ||||
|                 ->textHeader(Text::_('COM_FINDER_HEADING_INDEXER')) | ||||
|                 ->url('index.php?option=com_finder&view=indexer&tmpl=component') | ||||
|                 ->modalWidth('800px') | ||||
|                 ->modalHeight('400px') | ||||
|                 ->icon('icon-archive') | ||||
|                 ->title(Text::_('COM_FINDER_HEADING_INDEXER')); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         if (!$this->isEmptyState) { | ||||
|             if ($canDo->get('core.edit.state')) { | ||||
|                 $dropdown = $toolbar->dropdownButton('status-group') | ||||
|                     ->text('JTOOLBAR_CHANGE_STATUS') | ||||
|                     ->toggleSplit(false) | ||||
|                     ->icon('icon-ellipsis-h') | ||||
|                     ->buttonClass('btn btn-action') | ||||
|                     ->listCheck(true); | ||||
|  | ||||
|                 $childBar = $dropdown->getChildToolbar(); | ||||
|  | ||||
|                 $childBar->publish('index.publish')->listCheck(true); | ||||
|                 $childBar->unpublish('index.unpublish')->listCheck(true); | ||||
|             } | ||||
|  | ||||
|             if ($canDo->get('core.delete')) { | ||||
|                 $toolbar->confirmButton('delete', 'JTOOLBAR_DELETE', 'index.delete') | ||||
|                     ->message('COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT') | ||||
|                     ->icon('icon-delete') | ||||
|                     ->listCheck(true); | ||||
|                 $toolbar->divider(); | ||||
|             } | ||||
|  | ||||
|             if ($canDo->get('core.edit.state')) { | ||||
|                 /** @var DropdownButton $dropdown */ | ||||
|                 $dropdown = $toolbar->dropdownButton('maintenance-group', 'COM_FINDER_INDEX_TOOLBAR_MAINTENANCE') | ||||
|                     ->toggleSplit(false) | ||||
|                     ->icon('icon-wrench') | ||||
|                     ->buttonClass('btn btn-action'); | ||||
|  | ||||
|                 $childBar = $dropdown->getChildToolbar(); | ||||
|  | ||||
|                 $childBar->standardButton('cog', 'COM_FINDER_INDEX_TOOLBAR_OPTIMISE', 'index.optimise'); | ||||
|                 $childBar->confirmButton('index-purge', 'COM_FINDER_INDEX_TOOLBAR_PURGE', 'index.purge') | ||||
|                     ->message('COM_FINDER_INDEX_CONFIRM_PURGE_PROMPT') | ||||
|                     ->icon('icon-trash'); | ||||
|             } | ||||
|  | ||||
|             $toolbar->popupButton('statistics', 'COM_FINDER_STATISTICS') | ||||
|                 ->popupType('iframe') | ||||
|                 ->textHeader(Text::_('COM_FINDER_STATISTICS_TITLE')) | ||||
|                 ->url('index.php?option=com_finder&view=statistics&tmpl=component') | ||||
|                 ->modalWidth('800px') | ||||
|                 ->modalHeight('500px') | ||||
|                 ->title(Text::_('COM_FINDER_STATISTICS_TITLE')) | ||||
|                 ->icon('icon-bars'); | ||||
|         } | ||||
|  | ||||
|         if ($canDo->get('core.admin') || $canDo->get('core.options')) { | ||||
|             $toolbar->preferences('com_finder'); | ||||
|         } | ||||
|  | ||||
|         $toolbar->help('Smart_Search:_Indexed_Content'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,79 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Indexer; | ||||
|  | ||||
| use Joomla\CMS\Form\Form; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Router\Route; | ||||
| use Joomla\CMS\Toolbar\Toolbar; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Indexer view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * @var   Form  $form | ||||
|      * | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     public $form; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function display($tpl = null) | ||||
|     { | ||||
|         if ($this->getLayout() == 'debug') { | ||||
|             $this->form = $this->get('Form'); | ||||
|             $this->addToolbar(); | ||||
|         } | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         /** @var Toolbar $toolbar */ | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_INDEXER_TOOLBAR_TITLE'), 'search-plus finder'); | ||||
|  | ||||
|         $toolbar->linkButton('back', 'JTOOLBAR_BACK') | ||||
|             ->icon('icon-arrow-' . ($this->getLanguage()->isRtl() ? 'right' : 'left')) | ||||
|             ->url(Route::_('index.php?option=com_finder&view=index')); | ||||
|  | ||||
|         $toolbar->standardButton('index', 'COM_FINDER_INDEX') | ||||
|             ->icon('icon-play') | ||||
|             ->onclick('Joomla.debugIndexing();'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,92 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Item; | ||||
|  | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Router\Route; | ||||
| use Joomla\CMS\Toolbar\Toolbar; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
|  | ||||
| /** | ||||
|  * Index view class for Finder. | ||||
|  * | ||||
|  * @since  5.0.0 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * The indexed item | ||||
|      * | ||||
|      * @var  object | ||||
|      * | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $item; | ||||
|  | ||||
|     /** | ||||
|      * The associated terms | ||||
|      * | ||||
|      * @var  object[] | ||||
|      * | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $terms; | ||||
|  | ||||
|     /** | ||||
|      * The associated taxonomies | ||||
|      * | ||||
|      * @var  object[] | ||||
|      * | ||||
|      * @since  5.0.0 | ||||
|      */ | ||||
|     protected $taxonomies; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     public function display($tpl = null) | ||||
|     { | ||||
|         $this->item       = $this->get('Item'); | ||||
|         $this->terms      = $this->get('Terms'); | ||||
|         $this->taxonomies = $this->get('Taxonomies'); | ||||
|  | ||||
|         // Configure the toolbar. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   5.0.0 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         /** @var Toolbar $toolbar */ | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_INDEX_TOOLBAR_TITLE'), 'search-plus finder'); | ||||
|  | ||||
|         $toolbar->linkButton('back', 'JTOOLBAR_BACK') | ||||
|             ->icon('icon-arrow-' . ($this->getLanguage()->isRtl() ? 'right' : 'left')) | ||||
|             ->url(Route::_('index.php?option=com_finder&view=index')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										183
									
								
								administrator/components/com_finder/src/View/Maps/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								administrator/components/com_finder/src/View/Maps/HtmlView.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Maps; | ||||
|  | ||||
| use Joomla\CMS\Helper\ContentHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Toolbar\Button\DropdownButton; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
| use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Groups view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * An array of items | ||||
|      * | ||||
|      * @var  array | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $items; | ||||
|  | ||||
|     /** | ||||
|      * The pagination object | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Pagination\Pagination | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $pagination; | ||||
|  | ||||
|     /** | ||||
|      * The model state | ||||
|      * | ||||
|      * @var   \Joomla\Registry\Registry | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $state; | ||||
|  | ||||
|     /** | ||||
|      * The total number of items | ||||
|      * | ||||
|      * @var  integer | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $total; | ||||
|  | ||||
|     /** | ||||
|      * Form object for search filters | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Form\Form | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $filterForm; | ||||
|  | ||||
|     /** | ||||
|      * The active search filters | ||||
|      * | ||||
|      * @var    array | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $activeFilters; | ||||
|  | ||||
|     /** | ||||
|      * @var   boolean | ||||
|      * | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     private $isEmptyState = false; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     public function display($tpl = null) | ||||
|     { | ||||
|         // Load plugin language files. | ||||
|         LanguageHelper::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'); | ||||
|         $this->filterForm    = $this->get('FilterForm'); | ||||
|         $this->activeFilters = $this->get('ActiveFilters'); | ||||
|  | ||||
|         if ($this->total === 0 && $this->isEmptyState = $this->get('isEmptyState')) { | ||||
|             $this->setLayout('emptystate'); | ||||
|         } | ||||
|  | ||||
|         // Check for errors. | ||||
|         if (\count($errors = $this->get('Errors'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         // Prepare the view. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method to configure the toolbar for this view. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   2.5 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         $canDo   = ContentHelper::getActions('com_finder'); | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_MAPS_TOOLBAR_TITLE'), 'search-plus finder'); | ||||
|  | ||||
|         if (!$this->isEmptyState) { | ||||
|             if ($canDo->get('core.edit.state')) { | ||||
|                 /** @var DropdownButton $dropdown */ | ||||
|                 $dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS') | ||||
|                     ->toggleSplit(false) | ||||
|                     ->icon('icon-ellipsis-h') | ||||
|                     ->buttonClass('btn btn-action') | ||||
|                     ->listCheck(true); | ||||
|  | ||||
|                 $childBar = $dropdown->getChildToolbar(); | ||||
|  | ||||
|                 $childBar->publish('maps.publish')->listCheck(true); | ||||
|                 $childBar->unpublish('maps.unpublish')->listCheck(true); | ||||
|             } | ||||
|  | ||||
|             if ($canDo->get('core.delete')) { | ||||
|                 $toolbar->standardButton('delete', 'JTOOLBAR_DELETE', 'maps.delete') | ||||
|                     ->listCheck(true); | ||||
|                 $toolbar->divider(); | ||||
|             } | ||||
|  | ||||
|             $toolbar->divider(); | ||||
|             $toolbar->popupButton('bars', 'COM_FINDER_STATISTICS') | ||||
|                 ->popupType('iframe') | ||||
|                 ->textHeader(Text::_('COM_FINDER_STATISTICS_TITLE')) | ||||
|                 ->url('index.php?option=com_finder&view=statistics&tmpl=component') | ||||
|                 ->modalWidth('800px') | ||||
|                 ->modalHeight('500px') | ||||
|                 ->title(Text::_('COM_FINDER_STATISTICS_TITLE')) | ||||
|                 ->icon('icon-bars'); | ||||
|             $toolbar->divider(); | ||||
|         } | ||||
|  | ||||
|         if ($canDo->get('core.admin') || $canDo->get('core.options')) { | ||||
|             $toolbar->preferences('com_finder'); | ||||
|         } | ||||
|  | ||||
|         $toolbar->help('Smart_Search:_Content_Maps'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,172 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Searches; | ||||
|  | ||||
| use Joomla\CMS\Factory; | ||||
| use Joomla\CMS\Helper\ContentHelper; | ||||
| use Joomla\CMS\HTML\HTMLHelper; | ||||
| use Joomla\CMS\Language\Text; | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
| use Joomla\CMS\Router\Route; | ||||
| use Joomla\CMS\Toolbar\ToolbarHelper; | ||||
| use Joomla\CMS\Uri\Uri; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * View class for a list of search terms. | ||||
|  * | ||||
|  * @since  4.0.0 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * True if gathering search statistics is enabled | ||||
|      * | ||||
|      * @var  boolean | ||||
|      */ | ||||
|     protected $enabled; | ||||
|  | ||||
|     /** | ||||
|      * An array of items | ||||
|      * | ||||
|      * @var  array | ||||
|      */ | ||||
|     protected $items; | ||||
|  | ||||
|     /** | ||||
|      * The pagination object | ||||
|      * | ||||
|      * @var  \Joomla\CMS\Pagination\Pagination | ||||
|      */ | ||||
|     protected $pagination; | ||||
|  | ||||
|     /** | ||||
|      * The model state | ||||
|      * | ||||
|      * @var  \Joomla\Registry\Registry | ||||
|      */ | ||||
|     protected $state; | ||||
|  | ||||
|     /** | ||||
|      * Form object for search filters | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Form\Form | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $filterForm; | ||||
|  | ||||
|     /** | ||||
|      * The active search filters | ||||
|      * | ||||
|      * @var    array | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     public $activeFilters; | ||||
|  | ||||
|     /** | ||||
|      * The actions the user is authorised to perform | ||||
|      * | ||||
|      * @var    \Joomla\Registry\Registry | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     protected $canDo; | ||||
|  | ||||
|     /** | ||||
|      * @var boolean | ||||
|      * | ||||
|      * @since  4.0.0 | ||||
|      */ | ||||
|     private $isEmptyState = false; | ||||
|  | ||||
|     /** | ||||
|      * Display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths. | ||||
|      * | ||||
|      * @return  void | ||||
|      */ | ||||
|     public function display($tpl = null) | ||||
|     { | ||||
|         $app                 = Factory::getApplication(); | ||||
|         $this->items         = $this->get('Items'); | ||||
|         $this->pagination    = $this->get('Pagination'); | ||||
|         $this->state         = $this->get('State'); | ||||
|         $this->filterForm    = $this->get('FilterForm'); | ||||
|         $this->activeFilters = $this->get('ActiveFilters'); | ||||
|         $this->enabled       = $this->state->params->get('gather_search_statistics', 0); | ||||
|         $this->canDo         = ContentHelper::getActions('com_finder'); | ||||
|         $uri                 = Uri::getInstance(); | ||||
|         $link                = 'index.php?option=com_config&view=component&component=com_finder&return=' . base64_encode($uri); | ||||
|         $output              = HTMLHelper::_('link', Route::_($link), Text::_('JOPTIONS')); | ||||
|  | ||||
|         if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) { | ||||
|             $this->setLayout('emptystate'); | ||||
|         } | ||||
|  | ||||
|         // Check for errors. | ||||
|         if (\count($errors = $this->get('Errors'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         // Check if component is enabled | ||||
|         if (!$this->enabled) { | ||||
|             // Check if the user has access to the component options | ||||
|             if ($this->canDo->get('core.admin') || $this->canDo->get('core.options')) { | ||||
|                 $app->enqueueMessage(Text::sprintf('COM_FINDER_LOGGING_DISABLED', $output), 'warning'); | ||||
|             } else { | ||||
|                 $app->enqueueMessage(Text::_('COM_FINDER_LOGGING_DISABLED_NO_AUTH'), 'warning'); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Prepare the view. | ||||
|         $this->addToolbar(); | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add the page title and toolbar. | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @since   1.6 | ||||
|      */ | ||||
|     protected function addToolbar() | ||||
|     { | ||||
|         $canDo   = $this->canDo; | ||||
|         $toolbar = $this->getDocument()->getToolbar(); | ||||
|  | ||||
|         ToolbarHelper::title(Text::_('COM_FINDER_MANAGER_SEARCHES'), 'search'); | ||||
|  | ||||
|         if (!$this->isEmptyState) { | ||||
|             if ($canDo->get('core.edit.state')) { | ||||
|                 $toolbar->standardButton('reset', 'JSEARCH_RESET', 'searches.reset') | ||||
|                     ->icon('icon-refresh') | ||||
|                     ->listCheck(false); | ||||
|             } | ||||
|  | ||||
|             $toolbar->divider(); | ||||
|         } | ||||
|  | ||||
|         if ($canDo->get('core.admin') || $canDo->get('core.options')) { | ||||
|             $toolbar->preferences('com_finder'); | ||||
|         } | ||||
|  | ||||
|         $toolbar->help('Smart_Search:_Search_Term_Analysis'); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,57 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * @package     Joomla.Administrator | ||||
|  * @subpackage  com_finder | ||||
|  * | ||||
|  * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> | ||||
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt | ||||
|  */ | ||||
|  | ||||
| namespace Joomla\Component\Finder\Administrator\View\Statistics; | ||||
|  | ||||
| use Joomla\CMS\MVC\View\GenericDataException; | ||||
| use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||||
|  | ||||
| // phpcs:disable PSR1.Files.SideEffects | ||||
| \defined('_JEXEC') or die; | ||||
| // phpcs:enable PSR1.Files.SideEffects | ||||
|  | ||||
| /** | ||||
|  * Statistics view class for Finder. | ||||
|  * | ||||
|  * @since  2.5 | ||||
|  */ | ||||
| class HtmlView extends BaseHtmlView | ||||
| { | ||||
|     /** | ||||
|      * The index statistics | ||||
|      * | ||||
|      * @var    \Joomla\CMS\Object\CMSObject | ||||
|      * | ||||
|      * @since  3.6.1 | ||||
|      */ | ||||
|     protected $data; | ||||
|  | ||||
|     /** | ||||
|      * Method to display the view. | ||||
|      * | ||||
|      * @param   string  $tpl  A template file to load. [optional] | ||||
|      * | ||||
|      * @return  void | ||||
|      * | ||||
|      * @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'))) { | ||||
|             throw new GenericDataException(implode("\n", $errors), 500); | ||||
|         } | ||||
|  | ||||
|         parent::display($tpl); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user