Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
Syndetics
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
156
0.00% covered (danger)
0.00%
0 / 1
 loadByIsbn
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3/**
4 * Syndetics review content loader.
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  Content
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 Wiki
28 */
29
30namespace VuFind\Content\Reviews;
31
32/**
33 * Syndetics review content loader.
34 *
35 * @category VuFind
36 * @package  Content
37 * @author   Demian Katz <demian.katz@villanova.edu>
38 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
39 * @link     https://vufind.org/wiki/development Wiki
40 */
41class Syndetics extends \VuFind\Content\AbstractSyndetics
42{
43    /**
44     * List of syndetic review sources
45     *
46     * @var array
47     */
48    protected $sourceList = [
49        'CHREVIEW' => ['title' => 'Choice Review',
50                            'file' => 'CHREVIEW.XML',
51                            'div' => '<div id="syn_chreview"></div>'],
52        'NYREVIEW' => ['title' => 'New York Times Review',
53                            'file' => 'NYREVIEW.XML',
54                            'div' => '<div id="syn_nyreview"></div>'],
55        'BLREVIEW' => ['title' => 'Booklist Review',
56                            'file' => 'BLREVIEW.XML',
57                            'div' => '<div id="syn_blreview"></div>'],
58        'PWREVIEW' => ['title' => "Publisher's Weekly Review",
59                            'file' => 'PWREVIEW.XML',
60                            'div' => '<div id="syn_pwreview"></div>'],
61        'LJREVIEW' => ['title' => 'Library Journal Review',
62                            'file' => 'LJREVIEW.XML',
63                            'div' => '<div id="syn_ljreview"></div>'],
64        'SLJREVIEW' => ['title' => 'School Library Journal Review',
65                            'file' => 'SLJREVIEW.XML',
66                            'div' => '<div id="syn_sljreview"></div>'],
67        'HBREVIEW' => ['title' => 'Horn Book Review',
68                            'file' => 'HBREVIEW.XML',
69                            'div' => '<div id="syn_hbreview"></div>'],
70        'KIRKREVIEW' => ['title' => 'Kirkus Book Review',
71                            'file' => 'KIRKREVIEW.XML',
72                            'div' => '<div id="syn_kireview"></div>'],
73        'CRITICASREVIEW' => ['title' => 'Criticas Review',
74                            'file' => 'CRITICASREVIEW.XML',
75                            'div' => '<div id="syn_criticasreview"></div>'],
76        // These last two entries are probably typos -- retained for legacy
77        // compatibility just in case they're actually used for something!
78        'KIREVIEW' => ['title' => 'Kirkus Book Review',
79                            'file' => 'KIREVIEW.XML'],
80        'CRITICASEREVIEW' => ['title' => 'Criti Case Review',
81                            'file' => 'CRITICASEREVIEW.XML'],
82    ];
83
84    /**
85     * This method is responsible for connecting to Syndetics and abstracting
86     * reviews from multiple providers.
87     *
88     * It first queries the master url for the ISBN entry seeking a review URL.
89     * If a review URL is found, the script will then use HTTP request to
90     * retrieve the script. The script will then parse the review according to
91     * US MARC (I believe). It will provide a link to the URL master HTML page
92     * for more information.
93     * Configuration:  Sources are processed in order - refer to $sourceList above.
94     * If your library prefers one reviewer over another change the order.
95     * If your library does not like a reviewer, remove it. If there are more
96     * syndetics reviewers add another entry.
97     *
98     * @param string           $key     API key (unused here)
99     * @param \VuFindCode\ISBN $isbnObj ISBN object
100     *
101     * @throws \Exception
102     * @return array     Returns array with review data.
103     * @author Joel Timothy Norman <joel.t.norman@wmich.edu>
104     * @author Andrew Nagy <vufind-tech@lists.sourceforge.net>
105     */
106    public function loadByIsbn($key, \VuFindCode\ISBN $isbnObj)
107    {
108        // Initialize return value
109        $review = [];
110
111        // Find out if there are any reviews
112        $isbn = $this->getIsbn10($isbnObj);
113        $url = $this->getIsbnUrl($isbn, $key);
114        $result = $this->getHttpClient($url)->send();
115        if (!$result->isSuccess()) {
116            return $review;
117        }
118
119        // Test XML Response
120        if (!($xmldoc = $this->xmlToDOMDocument($result->getBody()))) {
121            throw new \Exception('Invalid XML');
122        }
123
124        $i = 0;
125        foreach ($this->sourceList as $source => $sourceInfo) {
126            $nodes = $xmldoc->getElementsByTagName($source);
127            if ($nodes->length) {
128                // Load reviews
129                $url = $this->getIsbnUrl($isbn, $key, $sourceInfo['file']);
130                $result2 = $this->getHttpClient($url)->send();
131                if (!$result2->isSuccess()) {
132                    continue;
133                }
134
135                // Test XML Response
136                $xmldoc2 = $this->xmlToDOMDocument($result2->getBody());
137                if (!$xmldoc2) {
138                    throw new \Exception('Invalid XML');
139                }
140
141                // If we have syndetics plus, we don't actually want the content
142                // we'll just stick in the relevant div
143                if ($this->usePlus) {
144                    $review[$i]['Content'] = $sourceInfo['div'];
145                } else {
146                    // Get the marc field for reviews (520)
147                    $nodes = $xmldoc2->GetElementsbyTagName('Fld520');
148                    if (!$nodes->length) {
149                        // Skip reviews with missing text
150                        continue;
151                    }
152                    // Decode the content and strip unwanted <a> tags:
153                    $review[$i]['Content'] = preg_replace(
154                        '/<a>|<a [^>]*>|<\/a>/',
155                        '',
156                        html_entity_decode($xmldoc2->saveXML($nodes->item(0)))
157                    );
158
159                    // Get the marc field for copyright (997)
160                    $nodes = $xmldoc2->GetElementsbyTagName('Fld997');
161                    if ($nodes->length) {
162                        $review[$i]['Copyright']
163                            = html_entity_decode($xmldoc2->saveXML($nodes->item(0)));
164                    } else {
165                        $review[$i]['Copyright'] = null;
166                    }
167
168                    if ($review[$i]['Copyright']) {  //stop duplicate copyrights
169                        $location = strripos(
170                            $review[0]['Content'],
171                            (string)$review[0]['Copyright']
172                        );
173                        if ($location > 0) {
174                            $review[$i]['Content']
175                                = substr($review[0]['Content'], 0, $location);
176                        }
177                    }
178                }
179
180                //change the xml to actual title:
181                $review[$i]['Source'] = $sourceInfo['title'];
182
183                $review[$i]['ISBN'] = $isbn;
184
185                $i++;
186            }
187        }
188
189        return $review;
190    }
191}