Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
12.82% covered (danger)
12.82%
5 / 39
14.29% covered (danger)
14.29%
1 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserResourceService
12.82% covered (danger)
12.82%
5 / 39
14.29% covered (danger)
14.29%
1 / 7
285.03
0.00% covered (danger)
0.00%
0 / 1
 getFavoritesForRecord
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getStatistics
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createOrUpdateLink
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
72
 unlinkFavorites
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 createEntity
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 changeResourceId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 deduplicate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Database service for UserResource.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2023.
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  Database
25 * @author   Sudharma Kellampalli <skellamp@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:database_gateways Wiki
28 */
29
30namespace VuFind\Db\Service;
31
32use Exception;
33use VuFind\Db\Entity\ResourceEntityInterface;
34use VuFind\Db\Entity\UserEntityInterface;
35use VuFind\Db\Entity\UserListEntityInterface;
36use VuFind\Db\Entity\UserResourceEntityInterface;
37use VuFind\Db\Table\DbTableAwareInterface;
38use VuFind\Db\Table\DbTableAwareTrait;
39
40use function is_int;
41
42/**
43 * Database service for UserResource.
44 *
45 * @category VuFind
46 * @package  Database
47 * @author   Demian Katz <demian.katz@villanova.edu>
48 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
49 * @link     https://vufind.org/wiki/development:plugins:database_gateways Wiki
50 */
51class UserResourceService extends AbstractDbService implements
52    DbTableAwareInterface,
53    DbServiceAwareInterface,
54    UserResourceServiceInterface
55{
56    use DbServiceAwareTrait;
57    use DbTableAwareTrait;
58
59    /**
60     * Get information saved in a user's favorites for a particular record.
61     *
62     * @param string                           $recordId ID of record being checked.
63     * @param string                           $source   Source of record to look up
64     * @param UserListEntityInterface|int|null $listOrId Optional list entity or ID
65     * (to limit results to a particular list).
66     * @param UserEntityInterface|int|null     $userOrId Optional user entity or ID
67     * (to limit results to a particular user).
68     *
69     * @return UserResourceEntityInterface[]
70     */
71    public function getFavoritesForRecord(
72        string $recordId,
73        string $source = DEFAULT_SEARCH_BACKEND,
74        UserListEntityInterface|int|null $listOrId = null,
75        UserEntityInterface|int|null $userOrId = null
76    ): array {
77        $listId = is_int($listOrId) ? $listOrId : $listOrId?->getId();
78        $userId = is_int($userOrId) ? $userOrId : $userOrId?->getId();
79        return iterator_to_array(
80            $this->getDbTable('UserResource')->getSavedData($recordId, $source, $listId, $userId)
81        );
82    }
83
84    /**
85     * Get statistics on use of UserResource.
86     *
87     * @return array
88     */
89    public function getStatistics(): array
90    {
91        return $this->getDbTable('UserResource')->getStatistics();
92    }
93
94    /**
95     * Create user/resource/list link if one does not exist; update notes if one does.
96     *
97     * @param ResourceEntityInterface|int $resourceOrId Entity or ID of resource to link up
98     * @param UserEntityInterface|int     $userOrId     Entity or ID of user creating link
99     * @param UserListEntityInterface|int $listOrId     Entity or ID of list to link up
100     * @param string                      $notes        Notes to associate with link
101     *
102     * @return UserResource|false
103     */
104    public function createOrUpdateLink(
105        ResourceEntityInterface|int $resourceOrId,
106        UserEntityInterface|int $userOrId,
107        UserListEntityInterface|int $listOrId,
108        string $notes = ''
109    ): UserResourceEntityInterface {
110        $resource = $resourceOrId instanceof ResourceEntityInterface
111            ? $resourceOrId : $this->getDbService(ResourceServiceInterface::class)->getResourceById($resourceOrId);
112        if (!$resource) {
113            throw new Exception("Cannot retrieve resource $resourceOrId");
114        }
115        $list = $listOrId instanceof UserListEntityInterface
116            ? $listOrId : $this->getDbService(UserListServiceInterface::class)->getUserListById($listOrId);
117        if (!$list) {
118            throw new Exception("Cannot retrieve list $listOrId");
119        }
120        $user = $userOrId instanceof UserEntityInterface
121            ? $userOrId : $this->getDbService(UserServiceInterface::class)->getUserById($userOrId);
122        if (!$user) {
123            throw new Exception("Cannot retrieve user $userOrId");
124        }
125        $params = [
126            'resource_id' => $resource->getId(),
127            'list_id' => $list->getId(),
128            'user_id' => $user->getId(),
129        ];
130        if (!($result = $this->getDbTable('UserResource')->select($params)->current())) {
131            $result = $this->createEntity()
132                ->setResource($resource)
133                ->setUser($user)
134                ->setUserList($list);
135        }
136        // Update the notes:
137        $result->setNotes($notes);
138        $this->persistEntity($result);
139        return $result;
140    }
141
142    /**
143     * Unlink rows for the specified resource.
144     *
145     * @param int|int[]|null              $resourceId ID (or array of IDs) of resource(s) to unlink (null for ALL
146     * matching resources)
147     * @param UserEntityInterface|int     $userOrId   ID or entity representing user removing links
148     * @param UserListEntityInterface|int $listOrId   ID or entity representing list to unlink (null for ALL
149     * matching lists)
150     *
151     * @return void
152     */
153    public function unlinkFavorites(
154        int|array|null $resourceId,
155        UserEntityInterface|int $userOrId,
156        UserListEntityInterface|int|null $listOrId = null
157    ): void {
158        // Build the where clause to figure out which rows to remove:
159        $listId = is_int($listOrId) ? $listOrId : $listOrId?->getId();
160        $userId = is_int($userOrId) ? $userOrId : $userOrId->getId();
161        $callback = function ($select) use ($resourceId, $userId, $listId) {
162            $select->where->equalTo('user_id', $userId);
163            if (null !== $resourceId) {
164                $select->where->in('resource_id', (array)$resourceId);
165            }
166            if (null !== $listId) {
167                $select->where->equalTo('list_id', $listId);
168            }
169        };
170
171        // Delete the rows:
172        $this->getDbTable('UserResource')->delete($callback);
173    }
174
175    /**
176     * Create a UserResource entity object.
177     *
178     * @return UserResourceEntityInterface
179     */
180    public function createEntity(): UserResourceEntityInterface
181    {
182        return $this->getDbTable('UserResource')->createRow();
183    }
184
185    /**
186     * Change all matching rows to use the new resource ID instead of the old one (called when an ID changes).
187     *
188     * @param int $old Original resource ID
189     * @param int $new New resource ID
190     *
191     * @return void
192     */
193    public function changeResourceId(int $old, int $new): void
194    {
195        $this->getDbTable('UserResource')->update(['resource_id' => $new], ['resource_id' => $old]);
196    }
197
198    /**
199     * Deduplicate rows (sometimes necessary after merging foreign key IDs).
200     *
201     * @return void
202     */
203    public function deduplicate(): void
204    {
205        $this->getDbTable('UserResource')->deduplicate();
206    }
207}