Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
70.45% covered (warning)
70.45%
31 / 44
50.00% covered (danger)
50.00%
4 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResourcePopulator
70.45% covered (warning)
70.45%
31 / 44
50.00% covered (danger)
50.00%
4 / 8
24.45
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOrCreateResourceForDriver
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getOrCreateResourceForRecordId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 createResourceForDriver
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createResourceForRecordId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createAndPersistResourceForDriver
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 createAndPersistResourceForRecordId
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 assignMetadata
82.14% covered (warning)
82.14%
23 / 28
0.00% covered (danger)
0.00%
0 / 1
8.36
1<?php
2
3/**
4 * Class for populating record rows in the resource table of the database
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 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  Record
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 Site
28 */
29
30namespace VuFind\Record;
31
32use VuFind\Date\Converter as DateConverter;
33use VuFind\Date\DateException;
34use VuFind\Db\Entity\ResourceEntityInterface;
35use VuFind\Db\Service\ResourceServiceInterface;
36use VuFind\RecordDriver\AbstractBase as RecordDriver;
37
38use function intval;
39use function strlen;
40
41/**
42 * Class for populating record rows in the resource table of the database
43 *
44 * @category VuFind
45 * @package  Record
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 Site
49 */
50class ResourcePopulator
51{
52    /**
53     * Constructor
54     *
55     * @param ResourceServiceInterface $resourceService Resource database service
56     * @param Loader                   $loader          Record loader
57     * @param DateConverter            $dateConverter   Date converter
58     *
59     * @return void
60     */
61    public function __construct(
62        protected ResourceServiceInterface $resourceService,
63        protected Loader $loader,
64        protected DateConverter $dateConverter
65    ) {
66    }
67
68    /**
69     * Retrieve an existing row matching the provided record driver if it exists; create, populate and persist it if
70     * it does not.
71     *
72     * @param RecordDriver $driver Record driver
73     *
74     * @return ResourceEntityInterface
75     */
76    public function getOrCreateResourceForDriver(RecordDriver $driver): ResourceEntityInterface
77    {
78        $resource = $this->resourceService
79            ->getResourceByRecordId($driver->getUniqueID(), $driver->getSourceIdentifier());
80        return $resource ? $resource : $this->createAndPersistResourceForDriver($driver);
81    }
82
83    /**
84     * Retrieve an existing row matching the provided id/source if it exists; create, populate and persist it if
85     * it does not.
86     *
87     * @param string $id     Record id
88     * @param string $source Record source
89     *
90     * @return ResourceEntityInterface
91     */
92    public function getOrCreateResourceForRecordId(string $id, string $source): ResourceEntityInterface
93    {
94        $resource = $this->resourceService->getResourceByRecordId($id, $source);
95        return $resource ? $resource : $this->createAndPersistResourceForRecordId($id, $source);
96    }
97
98    /**
99     * Create (but do not persist) a ResourceEntityInterface object populated with data from
100     * the provided record driver.
101     *
102     * @param RecordDriver $driver Record driver
103     *
104     * @return ResourceEntityInterface
105     */
106    public function createResourceForDriver(RecordDriver $driver): ResourceEntityInterface
107    {
108        return $this->assignMetadata($this->resourceService->createEntity(), $driver)
109            ->setRecordId($driver->getUniqueId())
110            ->setSource($driver->getSourceIdentifier());
111    }
112
113    /**
114     * Create (but do not persist) a ResourceEntityInterface object populated with data from
115     * the record driver looked up using the provided record ID and source.
116     *
117     * @param string $id     Record id
118     * @param string $source Record source
119     *
120     * @return ResourceEntityInterface
121     */
122    public function createResourceForRecordId(string $id, string $source): ResourceEntityInterface
123    {
124        return $this->createResourceForDriver($this->loader->load($id, $source));
125    }
126
127    /**
128     * Create and a ResourceEntityInterface object populated with data from the provided record driver.
129     *
130     * @param RecordDriver $driver Record driver
131     *
132     * @return ResourceEntityInterface
133     */
134    public function createAndPersistResourceForDriver(RecordDriver $driver): ResourceEntityInterface
135    {
136        $resource = $this->createResourceForDriver($driver);
137        $this->resourceService->persistEntity($resource);
138        return $resource;
139    }
140
141    /**
142     * Create and persist a ResourceEntityInterface object populated with data from the record driver
143     * looked up using the provided record ID and source.
144     *
145     * @param string $id     Record id
146     * @param string $source Record source
147     *
148     * @return ResourceEntityInterface
149     */
150    public function createAndPersistResourceForRecordId(string $id, string $source): ResourceEntityInterface
151    {
152        $resource = $this->createResourceForRecordId($id, $source);
153        $this->resourceService->persistEntity($resource);
154        return $resource;
155    }
156
157    /**
158     * Use a record driver to assign metadata to the current row. Return the
159     * current object to allow fluent interface.
160     *
161     * @param ResourceEntityInterface $resource The resource to populate
162     * @param RecordDriver            $driver   The record driver to populate from
163     *
164     * @return ResourceEntityInterface
165     */
166    public function assignMetadata(ResourceEntityInterface $resource, RecordDriver $driver): ResourceEntityInterface
167    {
168        // Grab title -- we have to have something in this field!
169        $title = mb_substr(
170            $driver->tryMethod('getSortTitle'),
171            0,
172            255,
173            'UTF-8'
174        );
175        if (empty($title)) {
176            $title = $driver->getBreadcrumb();
177        }
178        $resource->setTitle($title);
179
180        // Try to find an author; if not available, just leave the default null:
181        $author = mb_substr(
182            $driver->tryMethod('getPrimaryAuthor'),
183            0,
184            255,
185            'UTF-8'
186        );
187        if (!empty($author)) {
188            $resource->setAuthor($author);
189        }
190
191        // Try to find a year; if not available, just leave the default null:
192        $dates = $driver->tryMethod('getPublicationDates');
193        if (isset($dates[0]) && strlen($dates[0]) > 4) {
194            try {
195                $year = $this->dateConverter->convertFromDisplayDate('Y', $dates[0]);
196            } catch (DateException) {
197                // If conversion fails, don't store a date:
198                $year = '';
199            }
200        } else {
201            $year = $dates[0] ?? '';
202        }
203        if (!empty($year)) {
204            $resource->setYear(intval($year));
205        }
206
207        if ($extra = $driver->tryMethod('getExtraResourceMetadata')) {
208            $resource->setExtraMetadata(json_encode($extra));
209        }
210        return $resource;
211    }
212}