Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<?php

/**
* AlphaBrowse Module Controller.
* AlphaBrowse home action.
*
* PHP version 8
*
* Copyright (C) Villanova University 2011.
* Copyright (C) The National Library of Finland 2026.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Expand All @@ -21,38 +22,49 @@
* <https://www.gnu.org/licenses/>.
*
* @category VuFind
* @package Controller
* @package Action
* @author Mark Triggs <vufind-tech@lists.sourceforge.net>
* @author Chris Hallberg <challber@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/indexing:alphabetical_heading_browse Wiki
*/

namespace VuFind\Controller;
namespace VuFind\Action\Alphabrowse;

use Laminas\View\Model\ViewModel;
use VuFind\Config\Config;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use VuFind\Action\AbstractTemplateRenderingAction;
use VuFind\Exception\BadRequest;
use VuFind\ServiceManager\Factory\Autowire;
use VuFindSearch\Command\AlphabeticBrowseCommand;
use VuFindSearch\ParamBag;
use VuFindSearch\Service as SearchService;

use function in_array;
use function intval;

/**
* AlphabrowseController Class.
* AlphaBrowse home action.
*
* Controls the alphabetical browsing feature
*
* @category VuFind
* @package Controller
* @author Mark Triggs <vufind-tech@lists.sourceforge.net>
* @author Chris Hallberg <challber@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/indexing:alphabetical_heading_browse Wiki
*/
class AlphabrowseController extends AbstractBase
class HomeAction extends AbstractTemplateRenderingAction
{
use Feature\AlphaBrowseTrait;
/**
* The name of the backend providing alphabrowse services.
*
* @var string
*/
protected $alphabrowseBackend = 'Solr';

/**
* Default browse types.
Expand All @@ -77,6 +89,73 @@ class AlphabrowseController extends AbstractBase
'dewey' => 'title',
];

/**
* Constructor.
*
* @param SearchService $searchService Search service
* @param array $config VuFind configuration
*/
#[Autowire()]
public function __construct(
protected SearchService $searchService,
#[Autowire(config: 'config')] protected array $config,
) {
parent::__construct();
}

/**
* Display a particular tab.
*
* @param ServerRequestInterface $request Server request
* @param ResponseInterface $response Response
*
* @return ResponseInterface
*/
public function action(
ServerRequestInterface $request,
ResponseInterface $response,
): ResponseInterface {
// Load config parameters:
$config = $this->config;
$rowsBefore = ctype_digit((string)($config['AlphaBrowse']['rows_before'] ?? '-'))
? (int)$config['AlphaBrowse']['rows_before'] : 0;
$limit = ctype_digit((string)($config['AlphaBrowse']['page_size'] ?? '-'))
? (int)$config['AlphaBrowse']['page_size'] : 20;

// Process incoming parameters:
$source = $this->getQueryParam('source', false);
$from = $this->getQueryParam('from', false);
$page = intval($this->getQueryParam('page', 0));

// Load highlighting configuration while accounting for special case:
// highlighting is pointless if there's no user input:
$highlighting = empty($from) ? false : $config['AlphaBrowse']['highlighting'] ?? false;

// Set up any extra parameters to pass
$extras = $this->getExtras($config);

// Create template params:
$templateParams = [
'alphaBrowseTypes' => $this->getTypes($config),
'from' => $from,
'source' => $source,
'extras' => array_filter(explode(':', $extras[$source] ?? '')),
];

// If required parameters are present, load results:
$this->addResultsToTemplateParams(
$templateParams,
$page,
$limit,
$rowsBefore,
$highlighting,
$extras
);

// Render results:
return $this->renderTemplate($request, $response, $templateParams);
}

/**
* Get browse types from config file, or use defaults if unavailable.
*
Expand All @@ -102,87 +181,84 @@ protected function getExtras(array $config): array
}

/**
* Add alphabrowse results to the view model.
* Add alphabrowse results to the template params.
*
* @param ViewModel $view View model (must already contain source and
* from values)
* @param int $page Results page to load
* @param int $limit Page size
* @param int $rowsBefore Number of rows to display before highlighted
* row
* @param bool $highlighting Is row highlighting enabled?
* @param array $extras Extra fields to load in results
* @param array $templateParams Template params (must already contain source and from values)
* @param int $page Results page to load
* @param int $limit Page size
* @param int $rowsBefore Number of rows to display before highlighted row
* @param bool $highlighting Is row highlighting enabled?
* @param array $extras Extra fields to load in results
*
* @return void
*/
protected function addResultsToView(
ViewModel $view,
protected function addResultsToTemplateParams(
array &$templateParams,
int $page,
int $limit,
int $rowsBefore,
bool $highlighting,
array $extras
): void {
$result = [];
if ($view->source && $view->from !== false) {
$source = $templateParams['source'] ?? null;
$from = $templateParams['from'] ?? null;
$alphaBrowseTypes = $templateParams['alphaBrowseTypes'] ?? [];
if ($source && $from !== false) {
// Validate source parameter:
if (!in_array($view->source, array_keys($view->alphaBrowseTypes))) {
if (!in_array($source, array_keys($alphaBrowseTypes))) {
throw new BadRequest(
"Unsupported alphabrowse type: {$view->source}"
"Unsupported alphabrowse type: $source"
);
}

// Set up extra params:
$extraParams = new ParamBag();
if (isset($extras[$view->source])) {
$extraParams->add('extras', $extras[$view->source]);
if (isset($extras[$source])) {
$extraParams->add('extras', $extras[$source]);
}

// Load Solr data or die trying:
$result = $this->alphabeticBrowse(
$view->source,
$view->from,
$command = new AlphabeticBrowseCommand(
$this->alphabrowseBackend,
$source,
$from,
$page,
$limit,
$extraParams,
0 - $rowsBefore
);
$result = $this->searchService->invoke($command)->getResult();

// No results? Try the previous page just in case we've gone past
// the end of the list....
// No results? Try the previous page just in case we've gone past the end of the list....
if ($result['Browse']['totalCount'] == 0) {
$page--;
$result = $this->alphabeticBrowse(
$view->source,
$view->from,
$page,
$limit,
$extraParams,
0
);
$command->setPage($page)
->setOffsetDelta(0);
$result = $this->searchService->invoke($command)->getResult();
if ($highlighting) {
$view->highlight_end = true;
$templateParams['highlight_end'] = true;
}
}

// Only display next/previous page links when applicable:
if ($result['Browse']['totalCount'] > $limit) {
$view->nextpage = $page + 1;
$templateParams['nextpage'] = $page + 1;
}
if ($result['Browse']['offset'] + $result['Browse']['startRow'] > 1) {
$view->prevpage = $page - 1;
$templateParams['prevpage'] = $page - 1;
}
}

if ($view->source === 'topic') {
if ($source === 'topic') {
$this->applyTopicDelimiters($result);
}

$view->result = $result;
$templateParams['result'] = $result;

// set up highlighting: page 0 contains match location
if ($highlighting && $page == 0 && isset($view->result['Browse'])) {
$this->applyHighlighting($view, $rowsBefore);
if ($highlighting && $page == 0 && isset($result['Browse'])) {
$this->applyHighlighting($templateParams, $rowsBefore);
}
}

Expand All @@ -195,7 +271,7 @@ protected function addResultsToView(
*/
protected function applyTopicDelimiters(&$result): void
{
$config = $this->getConfigArray();
$config = $this->config;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's cleaner to just use $this->config in line 279 below; this assignment doesn't really seem necessary.


foreach ($result['Browse']['items'] as &$item) {
$item['heading'] = str_replace(
Expand All @@ -207,21 +283,21 @@ protected function applyTopicDelimiters(&$result): void
}

/**
* Apply highlighting settings to the view based on the result set.
* Apply highlighting settings to the template params based on the result set.
*
* @param ViewModel $view View model to be updated (must already contain
* results)
* @param int $rowsBefore Number of rows to display before highlighted row
* @param array $templateParams Template params to be updated (must already contain results)
* @param int $rowsBefore Number of rows to display before highlighted row
*
* @return void
*/
protected function applyHighlighting(ViewModel $view, int $rowsBefore): void
protected function applyHighlighting(array &$templateParams, int $rowsBefore): void
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to have this function return the modified array instead of changing it by reference? I don't have a strong preference, but I try to avoid manipulation by reference when feasible since it can be a little less clear.

(And, of course, same question applies to addResultsToTemplateParams above).

{
$startRow = $view->result['Browse']['startRow'];
$browseResult = $templateParams['result']['Browse'];
$startRow = $browseResult['startRow'];
// solr counts rows from 1; adjust to array position style
$startRow_adj = $startRow - 1;
$offset = $view->result['Browse']['offset'];
$totalRows = $view->result['Browse']['totalCount'];
$offset = $browseResult['offset'];
$totalRows = $browseResult['totalCount'];
$totalRows += $startRow + $offset > 0 ? $startRow_adj + $offset : 0;

// normal case: somewhere in the middle of the browse list
Expand All @@ -233,58 +309,9 @@ protected function applyHighlighting(ViewModel $view, int $rowsBefore): void
// special case: we've gone past the end
// only the rowsBefore records will have been returned
if ($startRow > $totalRows) {
$view->highlight_end = true;
$templateParams['highlight_end'] = true;
}
$view->highlight_row = $highlight_row;
$view->match_type = $view->result['Browse']['matchType'];
}

/**
* Gathers data for the view of the AlphaBrowser and does some initialization.
*
* @return ViewModel
*/
public function homeAction(): ViewModel
{
// Load config parameters
$config = $this->getConfigArray();
$rowsBefore = ctype_digit((string)($config['AlphaBrowse']['rows_before'] ?? '-'))
? (int)$config['AlphaBrowse']['rows_before'] : 0;
$limit = ctype_digit((string)($config['AlphaBrowse']['page_size'] ?? '-'))
? (int)$config['AlphaBrowse']['page_size'] : 20;

// Process incoming parameters:
$source = $this->params()->fromQuery('source', false);
$from = $this->params()->fromQuery('from', false);
$page = intval($this->params()->fromQuery('page', 0));

// Load highlighting configuration while accounting for special case:
// highlighting is pointless if there's no user input:
$highlighting = empty($from) ? false : $config['AlphaBrowse']['highlighting'] ?? false;

// Set up any extra parameters to pass
$extras = $this->getExtras($config);

// Create view model:
$view = $this->createViewModel(
[
'alphaBrowseTypes' => $this->getTypes($config),
'from' => $from,
'source' => $source,
'extras' => array_filter(explode(':', $extras[$source] ?? '')),
]
);

// If required parameters are present, load results:
$this->addResultsToView(
$view,
$page,
$limit,
$rowsBefore,
$highlighting,
$extras
);

return $view;
$templateParams['highlight_row'] = $highlight_row;
$templateParams['match_type'] = $browseResult['matchType'];
}
}
Loading
Loading