Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
46.00% covered (danger)
46.00%
23 / 50
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Router
46.00% covered (danger)
46.00%
23 / 50
66.67% covered (warning)
66.67%
2 / 3
69.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUrl
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getMetadata
34.15% covered (danger)
34.15%
14 / 41
0.00% covered (danger)
0.00%
0 / 1
79.26
1<?php
2
3/**
4 * Cover image router
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2016.
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  Cover_Generator
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/configuration:external_content Wiki
28 */
29
30namespace VuFind\Cover;
31
32use VuFind\Cover\Loader as CoverLoader;
33use VuFind\RecordDriver\AbstractBase as RecordDriver;
34
35use function get_class;
36use function is_array;
37
38/**
39 * Cover image router
40 *
41 * @category VuFind
42 * @package  Cover_Generator
43 * @author   Demian Katz <demian.katz@villanova.edu>
44 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
45 * @link     https://vufind.org/wiki/configuration:external_content Wiki
46 */
47class Router implements \Laminas\Log\LoggerAwareInterface
48{
49    use \VuFind\Log\LoggerAwareTrait;
50
51    /**
52     * Base URL for dynamic cover images.
53     *
54     * @var string
55     */
56    protected $dynamicUrl;
57
58    /**
59     * Cover loader
60     *
61     * @var CoverLoader
62     */
63    protected $coverLoader;
64
65    /**
66     * Constructor
67     *
68     * @param string      $url         Base URL for dynamic cover images.
69     * @param CoverLoader $coverLoader Cover loader
70     */
71    public function __construct($url, CoverLoader $coverLoader)
72    {
73        $this->dynamicUrl = $url;
74        $this->coverLoader = $coverLoader;
75    }
76
77    /**
78     * Generate a thumbnail URL (return false if unsupported; return null to indicate
79     * that a subsequent AJAX check is needed).
80     *
81     * @param RecordDriver $driver         Record driver
82     * @param string       $size           Size of thumbnail (small, medium or large;
83     * small is default).
84     * @param bool         $resolveDynamic Should we resolve dynamic cover data into
85     * a URL (true) or simply return false (false)?
86     * @param bool         $testLoadImage  If true the function will try to load the
87     * cover image in advance and returns false in case no image could be loaded
88     *
89     * @return string|false|null
90     */
91    public function getUrl(
92        RecordDriver $driver,
93        $size = 'small',
94        $resolveDynamic = true,
95        $testLoadImage = false
96    ) {
97        $metadata = $this->getMetadata(
98            $driver,
99            $size,
100            $resolveDynamic,
101            $testLoadImage
102        );
103        // getMetadata could return null or false, that is the reason we are
104        // respecting the returned value - in case it is not empty array to be on
105        // safe side and not return bad type here
106        return $metadata['url'] ?? (!is_array($metadata) ? $metadata : false);
107    }
108
109    /**
110     * Generate a thumbnail metadata (return false if unsupported; return null to
111     * indicate that a subsequent AJAX check is needed).
112     *
113     * @param RecordDriver $driver         Record driver
114     * @param string       $size           Size of thumbnail (small, medium or large;
115     * small is default).
116     * @param bool         $resolveDynamic Should we resolve dynamic cover data into
117     * a URL (true) or simply return false (false)?
118     * @param bool         $testLoadImage  If true the function will try to load the
119     * cover image in advance and returns false in case no image could be loaded
120     * @param bool         $ajax           True if the function is called from ajax
121     * handler
122     *
123     * @return false|array|null
124     */
125    public function getMetadata(
126        RecordDriver $driver,
127        $size = 'small',
128        $resolveDynamic = true,
129        $testLoadImage = false,
130        $ajax = false
131    ) {
132        // Try to build thumbnail:
133        $thumb = $driver->tryMethod('getThumbnail', [$size]);
134
135        // No thumbnail?  Return false:
136        if (empty($thumb)) {
137            return false;
138        }
139
140        // Array? It's parameters to send to the cover generator:
141        if (is_array($thumb)) {
142            if (!$resolveDynamic) {
143                return null;
144            }
145            $dynamicUrl =  $this->dynamicUrl . '?' . http_build_query($thumb);
146        } else {
147            return ['url' => $thumb];
148        }
149
150        $settings = is_array($thumb) ? array_merge($thumb, ['size' => $size])
151            : ['size' => $size];
152        $handlers = $this->coverLoader->getHandlers();
153        $ids = $this->coverLoader->getIdentifiersForSettings($settings);
154        foreach ($handlers as $handler) {
155            $backlinkLocations
156                = $handler['handler']->getMandatoryBacklinkLocations();
157            if (!empty($backlinkLocations) && !$ajax) {
158                $this->logWarning(
159                    'Cover provider ' . get_class($handler['handler'])
160                    . ' needs ajaxcovers setting to be on'
161                );
162                continue;
163            }
164            try {
165                // Is the current provider appropriate for the available data?
166                if (
167                    $handler['handler']->supports($ids)
168                    && $handler['handler']->useDirectUrls()
169                ) {
170                    $nextMetadata = $handler['handler']
171                        ->getMetadata($handler['key'], $size, $ids);
172                    if (!empty($nextMetadata)) {
173                        $nextMetadata['backlink_locations'] = $backlinkLocations;
174                        $metadata = $nextMetadata;
175                        break;
176                    }
177                }
178            } catch (\Exception $e) {
179                $this->debug(
180                    $e::class . ' during processing of '
181                    . get_class($handler['handler']) . ': ' . $e->getMessage()
182                );
183            }
184        }
185
186        if (isset($metadata)) {
187            return $metadata;
188        }
189        if ($testLoadImage) {
190            $this->coverLoader->loadImage($settings);
191            if ($this->coverLoader->hasLoadedUnavailable()) {
192                return false;
193            }
194        }
195        return ['url' => $dynamicUrl];
196    }
197}