Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
RecordFavoriteService
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
4 / 4
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toggleFavorite
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 isFavorite
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getUserFavoriteRecordIds
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Engine\Application\Service;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use PDO;
12
13/**
14 * Manages per-user favorite record flags stored in a_core_record_favorites.
15 *
16 * @package App\Core\Engine\Application\Service
17 */
18final readonly class RecordFavoriteService
19{
20    private const string SQL_CHECK = 'SELECT 1 FROM `a_core_record_favorites` '
21        . 'WHERE `module_name` = :module AND `record_id` = :record_id AND `user_id` = :user_id LIMIT 1';
22
23    private const string SQL_INSERT = 'INSERT INTO `a_core_record_favorites` '
24        . '(`module_name`, `record_id`, `user_id`) VALUES (:module, :record_id, :user_id)';
25
26    private const string SQL_DELETE = 'DELETE FROM `a_core_record_favorites` '
27        . 'WHERE `module_name` = :module AND `record_id` = :record_id AND `user_id` = :user_id';
28
29    private const string SQL_USER_FAVORITES = 'SELECT `record_id` FROM `a_core_record_favorites` '
30        . 'WHERE `module_name` = :module AND `user_id` = :user_id';
31
32    /**
33     * @param PDO $pdo Database connection.
34     */
35    public function __construct(
36        private PDO $pdo
37    ) {
38    }
39
40    /**
41     * Toggles favorite state for a given record and user.
42     *
43     * @param string $moduleName Module machine name.
44     * @param int    $recordId   Target record ID.
45     * @param int    $userId     Current user ID.
46     * @return bool True if record is now favorite, false if removed from favorites.
47     */
48    public function toggleFavorite(string $moduleName, int $recordId, int $userId): bool
49    {
50        if ($this->isFavorite($moduleName, $recordId, $userId)) {
51            $stmt = $this->pdo->prepare(self::SQL_DELETE);
52            $stmt->execute([
53                ':module'    => $moduleName,
54                ':record_id' => $recordId,
55                ':user_id'   => $userId,
56            ]);
57            return false;
58        }
59
60        $stmt = $this->pdo->prepare(self::SQL_INSERT);
61        $stmt->execute([
62            ':module'    => $moduleName,
63            ':record_id' => $recordId,
64            ':user_id'   => $userId,
65        ]);
66        return true;
67    }
68
69    /**
70     * Checks if a record is marked as favorite by the given user.
71     *
72     * @param string $moduleName Module machine name.
73     * @param int    $recordId   Target record ID.
74     * @param int    $userId     Current user ID.
75     * @return bool True if favorite.
76     */
77    public function isFavorite(string $moduleName, int $recordId, int $userId): bool
78    {
79        $stmt = $this->pdo->prepare(self::SQL_CHECK);
80        $stmt->execute([
81            ':module'    => $moduleName,
82            ':record_id' => $recordId,
83            ':user_id'   => $userId,
84        ]);
85
86        return $stmt->fetchColumn() !== false;
87    }
88
89    /**
90     * Returns list of record IDs marked as favorite by the user in this module.
91     *
92     * @param string $moduleName Module machine name.
93     * @param int    $userId     Current user ID.
94     * @return array<int> List of favorite record IDs.
95     */
96    public function getUserFavoriteRecordIds(string $moduleName, int $userId): array
97    {
98        $stmt = $this->pdo->prepare(self::SQL_USER_FAVORITES);
99        $stmt->execute([
100            ':module'  => $moduleName,
101            ':user_id' => $userId,
102        ]);
103
104        $ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
105
106        return array_map(static fn(mixed $id): int => (int) $id, $ids);
107    }
108}