Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 156
0.00% covered (danger)
0.00%
0 / 39
CRAP
0.00% covered (danger)
0.00%
0 / 1
Summon
0.00% covered (danger)
0.00%
0 / 156
0.00% covered (danger)
0.00%
0 / 39
10506
0.00% covered (danger)
0.00%
0 / 1
 getAllSubjectHeadings
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 getBibliographyNotes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCallNumbers
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 getCleanDOI
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 getEdition
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getExtraResourceMetadata
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getFormats
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRawAuthorHighlights
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 getHighlightedSnippet
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getHighlightedTitle
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getISBNs
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 getISSNs
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 getLanguages
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOCLC
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOpenUrl
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 supportsOpenUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPlacesOfPublication
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setDateConverter
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDateConverter
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getPublicationDates
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
90
 getPublishers
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPrimaryAuthors
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 getSeries
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getShortTitle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getSubtitle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getSummary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getThumbnail
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
90
 getTitle
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 getTOC
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getURLs
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
 getUniqueID
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContainerTitle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getContainerVolume
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getContainerIssue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getContainerStartPage
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getContainerEndPage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
 getContainerReference
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
56
 hasFullText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isOpenAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Model for Summon records.
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  RecordDrivers
25 * @author   Demian Katz <demian.katz@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:record_drivers Wiki
28 */
29
30namespace VuFind\RecordDriver;
31
32use function count;
33use function intval;
34use function is_array;
35use function strlen;
36
37/**
38 * Model for Summon records.
39 *
40 * @category VuFind
41 * @package  RecordDrivers
42 * @author   Demian Katz <demian.katz@villanova.edu>
43 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
44 * @link     https://vufind.org/wiki/development:plugins:record_drivers Wiki
45 */
46class Summon extends DefaultRecord implements Feature\PreviousUniqueIdInterface
47{
48    use Feature\PreviousUniqueIdTrait;
49
50    /**
51     * Fields that may contain subject headings, and their descriptions
52     *
53     * @var array
54     */
55    protected $subjectFields = [
56        'SubjectTerms' => 'topic',
57        'TemporalSubjectTerms' => 'chronological',
58        'GeographicLocations' => 'geographic',
59        'Keywords' => 'keyword',
60    ];
61
62    /**
63     * Date converter
64     *
65     * @var \VuFind\Date\Converter
66     */
67    protected $dateConverter = null;
68
69    /**
70     * Get all subject headings associated with this record. Each heading is
71     * returned as an array of chunks, increasing from least specific to most
72     * specific.
73     *
74     * @param bool $extended Whether to return a keyed array with the following
75     * keys:
76     * - heading: the actual subject heading chunks
77     * - type: heading type
78     * - source: source vocabulary
79     *
80     * @return array
81     */
82    public function getAllSubjectHeadings($extended = false)
83    {
84        $retval = [];
85
86        foreach ($this->subjectFields as $field => $fieldType) {
87            if (!isset($this->fields[$field])) {
88                continue;
89            }
90            foreach ($this->fields[$field] as $topic) {
91                $topic = trim($topic);
92                $retval[] = $extended
93                    ? [
94                        'heading' => [$topic],
95                        'type' => $fieldType,
96                        'source' => '',
97                    ] : [$topic];
98            }
99        }
100        return $retval;
101    }
102
103    /**
104     * Get notes on bibliography content.
105     *
106     * @return array
107     */
108    public function getBibliographyNotes()
109    {
110        return $this->fields['Notes'] ?? [];
111    }
112
113    /**
114     * Get the call numbers associated with the record (empty string if none).
115     *
116     * @return array
117     */
118    public function getCallNumbers()
119    {
120        // Summon calls this LCCNum even though it may be Dewey
121        return isset($this->fields['LCCCallnum'])
122            && !empty($this->fields['LCCCallnum'])
123            ? [$this->fields['LCCCallnum']] : [];
124    }
125
126    /**
127     * Return the first valid DOI found in the record (false if none).
128     *
129     * @return mixed
130     */
131    public function getCleanDOI()
132    {
133        return (isset($this->fields['DOI'][0]) && !empty($this->fields['DOI'][0]))
134            ? $this->fields['DOI'][0] : false;
135    }
136
137    /**
138     * Get the edition of the current record.
139     *
140     * @return string
141     */
142    public function getEdition()
143    {
144        return isset($this->fields['Edition']) ?
145            $this->fields['Edition'][0] : '';
146    }
147
148    /**
149     * Get extra metadata to store in the resource table. In this instance,
150     * we use the BookMark value so that it can be used to recover expired
151     * records in favorite lists.
152     *
153     * @return string
154     */
155    public function getExtraResourceMetadata()
156    {
157        return isset($this->fields['BookMark'][0])
158            ? ['bookmark' => $this->fields['BookMark'][0]] : null;
159    }
160
161    /**
162     * Get an array of all the formats associated with the record.
163     *
164     * @return array
165     */
166    public function getFormats()
167    {
168        return $this->fields['ContentType'] ?? [];
169    }
170
171    /**
172     * Get highlighted author data, if available.
173     *
174     * @return array
175     */
176    public function getRawAuthorHighlights()
177    {
178        // Don't check for highlighted values if highlighting is disabled.
179        return ($this->highlight && isset($this->fields['Author']))
180            ? $this->fields['Author'] : [];
181    }
182
183    /**
184     * Pick one line from the highlighted text (if any) to use as a snippet.
185     *
186     * @return mixed False if no snippet found, otherwise associative array
187     * with 'snippet' and 'caption' keys.
188     */
189    public function getHighlightedSnippet()
190    {
191        return isset($this->fields['Snippet'][0])
192            ? [
193                'snippet' => trim($this->fields['Snippet'][0], '.'),
194                'caption' => '',
195            ]
196            : false;
197    }
198
199    /**
200     * Get a highlighted title string, if available.
201     *
202     * @return string
203     */
204    public function getHighlightedTitle()
205    {
206        // Don't check for highlighted values if highlighting is disabled:
207        if (!$this->highlight) {
208            return '';
209        }
210        $title = $this->getShortTitle();
211        $sub = $this->getSubtitle();
212        return empty($sub) ? $title : "{$title}{$sub}";
213    }
214
215    /**
216     * Get an array of all ISBNs associated with the record (may be empty).
217     *
218     * @return array
219     */
220    public function getISBNs()
221    {
222        if (isset($this->fields['ISBN']) && is_array($this->fields['ISBN'])) {
223            return $this->fields['ISBN'];
224        }
225        return [];
226    }
227
228    /**
229     * Get an array of all ISSNs associated with the record (may be empty).
230     *
231     * @return array
232     */
233    public function getISSNs()
234    {
235        $issns = [];
236        if (isset($this->fields['ISSN'])) {
237            $issns = $this->fields['ISSN'];
238        }
239        if (isset($this->fields['EISSN'])) {
240            $issns = array_merge($issns, $this->fields['EISSN']);
241        }
242        return $issns;
243    }
244
245    /**
246     * Get an array of all the languages associated with the record.
247     *
248     * @return array
249     */
250    public function getLanguages()
251    {
252        return $this->fields['Language'] ?? [];
253    }
254
255    /**
256     * Get the OCLC number of the record.
257     *
258     * @return array
259     */
260    public function getOCLC()
261    {
262        return $this->fields['OCLC'] ?? [];
263    }
264
265    /**
266     * Get the OpenURL parameters to represent this record (useful for the
267     * title attribute of a COinS span tag).
268     *
269     * @param bool $overrideSupportsOpenUrl Flag to override checking
270     * supportsOpenUrl() (default is false)
271     *
272     * @return string OpenURL parameters.
273     */
274    public function getOpenUrl($overrideSupportsOpenUrl = false)
275    {
276        // stop here if this record does not support OpenURLs
277        if (!$overrideSupportsOpenUrl && !$this->supportsOpenUrl()) {
278            return false;
279        }
280
281        return $this->fields['openUrl']
282            ?? parent::getOpenUrl($overrideSupportsOpenUrl);
283    }
284
285    /**
286     * Checks the current record if it's supported for generating OpenURLs.
287     *
288     * @return bool
289     */
290    public function supportsOpenUrl()
291    {
292        // Summon never uses OpenURLs for anything other than COinS:
293        return false;
294    }
295
296    /**
297     * Get the item's place of publication.
298     *
299     * @return array
300     */
301    public function getPlacesOfPublication()
302    {
303        return $this->fields['PublicationPlace'] ?? [];
304    }
305
306    /**
307     * Pass in a date converter
308     *
309     * @param \VuFind\Date\Converter $dc Date converter
310     *
311     * @return void
312     */
313    public function setDateConverter(\VuFind\Date\Converter $dc)
314    {
315        $this->dateConverter = $dc;
316    }
317
318    /**
319     * Get a date converter
320     *
321     * @return \VuFind\Date\Converter
322     */
323    protected function getDateConverter()
324    {
325        // No object passed in yet?  Build one with default settings:
326        if (null === $this->dateConverter) {
327            $this->dateConverter = new \VuFind\Date\Converter();
328        }
329        return $this->dateConverter;
330    }
331
332    /**
333     * Get the publication dates of the record.  See also getDateSpan().
334     *
335     * @return array
336     */
337    public function getPublicationDates()
338    {
339        if (
340            isset($this->fields['PublicationDate_xml'])
341            && is_array($this->fields['PublicationDate_xml'])
342        ) {
343            $dates = [];
344            $converter = $this->getDateConverter();
345            foreach ($this->fields['PublicationDate_xml'] as $current) {
346                if (isset($current['month']) && isset($current['year'])) {
347                    if (!isset($current['day'])) {
348                        $current['day'] = 1;
349                    }
350                    $dates[] = $converter->convertToDisplayDate(
351                        'm-d-Y',
352                        "{$current['month']}-{$current['day']}-{$current['year']}"
353                    );
354                } elseif (isset($current['year'])) {
355                    $dates[] = $current['year'];
356                }
357            }
358            if (!empty($dates)) {
359                return $dates;
360            }
361        }
362        return $this->fields['PublicationDate'] ?? [];
363    }
364
365    /**
366     * Get the publishers of the record.
367     *
368     * @return array
369     */
370    public function getPublishers()
371    {
372        return $this->fields['Publisher'] ?? [];
373    }
374
375    /**
376     * Get an array of all primary authors.
377     *
378     * @return array
379     */
380    public function getPrimaryAuthors()
381    {
382        $authors = [];
383        if (isset($this->fields['Author_xml'])) {
384            for ($i = 0; $i < count($this->fields['Author_xml']); $i++) {
385                if (isset($this->fields['Author_xml'][$i]['fullname'])) {
386                    $authors[] = $this->fields['Author_xml'][$i]['fullname'];
387                }
388            }
389        }
390        return $authors;
391    }
392
393    /**
394     * Get an array of all series names containing the record. Array entries may
395     * be either the name string, or an associative array with 'name' and 'number'
396     * keys.
397     *
398     * @return array
399     */
400    public function getSeries()
401    {
402        return $this->fields['PublicationSeriesTitle'] ?? [];
403    }
404
405    /**
406     * Get the short (pre-subtitle) title of the record.
407     *
408     * @return string
409     */
410    public function getShortTitle()
411    {
412        return isset($this->fields['Title']) ?
413            $this->fields['Title'][0] : '';
414    }
415
416    /**
417     * Get the subtitle of the record.
418     *
419     * @return string
420     */
421    public function getSubtitle()
422    {
423        return isset($this->fields['Subtitle']) ?
424            $this->fields['Subtitle'][0] : '';
425    }
426
427    /**
428     * Get an array of summary strings for the record.
429     *
430     * @return array
431     */
432    public function getSummary()
433    {
434        return $this->fields['Abstract'] ?? [];
435    }
436
437    /**
438     * Returns one of three things: a full URL to a thumbnail preview of the record
439     * if an image is available in an external system; an array of parameters to
440     * send to VuFind's internal cover generator if no fixed URL exists; or false
441     * if no thumbnail can be generated.
442     *
443     * @param string $size Size of thumbnail (small, medium or large -- small is
444     * default).
445     *
446     * @return string|array|bool
447     */
448    public function getThumbnail($size = 'small')
449    {
450        $params = parent::getThumbnail($size);
451
452        // Support thumbnails embedded in the Summon record when no unique identifier
453        // is found... (We don't use them in cases where we have an identifier, since
454        // we want to allow these to be passed to configured external services).
455        if (
456            !isset($params['oclc']) && !isset($params['issn'])
457            && !isset($params['isbn']) && !isset($params['upc'])
458        ) {
459            if ($size === 'small' && isset($this->fields['thumbnail_s'][0])) {
460                return ['proxy' => $this->fields['thumbnail_s'][0]];
461            } elseif (isset($this->fields['thumbnail_m'][0])) {
462                return ['proxy' => $this->fields['thumbnail_m'][0]];
463            }
464        }
465
466        $formats = $this->getFormats();
467        if (!empty($formats)) {
468            $params['contenttype'] = $formats[0];
469        }
470        return $params;
471    }
472
473    /**
474     * Get the full title of the record.
475     *
476     * @return string
477     */
478    public function getTitle()
479    {
480        $title = $this->getShortTitle();
481        $sub = $this->getSubtitle();
482        $title = empty($sub) ? $title : "{$title}{$sub}";
483        return str_replace(
484            ['{{{{START_HILITE}}}}', '{{{{END_HILITE}}}}'],
485            '',
486            $title
487        );
488    }
489
490    /**
491     * Get an array of lines from the table of contents.
492     *
493     * @return array
494     */
495    public function getTOC()
496    {
497        return $this->fields['TableOfContents'] ?? [];
498    }
499
500    /**
501     * Return an array of associative URL arrays with one or more of the following
502     * keys:
503     *
504     * <li>
505     *   <ul>desc: URL description text to display (optional)</ul>
506     *   <ul>url: fully-formed URL (required if 'route' is absent)</ul>
507     *   <ul>route: VuFind route to build URL with (required if 'url' is absent)</ul>
508     *   <ul>routeParams: Parameters for route (optional)</ul>
509     *   <ul>queryString: Query params to append after building route (optional)</ul>
510     * </li>
511     *
512     * @return array
513     */
514    public function getURLs()
515    {
516        if (isset($this->fields['link'])) {
517            $msg = $this->hasFullText() ? 'Get full text' : 'Get more information';
518            return [
519                ['url' => $this->fields['link'], 'desc' => $this->translate($msg)],
520            ];
521        }
522        $retVal = [];
523        if (isset($this->fields['url']) && is_array($this->fields['url'])) {
524            foreach ($this->fields['url'] as $desc => $url) {
525                $retVal[] = ['url' => $url, 'desc' => $desc];
526            }
527        }
528        return $retVal;
529    }
530
531    /**
532     * Return the unique identifier of this record within the Solr index;
533     * useful for retrieving additional information (like tags and user
534     * comments) from the external MySQL database.
535     *
536     * @return string Unique identifier.
537     */
538    public function getUniqueID()
539    {
540        return $this->fields['ID'][0];
541    }
542
543    /**
544     * Get the title of the item that contains this record (i.e. MARC 773s of a
545     * journal).
546     *
547     * @return string
548     */
549    public function getContainerTitle()
550    {
551        return isset($this->fields['PublicationTitle'])
552            ? $this->fields['PublicationTitle'][0] : '';
553    }
554
555    /**
556     * Get the volume of the item that contains this record (i.e. MARC 773v of a
557     * journal).
558     *
559     * @return string
560     */
561    public function getContainerVolume()
562    {
563        return (isset($this->fields['Volume'])) ? $this->fields['Volume'][0] : '';
564    }
565
566    /**
567     * Get the issue of the item that contains this record (i.e. MARC 773l of a
568     * journal).
569     *
570     * @return string
571     */
572    public function getContainerIssue()
573    {
574        return (isset($this->fields['Issue'])) ? $this->fields['Issue'][0] : '';
575    }
576
577    /**
578     * Get the start page of the item that contains this record (i.e. MARC 773q of a
579     * journal).
580     *
581     * @return string
582     */
583    public function getContainerStartPage()
584    {
585        return (isset($this->fields['StartPage']))
586            ? $this->fields['StartPage'][0] : '';
587    }
588
589    /**
590     * Get the end page of the item that contains this record.
591     *
592     * @return string
593     */
594    public function getContainerEndPage()
595    {
596        if (isset($this->fields['EndPage'])) {
597            return $this->fields['EndPage'][0];
598        } elseif (
599            isset($this->fields['PageCount'])
600            && $this->fields['PageCount'] > 1
601            && intval($this->fields['StartPage'][0]) > 0
602        ) {
603            return $this->fields['StartPage'][0] + $this->fields['PageCount'][0] - 1;
604        }
605        return $this->getContainerStartPage();
606    }
607
608    /**
609     * Get a full, free-form reference to the context of the item that contains this
610     * record (i.e. volume, year, issue, pages).
611     *
612     * @return string
613     */
614    public function getContainerReference()
615    {
616        $str = '';
617        $vol = $this->getContainerVolume();
618        if (!empty($vol)) {
619            $str .= $this->translate('citation_volume_abbrev')
620                . ' ' . $vol;
621        }
622        $no = $this->getContainerIssue();
623        if (!empty($no)) {
624            if (strlen($str) > 0) {
625                $str .= '; ';
626            }
627            $str .= $this->translate('citation_issue_abbrev')
628                . ' ' . $no;
629        }
630        $start = $this->getContainerStartPage();
631        if (!empty($start)) {
632            if (strlen($str) > 0) {
633                $str .= '; ';
634            }
635            $end = $this->getContainerEndPage();
636            if ($start == $end) {
637                $str .= $this->translate('citation_singlepage_abbrev')
638                    . ' ' . $start;
639            } else {
640                $str .= $this->translate('citation_multipage_abbrev')
641                    . ' ' . $start . ' - ' . $end;
642            }
643        }
644        return $str;
645    }
646
647    /**
648     * Does this record have full text access?
649     *
650     * @return bool
651     */
652    public function hasFullText()
653    {
654        return (bool)($this->fields['hasFullText'] ?? false);
655    }
656
657    /**
658     * Is this an open access record?
659     *
660     * @return bool
661     */
662    public function isOpenAccess()
663    {
664        return (bool)($this->fields['IsOpenAccess'] ?? false);
665    }
666}