Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
19.10% |
17 / 89 |
|
45.45% |
10 / 22 |
CRAP | |
0.00% |
0 / 1 |
AbstractBase | |
19.10% |
17 / 89 |
|
45.45% |
10 / 22 |
574.16 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setRawData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRawData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getBreadcrumb | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getUniqueID | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getComments | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getSortTitle | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getTags | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
addTags | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
deleteTags | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getRatingData | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
getRatingBreakdown | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
addOrUpdateRating | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getListNotes | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
getContainingLists | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
supportsAjaxStatus | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
supportsOpenUrl | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
supportsCoinsOpenUrl | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isRatingAllowed | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setExtraDetail | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCitationFormats | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
5 | |||
getSupportedCitationFormats | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getExtraDetail | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
tryMethod | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * Abstract base record model. |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) Villanova University 2010-2024. |
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 Main Page |
28 | */ |
29 | |
30 | namespace VuFind\RecordDriver; |
31 | |
32 | use VuFind\Db\Service\CommentsServiceInterface; |
33 | use VuFind\Db\Service\TagServiceInterface; |
34 | use VuFind\Db\Service\UserListServiceInterface; |
35 | use VuFind\XSLT\Import\VuFind as ArticleStripper; |
36 | |
37 | use function is_callable; |
38 | |
39 | /** |
40 | * Abstract base record model. |
41 | * |
42 | * This abstract class defines the basic methods for modeling a record in VuFind. |
43 | * |
44 | * @category VuFind |
45 | * @package RecordDrivers |
46 | * @author Demian Katz <demian.katz@villanova.edu> |
47 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
48 | * @link https://vufind.org Main Page |
49 | */ |
50 | abstract class AbstractBase implements |
51 | \VuFind\Db\Service\DbServiceAwareInterface, |
52 | \VuFind\Db\Table\DbTableAwareInterface, |
53 | \VuFind\I18n\Translator\TranslatorAwareInterface, |
54 | \VuFindSearch\Response\RecordInterface |
55 | { |
56 | use \VuFind\Db\Service\DbServiceAwareTrait; |
57 | use \VuFind\Db\Table\DbTableAwareTrait; |
58 | use \VuFind\I18n\Translator\TranslatorAwareTrait; |
59 | use \VuFindSearch\Response\RecordTrait; |
60 | |
61 | /** |
62 | * For storing extra data with record |
63 | * |
64 | * @var array |
65 | */ |
66 | protected $extraDetails = []; |
67 | |
68 | /** |
69 | * Main VuFind configuration |
70 | * |
71 | * @var \Laminas\Config\Config |
72 | */ |
73 | protected $mainConfig; |
74 | |
75 | /** |
76 | * Record-specific configuration |
77 | * |
78 | * @var \Laminas\Config\Config |
79 | */ |
80 | protected $recordConfig; |
81 | |
82 | /** |
83 | * Raw data |
84 | * |
85 | * @var array |
86 | */ |
87 | protected $fields = []; |
88 | |
89 | /** |
90 | * Cache for rating data |
91 | * |
92 | * @var array |
93 | */ |
94 | protected $ratingCache = []; |
95 | |
96 | /** |
97 | * Constructor |
98 | * |
99 | * @param \Laminas\Config\Config $mainConfig VuFind main configuration (omit |
100 | * for built-in defaults) |
101 | * @param \Laminas\Config\Config $recordConfig Record-specific configuration file |
102 | * (omit to use $mainConfig as $recordConfig) |
103 | */ |
104 | public function __construct($mainConfig = null, $recordConfig = null) |
105 | { |
106 | $this->mainConfig = $mainConfig; |
107 | $this->recordConfig = $recordConfig ?? $mainConfig; |
108 | } |
109 | |
110 | /** |
111 | * Set raw data to initialize the object. |
112 | * |
113 | * @param mixed $data Raw data representing the record; Record Model |
114 | * objects are normally constructed by Record Driver objects using data |
115 | * passed in from a Search Results object. The exact nature of the data may |
116 | * vary depending on the data source -- the important thing is that the |
117 | * Record Driver + Search Results objects work together correctly. |
118 | * |
119 | * @return void |
120 | */ |
121 | public function setRawData($data) |
122 | { |
123 | $this->fields = $data; |
124 | } |
125 | |
126 | /** |
127 | * Retrieve raw data from object (primarily for use in staff view and |
128 | * autocomplete; avoid using whenever possible). |
129 | * |
130 | * @return mixed |
131 | */ |
132 | public function getRawData() |
133 | { |
134 | return $this->fields; |
135 | } |
136 | |
137 | /** |
138 | * Get text that can be displayed to represent this record in breadcrumbs. |
139 | * |
140 | * @return string Breadcrumb text to represent this record. |
141 | */ |
142 | abstract public function getBreadcrumb(); |
143 | |
144 | /** |
145 | * Return the unique identifier of this record for retrieving additional |
146 | * information (like tags and user comments) from the external MySQL database. |
147 | * |
148 | * @return string Unique identifier. |
149 | */ |
150 | abstract public function getUniqueID(); |
151 | |
152 | /** |
153 | * Get comments associated with this record. |
154 | * |
155 | * @return array |
156 | * |
157 | * @deprecated Use CommentsServiceInterface::getRecordComments() |
158 | */ |
159 | public function getComments() |
160 | { |
161 | return $this->getDbService(CommentsServiceInterface::class)->getRecordComments( |
162 | $this->getUniqueId(), |
163 | $this->getSourceIdentifier() |
164 | ); |
165 | } |
166 | |
167 | /** |
168 | * Get a sortable title for the record (i.e. no leading articles). |
169 | * |
170 | * @return string |
171 | */ |
172 | public function getSortTitle() |
173 | { |
174 | // Child classes should override this with smarter behavior, and the "strip |
175 | // articles" logic probably belongs in a more appropriate place, but for now |
176 | // in the absence of a better plan, we'll just use the XSLT Importer's strip |
177 | // articles functionality. |
178 | return ArticleStripper::stripArticles($this->getBreadcrumb()); |
179 | } |
180 | |
181 | /** |
182 | * Get tags associated with this record. |
183 | * |
184 | * @param int $list_id ID of list to load tags from (null for all lists) |
185 | * @param int $user_id ID of user to load tags from (null for all users) |
186 | * @param string $sort Sort type ('count' or 'tag') |
187 | * @param int $ownerId ID of user to check for ownership |
188 | * |
189 | * @return array |
190 | * |
191 | * @deprecated Use TagServiceInterface::getRecordTags() or TagServiceInterface::getRecordTagsFromFavorites() |
192 | * or TagServiceInterface::getRecordTagsNotInFavorites() |
193 | */ |
194 | public function getTags( |
195 | $list_id = null, |
196 | $user_id = null, |
197 | $sort = 'count', |
198 | $ownerId = null |
199 | ) { |
200 | return $this->getDbTable('Tags')->getForResource( |
201 | $this->getUniqueId(), |
202 | $this->getSourceIdentifier(), |
203 | 0, |
204 | $list_id, |
205 | $user_id, |
206 | $sort, |
207 | $ownerId |
208 | ); |
209 | } |
210 | |
211 | /** |
212 | * Add tags to the record. |
213 | * |
214 | * @param UserEntityInterface $user The user posting the tag |
215 | * @param array $tags The user-provided tags |
216 | * |
217 | * @return void |
218 | * |
219 | * @deprecated Use \VuFind\Tags\TagsService::linkTagsToRecord() |
220 | */ |
221 | public function addTags($user, $tags) |
222 | { |
223 | $resources = $this->getDbTable('Resource'); |
224 | $resource = $resources->findResource( |
225 | $this->getUniqueId(), |
226 | $this->getSourceIdentifier() |
227 | ); |
228 | foreach ($tags as $tag) { |
229 | $resource->addTag($tag, $user); |
230 | } |
231 | } |
232 | |
233 | /** |
234 | * Remove tags from the record. |
235 | * |
236 | * @param UserEntityInterface $user The user posting the tag |
237 | * @param array $tags The user-provided tags |
238 | * |
239 | * @return void |
240 | * |
241 | * @deprecated Use \VuFind\Tags\TagsService::unlinkTagsFromRecord() |
242 | */ |
243 | public function deleteTags($user, $tags) |
244 | { |
245 | $resources = $this->getDbTable('Resource'); |
246 | $resource = $resources->findResource( |
247 | $this->getUniqueId(), |
248 | $this->getSourceIdentifier() |
249 | ); |
250 | foreach ($tags as $tag) { |
251 | $resource->deleteTag($tag, $user); |
252 | } |
253 | } |
254 | |
255 | /** |
256 | * Get rating information for this record. |
257 | * |
258 | * Returns an array with the following keys: |
259 | * |
260 | * rating - average rating (0-100) |
261 | * count - count of ratings |
262 | * |
263 | * @param ?int $userId User ID, or null for all users |
264 | * |
265 | * @return array |
266 | * |
267 | * @deprecated Use \VuFind\Ratings\RatingsService::getRatingData() |
268 | */ |
269 | public function getRatingData(?int $userId = null) |
270 | { |
271 | // Cache data since comments list may ask for same information repeatedly: |
272 | $cacheKey = $userId ?? '-'; |
273 | if (!isset($this->ratingCache[$cacheKey])) { |
274 | $ratingsService = $this->getDbService( |
275 | \VuFind\Db\Service\RatingsServiceInterface::class |
276 | ); |
277 | $this->ratingCache[$cacheKey] = $ratingsService->getRecordRatings( |
278 | $this->getUniqueId(), |
279 | $this->getSourceIdentifier(), |
280 | $userId |
281 | ); |
282 | } |
283 | return $this->ratingCache[$cacheKey]; |
284 | } |
285 | |
286 | /** |
287 | * Get rating breakdown for this record. |
288 | * |
289 | * Returns an array with the following keys: |
290 | * |
291 | * rating - average rating (0-100) |
292 | * count - count of ratings |
293 | * groups - grouped counts |
294 | * |
295 | * @param array $groups Group definition (key => [min, max]) |
296 | * |
297 | * @return array |
298 | * |
299 | * @deprecated Use \VuFind\Ratings\RatingsService::getRatingBreakdown() |
300 | */ |
301 | public function getRatingBreakdown(array $groups) |
302 | { |
303 | return $this->getDbService(\VuFind\Db\Service\RatingsServiceInterface::class) |
304 | ->getCountsForRecord( |
305 | $this->getUniqueId(), |
306 | $this->getSourceIdentifier(), |
307 | $groups |
308 | ); |
309 | } |
310 | |
311 | /** |
312 | * Add or update user's rating for the record. |
313 | * |
314 | * @param int $userId ID of the user posting the rating |
315 | * @param ?int $rating The user-provided rating, or null to clear any existing |
316 | * rating |
317 | * |
318 | * @return void |
319 | * |
320 | * @deprecated Use \VuFind\Ratings\RatingsService::saveRating() |
321 | */ |
322 | public function addOrUpdateRating(int $userId, ?int $rating): void |
323 | { |
324 | // Clear rating cache: |
325 | $this->ratingCache = []; |
326 | $resources = $this->getDbTable('Resource'); |
327 | $resource = $resources->findResource( |
328 | $this->getUniqueId(), |
329 | $this->getSourceIdentifier() |
330 | ); |
331 | $this->getDbService(\VuFind\Db\Service\RatingsServiceInterface::class) |
332 | ->addOrUpdateRating($resource, $userId, $rating); |
333 | } |
334 | |
335 | /** |
336 | * Get notes associated with this record in user lists. |
337 | * |
338 | * @param int $list_id ID of list to load tags from (null for all lists) |
339 | * @param int $user_id ID of user to load tags from (null for all users) |
340 | * |
341 | * @return array |
342 | * |
343 | * @deprecated Use \VuFind\View\Helper\Root\Record::getListNotes() |
344 | */ |
345 | public function getListNotes($list_id = null, $user_id = null) |
346 | { |
347 | $db = $this->getDbTable('UserResource'); |
348 | $data = $db->getSavedData( |
349 | $this->getUniqueId(), |
350 | $this->getSourceIdentifier(), |
351 | $list_id, |
352 | $user_id |
353 | ); |
354 | $notes = []; |
355 | foreach ($data as $current) { |
356 | if (!empty($current->notes)) { |
357 | $notes[] = $current->notes; |
358 | } |
359 | } |
360 | return $notes; |
361 | } |
362 | |
363 | /** |
364 | * Get a list of lists containing this record. |
365 | * |
366 | * @param int $user_id ID of user to load tags from (null for all users) |
367 | * |
368 | * @return array |
369 | * |
370 | * @deprecated Use UserListServiceInterface::getListsContainingRecord() |
371 | */ |
372 | public function getContainingLists($user_id = null) |
373 | { |
374 | return $this->getDbService(UserListServiceInterface::class)->getListsContainingRecord( |
375 | $this->getUniqueId(), |
376 | $this->getSourceIdentifier(), |
377 | $user_id |
378 | ); |
379 | } |
380 | |
381 | /** |
382 | * Returns true if the record supports real-time AJAX status lookups. |
383 | * |
384 | * @return bool |
385 | */ |
386 | public function supportsAjaxStatus() |
387 | { |
388 | return false; |
389 | } |
390 | |
391 | /** |
392 | * Checks the current record if it's supported for generating OpenURLs. |
393 | * |
394 | * @return bool |
395 | */ |
396 | public function supportsOpenUrl() |
397 | { |
398 | return true; |
399 | } |
400 | |
401 | /** |
402 | * Checks the current record if it's supported for generating COinS-OpenURLs. |
403 | * |
404 | * @return bool |
405 | */ |
406 | public function supportsCoinsOpenUrl() |
407 | { |
408 | return true; |
409 | } |
410 | |
411 | /** |
412 | * Check if rating the record is allowed. |
413 | * |
414 | * @return bool |
415 | */ |
416 | public function isRatingAllowed(): bool |
417 | { |
418 | return !empty($this->recordConfig->Social->rating); |
419 | } |
420 | |
421 | /** |
422 | * Store a piece of supplemental information in the record driver. |
423 | * |
424 | * @param string $key Name of stored information |
425 | * @param mixed $val Information to store |
426 | * |
427 | * @return void |
428 | */ |
429 | public function setExtraDetail($key, $val) |
430 | { |
431 | $this->extraDetails[$key] = $val; |
432 | } |
433 | |
434 | /** |
435 | * Get an array of supported, user-activated citation formats. |
436 | * |
437 | * @return array Strings representing citation formats. |
438 | */ |
439 | public function getCitationFormats() |
440 | { |
441 | $formatSetting = $this->mainConfig->Record->citation_formats ?? true; |
442 | |
443 | // Default behavior: use all supported options. |
444 | if ($formatSetting === true || $formatSetting === 'true') { |
445 | return $this->getSupportedCitationFormats(); |
446 | } |
447 | |
448 | // Citations disabled: |
449 | if ($formatSetting === false || $formatSetting === 'false') { |
450 | return []; |
451 | } |
452 | |
453 | // Filter based on include list: |
454 | $allowed = array_map('trim', explode(',', $formatSetting)); |
455 | return array_intersect($allowed, $this->getSupportedCitationFormats()); |
456 | } |
457 | |
458 | /** |
459 | * Get an array of strings representing citation formats supported |
460 | * by this record's data (empty if none). For possible legal values, |
461 | * see /application/themes/root/helpers/Citation.php. |
462 | * |
463 | * @return array Strings representing citation formats. |
464 | */ |
465 | protected function getSupportedCitationFormats() |
466 | { |
467 | return []; |
468 | } |
469 | |
470 | /** |
471 | * Retrieve a piece of supplemental information stored using setExtraDetail(). |
472 | * |
473 | * @param string $key Name of stored information |
474 | * |
475 | * @return mixed |
476 | */ |
477 | public function getExtraDetail($key) |
478 | { |
479 | return $this->extraDetails[$key] ?? null; |
480 | } |
481 | |
482 | /** |
483 | * Try to call the requested method and return null if it is unavailable; this is |
484 | * useful for checking for the existence of get methods for particular types of |
485 | * data without causing fatal errors. |
486 | * |
487 | * @param string $method Name of method to call. |
488 | * @param array $params Array of parameters to pass to method. |
489 | * @param mixed $default A default value to return if the method is not |
490 | * callable |
491 | * |
492 | * @return mixed |
493 | */ |
494 | public function tryMethod($method, $params = [], $default = null) |
495 | { |
496 | return is_callable([$this, $method]) ? $this->$method(...$params) : $default; |
497 | } |
498 | } |