Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
PrimoBackendFactory
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 10
420
0.00% covered (danger)
0.00%
0 / 1
 __invoke
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 createBackend
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 createListeners
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 createConnector
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 createRestConnector
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
20
 createQueryBuilder
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 createRecordCollectionFactory
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getInjectOnCampusListener
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getPermissionHandler
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getHttpOptions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Factory for Primo Central backends.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2013.
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  Search
25 * @author   David Maus <maus@hab.de>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org Main Site
28 */
29
30namespace VuFind\Search\Factory;
31
32use LmcRbacMvc\Service\AuthorizationService;
33use Psr\Container\ContainerInterface;
34use VuFind\Search\Primo\InjectOnCampusListener;
35use VuFind\Search\Primo\PrimoPermissionHandler;
36use VuFindSearch\Backend\Primo\Backend;
37use VuFindSearch\Backend\Primo\Connector;
38use VuFindSearch\Backend\Primo\ConnectorInterface;
39use VuFindSearch\Backend\Primo\QueryBuilder;
40use VuFindSearch\Backend\Primo\Response\RecordCollectionFactory;
41use VuFindSearch\Backend\Primo\RestConnector;
42
43/**
44 * Factory for Primo Central backends.
45 *
46 * @category VuFind
47 * @package  Search
48 * @author   David Maus <maus@hab.de>
49 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
50 * @link     https://vufind.org Main Site
51 */
52class PrimoBackendFactory extends AbstractBackendFactory
53{
54    use SharedListenersTrait;
55
56    /**
57     * Logger.
58     *
59     * @var \Laminas\Log\LoggerInterface
60     */
61    protected $logger;
62
63    /**
64     * Primo configuration
65     *
66     * @var \Laminas\Config\Config
67     */
68    protected $primoConfig;
69
70    /**
71     * Primo backend class
72     *
73     * @var string
74     */
75    protected $backendClass = Backend::class;
76
77    /**
78     * Primo legacy brief search connector class
79     *
80     * @var string
81     */
82    protected $connectorClass = Connector::class;
83
84    /**
85     * Primo REST API connector class
86     *
87     * @var string
88     */
89    protected $restConnectorClass = RestConnector::class;
90
91    /**
92     * Create service
93     *
94     * @param ContainerInterface $sm      Service manager
95     * @param string             $name    Requested service name (unused)
96     * @param array              $options Extra options (unused)
97     *
98     * @return Backend
99     *
100     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
101     */
102    public function __invoke(ContainerInterface $sm, $name, array $options = null)
103    {
104        $this->setup($sm);
105        $configReader = $this->serviceLocator
106            ->get(\VuFind\Config\PluginManager::class);
107        $this->primoConfig = $configReader->get('Primo');
108        if ($this->serviceLocator->has(\VuFind\Log\Logger::class)) {
109            $this->logger = $this->serviceLocator->get(\VuFind\Log\Logger::class);
110        }
111
112        if (($this->primoConfig->General->api ?? 'legacy') === 'rest') {
113            $connector = $this->createRestConnector();
114        } else {
115            $connector = $this->createConnector();
116        }
117        $backend   = $this->createBackend($connector);
118
119        $this->createListeners($backend);
120
121        return $backend;
122    }
123
124    /**
125     * Create the Primo Central backend.
126     *
127     * @param ConnectorInterface $connector Connector
128     *
129     * @return Backend
130     */
131    protected function createBackend(ConnectorInterface $connector)
132    {
133        $backend = new $this->backendClass(
134            $connector,
135            $this->createRecordCollectionFactory()
136        );
137        $backend->setLogger($this->logger);
138        $backend->setQueryBuilder($this->createQueryBuilder());
139        return $backend;
140    }
141
142    /**
143     * Create listeners.
144     *
145     * @param Backend $backend Backend
146     *
147     * @return void
148     */
149    protected function createListeners(Backend $backend)
150    {
151        $events = $this->serviceLocator->get('SharedEventManager');
152
153        $this->getInjectOnCampusListener()->attach($events);
154
155        // Attach hide facet value listener:
156        $hfvListener = $this
157            ->getHideFacetValueListener($backend, $this->primoConfig);
158        if ($hfvListener) {
159            $hfvListener->attach($events);
160        }
161    }
162
163    /**
164     * Create the Primo Central legacy brief search connector.
165     *
166     * @return Connector
167     */
168    protected function createConnector()
169    {
170        // Get the PermissionHandler
171        $permHandler = $this->getPermissionHandler();
172
173        // Load url and credentials:
174        if (!isset($this->primoConfig->General->url)) {
175            throw new \Exception('Missing url in Primo.ini');
176        }
177        $instCode = isset($permHandler)
178            ? $permHandler->getInstCode()
179            : null;
180
181        // Create connector:
182        $connector = new $this->connectorClass(
183            $this->primoConfig->General->url,
184            $instCode,
185            $this->createHttpClient($this->primoConfig->General->timeout ?? 30)
186        );
187        $connector->setLogger($this->logger);
188        if ($cache = $this->createConnectorCache($this->primoConfig)) {
189            $connector->setCache($cache);
190        }
191        return $connector;
192    }
193
194    /**
195     * Create the Primo Central REST connector.
196     *
197     * @return Connector
198     */
199    protected function createRestConnector()
200    {
201        // Get the PermissionHandler
202        $permHandler = $this->getPermissionHandler();
203
204        // Load URLs and credentials:
205        if (empty($this->primoConfig->General->search_url)) {
206            throw new \Exception('Missing search_url in Primo.ini');
207        }
208        $instCode = isset($permHandler)
209            ? $permHandler->getInstCode()
210            : null;
211
212        $session = new \Laminas\Session\Container(
213            'Primo',
214            $this->serviceLocator->get(\Laminas\Session\SessionManager::class)
215        );
216
217        // Create connector:
218        $timeout = $this->primoConfig->General->timeout ?? 30;
219        $connector = new $this->restConnectorClass(
220            $this->primoConfig->General->jwt_url ?? '',
221            $this->primoConfig->General->search_url,
222            $instCode,
223            function (string $url) use ($timeout) {
224                return $this->createHttpClient(
225                    $timeout,
226                    $this->getHttpOptions($url),
227                    $url
228                );
229            },
230            $session
231        );
232        $connector->setLogger($this->logger);
233        if ($cache = $this->createConnectorCache($this->primoConfig)) {
234            $connector->setCache($cache);
235        }
236        return $connector;
237    }
238
239    /**
240     * Create the Primo query builder.
241     *
242     * @return QueryBuilder
243     */
244    protected function createQueryBuilder()
245    {
246        $builder = new QueryBuilder();
247        return $builder;
248    }
249
250    /**
251     * Create the record collection factory
252     *
253     * @return RecordCollectionFactory
254     */
255    protected function createRecordCollectionFactory()
256    {
257        $manager = $this->serviceLocator
258            ->get(\VuFind\RecordDriver\PluginManager::class);
259        $callback = function ($data) use ($manager) {
260            $driver = $manager->get('Primo');
261            $driver->setRawData($data);
262            return $driver;
263        };
264        return new RecordCollectionFactory($callback);
265    }
266
267    /**
268     * Get a OnCampus Listener
269     *
270     * @return InjectOnCampusListener
271     */
272    protected function getInjectOnCampusListener()
273    {
274        $listener = new InjectOnCampusListener($this->getPermissionHandler());
275        return $listener;
276    }
277
278    /**
279     * Get a PrimoPermissionHandler
280     *
281     * @return ?PrimoPermissionHandler
282     */
283    protected function getPermissionHandler(): ?PrimoPermissionHandler
284    {
285        if (isset($this->primoConfig->Institutions)) {
286            $permHandler = new PrimoPermissionHandler(
287                $this->primoConfig->Institutions
288            );
289            $permHandler->setAuthorizationService(
290                $this->serviceLocator->get(AuthorizationService::class)
291            );
292            return $permHandler;
293        }
294
295        // If no PermissionHandler can be set, return null
296        return null;
297    }
298
299    /**
300     * Get HTTP options for the client
301     *
302     * @param string $url URL being requested
303     *
304     * @return array
305     *
306     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
307     */
308    protected function getHttpOptions(string $url): array
309    {
310        return [];
311    }
312}