diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-06.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-06.sql new file mode 100644 index 0000000000000..b265025b2c16c --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-06.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS `#__finder_logging` ( + `searchterm` VARCHAR(255) NOT NULL DEFAULT '', + `md5sum` VARCHAR(32) NOT NULL DEFAULT '', + `query` BLOB NOT NULL, + `hits` INT(11) NOT NULL DEFAULT '1', + `results` INT(11) NOT NULL DEFAULT '0', + UNIQUE INDEX `md5sum` (`md5sum`), + INDEX `searchterm` (`searchterm`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci; diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-06.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-06.sql new file mode 100644 index 0000000000000..c0368b06a5530 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-06.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS "#__finder_logging" ( + "searchterm" character varying(255) NOT NULL DEFAULT '', + "md5sum" character varying(32) NOT NULL DEFAULT '', + "query" bytes NOT NULL, + "hits" integer NOT NULL DEFAULT 1, + "results" integer NOT NULL DEFAULT 0, + CONSTRAINT "#__finder_logging_idx_md5sum" UNIQUE ("md5sum") +); +CREATE INDEX "#__finder_logging_idx_md5sum" on "#__finder_logging" ("md5sum"); +CREATE INDEX "#__finder_logging_idx_searchterm" on "#__finder_logging" ("searchterm"); diff --git a/administrator/components/com_finder/Controller/SearchesController.php b/administrator/components/com_finder/Controller/SearchesController.php new file mode 100644 index 0000000000000..734f5b5823655 --- /dev/null +++ b/administrator/components/com_finder/Controller/SearchesController.php @@ -0,0 +1,41 @@ +getModel('Searches'); + + if (!$model->reset()) + { + $this->app->enqueueMessage($model->getError(), 'error'); + } + + $this->setRedirect('index.php?option=com_finder&view=searches'); + } +} diff --git a/administrator/components/com_finder/Helper/FinderHelper.php b/administrator/components/com_finder/Helper/FinderHelper.php index b7bc2f732e271..2dcc2b40efa6f 100644 --- a/administrator/components/com_finder/Helper/FinderHelper.php +++ b/administrator/components/com_finder/Helper/FinderHelper.php @@ -53,6 +53,11 @@ public static function addSubmenu($vName) 'index.php?option=com_finder&view=filters', $vName === 'filters' ); + \JHtmlSidebar::addEntry( + \JText::_('COM_FINDER_SUBMENU_SEARCHES'), + 'index.php?option=com_finder&view=searches', + $vName === 'searches' + ); } /** diff --git a/administrator/components/com_finder/Model/SearchesModel.php b/administrator/components/com_finder/Model/SearchesModel.php new file mode 100644 index 0000000000000..05369341a48d2 --- /dev/null +++ b/administrator/components/com_finder/Model/SearchesModel.php @@ -0,0 +1,175 @@ +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 __DEPLOY_VERSION__ + */ + 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 \JDatabaseQuery + * + * @since __DEPLOY_VERSION__ + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $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 __DEPLOY_VERSION__ + */ + public function getItems() + { + $items = parent::getItems(); + + \JLoader::register('FinderIndexerQuery', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/indexer/query.php'); + \JLoader::register('FinderIndexerToken', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/indexer/token.php'); + + foreach ($items as $item) + { + $item->query = unserialize($item->query); + } + + return $items; + } + + /** + * Method to reset the search log table. + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + public function reset() + { + $db = $this->getDbo(); + + try + { + $db->truncateTable('#__finder_logging'); + } + catch (\RuntimeException $e) + { + $this->setError($e->getMessage()); + + return false; + } + + return true; + } +} diff --git a/administrator/components/com_finder/View/Searches/HtmlView.php b/administrator/components/com_finder/View/Searches/HtmlView.php new file mode 100644 index 0000000000000..4b578389d7541 --- /dev/null +++ b/administrator/components/com_finder/View/Searches/HtmlView.php @@ -0,0 +1,148 @@ +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('logging_enabled'); + $this->canDo = ContentHelper::getActions('com_finder'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new \JViewGenericdataexception(implode("\n", $errors), 500); + } + + FinderHelper::addSubmenu('searches'); + + // Check if plugin is enabled + if ($this->enabled) + { + $app->enqueueMessage(\JText::_('COM_FINDER_LOGGING_ENABLED'), 'notice'); + } + else + { + $app->enqueueMessage(\JText::_('COM_FINDER_LOGGING_DISABLED'), 'warning'); + } + + // Prepare the view. + $this->addToolbar(); + $this->sidebar = \JHtmlSidebar::render(); + + return parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = $this->canDo; + + ToolbarHelper::title(\JText::_('COM_FINDER_MANAGER_SEARCHES'), 'search'); + + if ($canDo->get('core.edit.state')) + { + ToolbarHelper::custom('searches.reset', 'refresh.png', 'refresh_f2.png', 'JSEARCH_RESET', false); + } + + ToolbarHelper::divider(); + + if ($canDo->get('core.admin') || $canDo->get('core.options')) + { + ToolbarHelper::preferences('com_finder'); + } + + ToolbarHelper::help('JHELP_COMPONENTS_FINDER_MANAGE_SEARCHES'); + } +} diff --git a/administrator/components/com_finder/config.xml b/administrator/components/com_finder/config.xml index 351aaebb213cd..d0dff456b8f68 100644 --- a/administrator/components/com_finder/config.xml +++ b/administrator/components/com_finder/config.xml @@ -7,7 +7,7 @@ > +
+ + + + + + + + + + + + + +
diff --git a/administrator/components/com_finder/sql/install.mysql.sql b/administrator/components/com_finder/sql/install.mysql.sql index 6df173ecc27d6..792d43c162566 100644 --- a/administrator/components/com_finder/sql/install.mysql.sql +++ b/administrator/components/com_finder/sql/install.mysql.sql @@ -66,6 +66,20 @@ CREATE TABLE IF NOT EXISTS `#__finder_links_terms` ( KEY `idx_link_term_weight` (`link_id`,`term_id`,`weight`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci; +-- +-- Table structure for table `#__finder_logging` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_logging` ( + `searchterm` VARCHAR(255) NOT NULL DEFAULT '', + `md5sum` VARCHAR(32) NOT NULL DEFAULT '', + `query` BLOB NOT NULL, + `hits` INT(11) NOT NULL DEFAULT '1', + `results` INT(11) NOT NULL DEFAULT '0', + UNIQUE INDEX `md5sum` (`md5sum`), + INDEX `searchterm` (`searchterm`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci; + -- -- Table structure for table `#__finder_taxonomy` -- diff --git a/administrator/components/com_finder/sql/install.postgresql.sql b/administrator/components/com_finder/sql/install.postgresql.sql index 69db285c6b4b0..086964f903f0f 100644 --- a/administrator/components/com_finder/sql/install.postgresql.sql +++ b/administrator/components/com_finder/sql/install.postgresql.sql @@ -63,6 +63,21 @@ CREATE TABLE IF NOT EXISTS "#__finder_links_terms" ( CREATE INDEX "#__finder_links_terms0_idx_term_weight" on "#__finder_links_terms0" ("term_id", "weight"); CREATE INDEX "#__finder_links_terms0_idx_link_term_weight" on "#__finder_links_terms0" ("link_id", "term_id", "weight"); +-- +-- Table structure for table `#__finder_logging` +-- + +CREATE TABLE IF NOT EXISTS "#__finder_logging" ( + "searchterm" character varying(255) NOT NULL DEFAULT '', + "md5sum" character varying(32) NOT NULL DEFAULT '', + "query" bytes NOT NULL, + "hits" integer NOT NULL DEFAULT 1, + "results" integer NOT NULL DEFAULT 0, + CONSTRAINT "#__finder_logging_idx_md5sum" UNIQUE ("md5sum") +); +CREATE INDEX "#__finder_logging_idx_md5sum" on "#__finder_logging" ("md5sum"); +CREATE INDEX "#__finder_logging_idx_searchterm" on "#__finder_logging" ("searchterm"); + -- -- Table: #__finder_taxonomy -- diff --git a/administrator/components/com_finder/sql/uninstall.mysql.sql b/administrator/components/com_finder/sql/uninstall.mysql.sql index 59d1b7a9b9491..5167421c75378 100644 --- a/administrator/components/com_finder/sql/uninstall.mysql.sql +++ b/administrator/components/com_finder/sql/uninstall.mysql.sql @@ -1,6 +1,7 @@ DROP TABLE IF EXISTS `#__finder_filters`; DROP TABLE IF EXISTS `#__finder_links`; DROP TABLE IF EXISTS `#__finder_links_terms`; +DROP TABLE IF EXISTS `#__finder_logging`; DROP TABLE IF EXISTS `#__finder_taxonomy`; DROP TABLE IF EXISTS `#__finder_taxonomy_map`; DROP TABLE IF EXISTS `#__finder_terms`; diff --git a/administrator/components/com_finder/sql/uninstall.postgresql.sql b/administrator/components/com_finder/sql/uninstall.postgresql.sql index 6bc222650b261..06507dcd70af5 100644 --- a/administrator/components/com_finder/sql/uninstall.postgresql.sql +++ b/administrator/components/com_finder/sql/uninstall.postgresql.sql @@ -1,6 +1,7 @@ DROP TABLE IF EXISTS "#__finder_filters"; DROP TABLE IF EXISTS "#__finder_links"; DROP TABLE IF EXISTS "#__finder_links_terms"; +DROP TABLE IF EXISTS "#__finder_logging"; DROP TABLE IF EXISTS "#__finder_taxonomy"; DROP TABLE IF EXISTS "#__finder_taxonomy_map"; DROP TABLE IF EXISTS "#__finder_terms"; diff --git a/administrator/components/com_finder/tmpl/searches/default.php b/administrator/components/com_finder/tmpl/searches/default.php new file mode 100644 index 0000000000000..85dae2f684728 --- /dev/null +++ b/administrator/components/com_finder/tmpl/searches/default.php @@ -0,0 +1,75 @@ +escape($this->state->get('list.ordering')); +$listDirn = $this->escape($this->state->get('list.direction')); +?> +
+
+
+ sidebar; ?> +
+
+
+ $this, 'options' => array('filterButton' => false))); ?> + items)) : ?> + + + + + + + + + + + + + + + + + items as $i => $item) : ?> + + + + + + + +
+ + + + + +
+ pagination->getListFooter(); ?> +
+ escape($item->searchterm); ?> + + hits; ?> + + results; ?> +
+ + + + +
+
+
+
diff --git a/administrator/language/en-GB/en-GB.com_finder.ini b/administrator/language/en-GB/en-GB.com_finder.ini index a27de9f07328d..47fdab65c2a22 100644 --- a/administrator/language/en-GB/en-GB.com_finder.ini +++ b/administrator/language/en-GB/en-GB.com_finder.ini @@ -85,6 +85,10 @@ COM_FINDER_HEADING_MAP_COUNT="Map Count" COM_FINDER_HEADING_MAP_COUNT_ASC="Map Count ascending" COM_FINDER_HEADING_MAP_COUNT_DESC="Map Count descending" COM_FINDER_HEADING_NODES="Items" +COM_FINDER_HEADING_PHRASE="Search Phrase" +COM_FINDER_HEADING_RESULTS="Results" +COM_FINDER_HEADING_SEARCH_TERM_ASC="Search Phrase ascending" +COM_FINDER_HEADING_SEARCH_TERM_DESC="Search Phrase descending" COM_FINDER_INDEX="Index" COM_FINDER_INDEX_CONFIRM_DELETE_PROMPT="Are you sure you want to delete the selected item(s)?" COM_FINDER_INDEX_CONFIRM_PURGE_PROMPT="Are you sure you want to delete ALL items from the index? This can take a long time on large sites." @@ -126,6 +130,9 @@ COM_FINDER_INDEXER_MESSAGE_OPTIMIZE="The index tables are being optimised for th COM_FINDER_INDEXER_MESSAGE_RUNNING="Your content is being indexed. Do not close this window." COM_FINDER_ITEM_X_ONLY="%s Only" COM_FINDER_ITEMS="Content" +COM_FINDER_LOGGING_DISABLED="Gathering statistics disabled. Enable it in the Options." +COM_FINDER_LOGGING_ENABLED="Gathering statistics enabled." +COM_FINDER_MANAGER_SEARCHES="Search Term Analysis" COM_FINDER_MAPS="Maps" COM_FINDER_MAPS_CONFIRM_DELETE_PROMPT="Are you sure you want to delete the selected map(s)?" COM_FINDER_MAPS_COUNT_PUBLISHED_ITEMS="Published Indexed Content" @@ -155,6 +162,8 @@ COM_FINDER_QUERY_OPERATOR_AND="And" COM_FINDER_QUERY_OPERATOR_NOT="Not" COM_FINDER_QUERY_OPERATOR_OR="Or" COM_FINDER_SEARCH_FILTER_SEARCH_LABEL="Search Filters" +COM_FINDER_SEARCH_IN_PHRASE_LABEL="Filter by searched phrase" +COM_FINDER_SEARCH_IN_PHRASE_DESC="Search for the logged phrase of a search" COM_FINDER_SEARCH_LABEL="Search %s:" COM_FINDER_SEARCH_SEARCH_QUERY_LABEL="Search Content Maps" COM_FINDER_SELECT_SEARCH_FILTER="Select filter" @@ -167,4 +176,5 @@ COM_FINDER_STATISTICS_TITLE="Smart Search Statistics" COM_FINDER_SUBMENU_FILTERS="Search Filters" COM_FINDER_SUBMENU_INDEX="Indexed Content" COM_FINDER_SUBMENU_MAPS="Content Maps" +COM_FINDER_SUBMENU_SEARCHES="Statistics" COM_FINDER_XML_DESCRIPTION="Smart Search." diff --git a/components/com_finder/Helper/FinderHelper.php b/components/com_finder/Helper/FinderHelper.php new file mode 100644 index 0000000000000..568f1174b18d3 --- /dev/null +++ b/components/com_finder/Helper/FinderHelper.php @@ -0,0 +1,85 @@ +get('logging_enabled', 1); + + if (!$enable_log_searches) + { + return; + } + + if (trim($searchquery->input) == '' && !$searchquery->empty) + { + return; + } + + // Initialise our variables + $db = \JFactory::getDbo(); + $query = $db->getQuery(true); + + // Sanitise the term for the database + $temp = unserialize(serialize($searchquery)); + $temp->input = trim(strtolower($searchquery->input)); + $entry = new \stdClass; + $entry->searchterm = $temp->input; + $entry->query = serialize($temp); + $entry->md5sum = md5($entry->query); + $entry->hits = 1; + $entry->results = $resultCount; + + // Query the table to determine if the term has been searched previously + $query->select($db->quoteName('hits')) + ->from($db->quoteName('#__finder_logging')) + ->where($db->quoteName('md5sum') . ' = ' . $db->quote($entry->md5sum)); + $db->setQuery($query); + $hits = (int) $db->loadResult(); + + // Reset the $query object + $query->clear(); + + // Update the table based on the results + if ($hits) + { + $query->update($db->quoteName('#__finder_logging')) + ->set('hits = (hits + 1)') + ->where($db->quoteName('md5sum') . ' = ' . $db->quote($entry->md5sum)); + $db->setQuery($query); + $db->execute(); + } + else + { + $db->insertObject('#__finder_logging', $entry); + } + } +} diff --git a/components/com_finder/View/Search/HtmlView.php b/components/com_finder/View/Search/HtmlView.php index 9a16adc6981cd..62b48ae7541da 100644 --- a/components/com_finder/View/Search/HtmlView.php +++ b/components/com_finder/View/Search/HtmlView.php @@ -10,7 +10,7 @@ defined('_JEXEC') or die; -use Joomla\CMS\Helper\SearchHelper; +use Joomla\Component\Finder\Site\Helper\FinderHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Pagination\Pagination; @@ -168,7 +168,7 @@ public function display($tpl = null) } // Log the search - SearchHelper::logSearch($this->query->input, 'com_finder'); + FinderHelper::logSearch($this->query, $this->total); // Push out the query data. \JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html'); diff --git a/installation/sql/mysql/joomla.sql b/installation/sql/mysql/joomla.sql index be4b8e9a19a07..ef95d538d9e47 100644 --- a/installation/sql/mysql/joomla.sql +++ b/installation/sql/mysql/joomla.sql @@ -844,6 +844,22 @@ CREATE TABLE IF NOT EXISTS `#__finder_links_terms` ( -- -------------------------------------------------------- +-- +-- Table structure for table `#__finder_logging` +-- + +CREATE TABLE IF NOT EXISTS `#__finder_logging` ( + `searchterm` VARCHAR(255) NOT NULL DEFAULT '', + `md5sum` VARCHAR(32) NOT NULL DEFAULT '', + `query` BLOB NOT NULL, + `hits` INT(11) NOT NULL DEFAULT '1', + `results` INT(11) NOT NULL DEFAULT '0', + UNIQUE INDEX `md5sum` (`md5sum`), + INDEX `searchterm` (`searchterm`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + -- -- Table structure for table `#__finder_taxonomy` -- diff --git a/installation/sql/postgresql/joomla.sql b/installation/sql/postgresql/joomla.sql index dd27873d2895e..49c687a3a4390 100644 --- a/installation/sql/postgresql/joomla.sql +++ b/installation/sql/postgresql/joomla.sql @@ -845,6 +845,21 @@ CREATE TABLE IF NOT EXISTS "#__finder_links_terms" ( CREATE INDEX "#__finder_links_terms_idx_term_weight" on "#__finder_links_terms" ("term_id", "weight"); CREATE INDEX "#__finder_links_terms_idx_link_term_weight" on "#__finder_links_terms" ("link_id", "term_id", "weight"); +-- +-- Table structure for table `#__finder_logging` +-- + +CREATE TABLE IF NOT EXISTS "#__finder_logging" ( + "searchterm" character varying(255) NOT NULL DEFAULT '', + "md5sum" character varying(32) NOT NULL DEFAULT '', + "query" bytes NOT NULL, + "hits" integer NOT NULL DEFAULT 1, + "results" integer NOT NULL DEFAULT 0, + CONSTRAINT "#__finder_logging_idx_md5sum" UNIQUE ("md5sum") +); +CREATE INDEX "#__finder_logging_idx_md5sum" on "#__finder_logging" ("md5sum"); +CREATE INDEX "#__finder_logging_idx_searchterm" on "#__finder_logging" ("searchterm"); + -- -- Table structure for table `#__finder_taxonomy` --