Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
AuthorInfo
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 10
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 setConfig
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 setTranslator
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAuthorInfo
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 normalizeName
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getWikipediaNameFromViaf
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 normalizeNameWithViaf
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 getAuthor
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3/**
4 * AuthorInfo Recommendations Module
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2010.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Recommendations
25 * @author   Chris Hallberg <challber@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
28 */
29
30namespace VuFind\Recommend;
31
32use Exception;
33use Laminas\I18n\Translator\TranslatorInterface;
34use VuFind\Connection\Wikipedia;
35use VuFind\I18n\Translator\TranslatorAwareInterface;
36use VuFindSearch\Query\Query;
37
38use function count;
39
40/**
41 * AuthorInfo Recommendations Module
42 *
43 * This class gathers information from the Wikipedia API and publishes the results
44 * to a module at the top of an author's results page
45 *
46 * @category VuFind
47 * @package  Recommendations
48 * @author   Chris Hallberg <challber@villanova.edu>
49 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
50 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
51 * @view     AuthorInfoFacets.phtml
52 */
53class AuthorInfo implements RecommendInterface, TranslatorAwareInterface
54{
55    use \VuFind\I18n\Translator\TranslatorAwareTrait {
56        setTranslator as setTranslatorThroughTrait;
57    }
58
59    /**
60     * HTTP client
61     *
62     * @var \Laminas\Http\Client
63     */
64    protected $client;
65
66    /**
67     * Wikipedia client
68     *
69     * @var Wikipedia
70     */
71    protected $wikipedia;
72
73    /**
74     * Saved search results
75     *
76     * @var \VuFind\Search\Base\Results
77     */
78    protected $searchObject;
79
80    /**
81     * Results plugin manager
82     *
83     * @var \VuFind\Search\Results\PluginManager
84     */
85    protected $resultsManager;
86
87    /**
88     * Should we use VIAF for authorized names?
89     *
90     * @var bool
91     */
92    protected $useViaf = false;
93
94    /**
95     * Sources of author data that may be used (comma-delimited string; currently
96     * only 'wikipedia' is supported).
97     *
98     * @var string
99     */
100    protected $sources;
101
102    /**
103     * Constructor
104     *
105     * @param \VuFind\Search\Results\PluginManager $results Results plugin manager
106     * @param \Laminas\Http\Client                 $client  HTTP client
107     * @param string                               $sources Source identifiers
108     * (currently, only 'wikipedia' is supported)
109     */
110    public function __construct(
111        \VuFind\Search\Results\PluginManager $results,
112        \Laminas\Http\Client $client,
113        $sources = 'wikipedia'
114    ) {
115        $this->resultsManager = $results;
116        $this->client = $client;
117        $this->wikipedia = new Wikipedia($client);
118        $this->sources = $sources;
119    }
120
121    /**
122     * Store the configuration of the recommendation module.
123     *
124     * @param string $settings Settings from searches.ini.
125     *
126     * @return void
127     */
128    public function setConfig($settings)
129    {
130        $parts = explode(':', $settings);
131        if (
132            isset($parts[0]) && !empty($parts[0])
133            && strtolower(trim($parts[0])) !== 'false'
134        ) {
135            $this->useViaf = true;
136        }
137    }
138
139    /**
140     * Set a translator
141     *
142     * @param TranslatorInterface $translator Translator
143     *
144     * @return TranslatorAwareInterface
145     */
146    public function setTranslator(TranslatorInterface $translator)
147    {
148        $this->setTranslatorThroughTrait($translator);
149        $this->wikipedia->setTranslator($translator);
150        $this->wikipedia->setLanguage($this->getTranslatorLocale());
151        return $this;
152    }
153
154    /**
155     * Called before the Search Results object performs its main search
156     * (specifically, in response to \VuFind\Search\SearchRunner::EVENT_CONFIGURED).
157     * This method is responsible for setting search parameters needed by the
158     * recommendation module and for reading any existing search parameters that may
159     * be needed.
160     *
161     * @param \VuFind\Search\Base\Params $params  Search parameter object
162     * @param \Laminas\Stdlib\Parameters $request Parameter object representing user
163     * request.
164     *
165     * @return void
166     */
167    public function init($params, $request)
168    {
169        // No action needed here.
170    }
171
172    /**
173     * Called after the Search Results object has performed its main search. This
174     * may be used to extract necessary information from the Search Results object
175     * or to perform completely unrelated processing.
176     *
177     * @param \VuFind\Search\Base\Results $results Search results object
178     *
179     * @return void
180     */
181    public function process($results)
182    {
183        $this->searchObject = $results;
184    }
185
186    /**
187     * Returns info from Wikipedia to the view
188     *
189     * @reference _parseWikipedia : Home.php (VuFind 1)
190     * @refauthor Rushikesh Katikar <rushikesh.katikar@gmail.com>
191     *
192     * @return array info = {
193     *              'description' : string : extracted/formatted Wikipedia text
194     *              'image'       : string : url of the Wikipedia page's image
195     *              'altimge'     : string : alt text for the image
196     *              'name'        : string : title of Wikipedia article
197     *              'wiki_lang'   : string : truncated from the lang. settings
198     *           }
199     */
200    public function getAuthorInfo()
201    {
202        // Don't load Wikipedia content if Wikipedia is disabled:
203        try {
204            return stristr($this->sources, 'wikipedia') ? $this->wikipedia->get($this->getAuthor()) : null;
205        } catch (Exception $e) {
206            error_log("Unexpected error while loading author info: {$e->getMessage()}");
207            return null;
208        }
209    }
210
211    /**
212     * Normalize an author name using internal logic.
213     *
214     * @param string $author Author name
215     *
216     * @return string
217     */
218    protected function normalizeName($author)
219    {
220        // remove dates
221        $author = preg_replace('/[0-9]+-[0-9]*/', '', $author);
222        // if name is rearranged by commas
223        $author = trim($author, ', .');
224        $nameParts = explode(', ', $author);
225        $last = $nameParts[0];
226        // - move all names up an index, move last name to last
227        // - Last, First M. -> First M. Last
228        for ($i = 1; $i < count($nameParts); $i++) {
229            $nameParts[$i - 1] = $nameParts[$i];
230        }
231        $nameParts[count($nameParts) - 1] = $last;
232        $author = implode(' ', $nameParts);
233        return $author;
234    }
235
236    /**
237     * Translate an LCCN to a Wikipedia name through the VIAF web service. Returns
238     * false if no value can be found.
239     *
240     * @param string $lccn LCCN
241     *
242     * @return string|bool
243     */
244    protected function getWikipediaNameFromViaf($lccn)
245    {
246        $param = urlencode("LC|$lccn");
247        $url = "http://viaf.org/viaf/sourceID/{$param}/justlinks.json";
248        $result = $this->client->setUri($url)->setMethod('GET')->send();
249        if (!$result->isSuccess()) {
250            return false;
251        }
252        $details = json_decode($result->getBody());
253        return $details->WKP[0] ?? false;
254    }
255
256    /**
257     * Normalize an author name using VIAF.
258     *
259     * @param string $author Author name
260     *
261     * @return string
262     */
263    protected function normalizeNameWithViaf($author)
264    {
265        // Do authority search:
266        $auth = $this->resultsManager->get('SolrAuth');
267        $auth->getParams()->setBasicSearch('"' . $author . '"', 'MainHeading');
268        $results = $auth->getResults();
269
270        // Find first useful LCCN:
271        foreach ($results as $current) {
272            $lccn = $current->tryMethod('getRawLCCN');
273            if (!empty($lccn)) {
274                $name = $this->getWikipediaNameFromViaf($lccn);
275                if (!empty($name)) {
276                    return $name;
277                }
278            }
279        }
280
281        // No LCCN found?  Use the default normalization routine:
282        return $this->normalizeName($author);
283    }
284
285    /**
286     * Takes the search term and extracts a normal name from it
287     *
288     * @return string
289     */
290    protected function getAuthor()
291    {
292        $search = $this->searchObject->getParams()->getQuery();
293        if ($search instanceof Query) {
294            $author = $search->getString();
295            // remove quotes
296            $author = str_replace('"', '', $author);
297            return $this->useViaf
298                ? $this->normalizeNameWithViaf($author)
299                : $this->normalizeName($author);
300        }
301        return '';
302    }
303}