Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 107
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Comment
0.00% covered (danger)
0.00%
0 / 107
0.00% covered (danger)
0.00%
0 / 8
756
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 save
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
110
 delete
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 toArray
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 getForArticle
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
20
 getCountForArticle
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 approve
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getPending
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace BuyerKiosk\Support;
4
5use \PDO;
6use \PDOException;
7
8/**
9 * Comment - Article comment model (store-level)
10 *
11 * Manages employee comments on support articles with moderation support.
12 * Stored in individual store databases for multi-tenant isolation.
13 */
14class Comment
15{
16    /**
17     * @var int|null Comment ID
18     */
19    public $id;
20
21    /**
22     * @var int Article ID (from kiosk_buykiosk.support_articles)
23     */
24    public $articleId;
25
26    /**
27     * @var int Employee ID (from store database)
28     */
29    public $employeeId;
30
31    /**
32     * @var string|null Employee name (for display)
33     */
34    public $employeeName;
35
36    /**
37     * @var string Comment text
38     */
39    public $comment;
40
41    /**
42     * @var bool Whether comment is approved for display
43     */
44    public $isApproved;
45
46    /**
47     * @var string Created timestamp
48     */
49    public $createdAt;
50
51    /**
52     * @var string|null Updated timestamp
53     */
54    public $updatedAt;
55
56    /**
57     * @var PDO Database connection (store DB)
58     */
59    private $db;
60
61    /**
62     * Constructor
63     *
64     * @param PDO $db Store database connection
65     */
66    public function __construct(PDO $db)
67    {
68        $this->db = $db;
69    }
70
71    /**
72     * Save comment (insert or update)
73     *
74     * Uses INSERT or UPDATE based on whether ID is set
75     *
76     * @return bool True if successful
77     */
78    public function save(): bool
79    {
80        if (!isset($this->articleId) || !isset($this->employeeId) || !isset($this->comment)) {
81            error_log("Comment::save error: articleId, employeeId, and comment are required");
82            return false;
83        }
84
85        // Set defaults
86        if (!isset($this->isApproved)) {
87            $this->isApproved = true; // Auto-approve by default
88        }
89
90        try {
91            if ($this->id) {
92                // Update existing comment
93                $stmt = $this->db->prepare("
94                    UPDATE support_article_comments
95                    SET comment = :comment,
96                        is_approved = :isApproved
97                    WHERE id = :id
98                ");
99
100                return $stmt->execute([
101                    ':id' => $this->id,
102                    ':comment' => $this->comment,
103                    ':isApproved' => $this->isApproved ? 1 : 0
104                ]);
105            } else {
106                // Insert new comment (note: table doesn't have employee_name column, so we don't insert it)
107                $stmt = $this->db->prepare("
108                    INSERT INTO support_article_comments
109                    (article_id, employee_id, comment, is_approved)
110                    VALUES
111                    (:articleId, :employeeId, :comment, :isApproved)
112                ");
113
114                $result = $stmt->execute([
115                    ':articleId' => $this->articleId,
116                    ':employeeId' => $this->employeeId,
117                    ':comment' => $this->comment,
118                    ':isApproved' => $this->isApproved ? 1 : 0
119                ]);
120
121                if ($result) {
122                    $this->id = (int) $this->db->lastInsertId();
123                }
124
125                return $result;
126            }
127        } catch (PDOException $e) {
128            error_log("Comment::save error: " . $e->getMessage());
129            return false;
130        }
131    }
132
133    /**
134     * Delete comment
135     *
136     * @return bool True if successful
137     */
138    public function delete(): bool
139    {
140        if (!isset($this->id)) {
141            error_log("Comment::delete error: id is required");
142            return false;
143        }
144
145        try {
146            $stmt = $this->db->prepare("
147                DELETE FROM support_article_comments
148                WHERE id = :id
149            ");
150
151            return $stmt->execute([':id' => $this->id]);
152        } catch (PDOException $e) {
153            error_log("Comment::delete error: " . $e->getMessage());
154            return false;
155        }
156    }
157
158    /**
159     * Convert Comment to array for API responses
160     *
161     * @return array Associative array representation
162     */
163    public function toArray(): array
164    {
165        return [
166            'id' => $this->id,
167            'articleId' => $this->articleId,
168            'employeeId' => $this->employeeId,
169            'employeeName' => $this->employeeName,
170            'comment' => $this->comment,
171            'isApproved' => (bool) $this->isApproved,
172            'createdAt' => $this->createdAt,
173            'updatedAt' => $this->updatedAt
174        ];
175    }
176
177    /**
178     * Get all comments for an article
179     *
180     * @param PDO $db Store database connection
181     * @param int $articleId Article ID
182     * @param bool $approvedOnly Whether to return only approved comments
183     * @return array Array of Comment objects
184     */
185    public static function getForArticle(PDO $db, int $articleId, bool $approvedOnly = true): array
186    {
187        try {
188            $sql = "
189                SELECT
190                    c.*,
191                    e.employeeFirstName,
192                    e.employeeLastName
193                FROM support_article_comments c
194                LEFT JOIN employees e ON c.employee_id = e.employeeID
195                WHERE c.article_id = :articleId
196            ";
197
198            if ($approvedOnly) {
199                $sql .= " AND c.is_approved = 1";
200            }
201
202            $sql .= " ORDER BY c.created_at ASC";
203
204            $stmt = $db->prepare($sql);
205            $stmt->execute([':articleId' => $articleId]);
206
207            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
208            $comments = [];
209
210            foreach ($rows as $row) {
211                $comment = new self($db);
212                $comment->id = (int) $row['id'];
213                $comment->articleId = (int) $row['article_id'];
214                $comment->employeeId = (int) $row['employee_id'];
215
216                // Build employee name from employee record
217                $comment->employeeName = trim(($row['employeeFirstName'] ?? '') . ' ' . ($row['employeeLastName'] ?? ''));
218
219                $comment->comment = $row['comment'];
220                $comment->isApproved = (bool) $row['is_approved'];
221                $comment->createdAt = $row['created_at'];
222                $comment->updatedAt = $row['updated_at'];
223
224                $comments[] = $comment;
225            }
226
227            return $comments;
228        } catch (PDOException $e) {
229            error_log("Comment::getForArticle error: " . $e->getMessage());
230            return [];
231        }
232    }
233
234    /**
235     * Get comment count for an article
236     *
237     * @param PDO $db Store database connection
238     * @param int $articleId Article ID
239     * @param bool $approvedOnly Whether to count only approved comments
240     * @return int Comment count
241     */
242    public static function getCountForArticle(PDO $db, int $articleId, bool $approvedOnly = true): int
243    {
244        try {
245            $sql = "SELECT COUNT(*) FROM support_article_comments WHERE article_id = :articleId";
246
247            if ($approvedOnly) {
248                $sql .= " AND is_approved = 1";
249            }
250
251            $stmt = $db->prepare($sql);
252            $stmt->execute([':articleId' => $articleId]);
253
254            return (int) $stmt->fetchColumn();
255        } catch (PDOException $e) {
256            error_log("Comment::getCountForArticle error: " . $e->getMessage());
257            return 0;
258        }
259    }
260
261    /**
262     * Approve a comment
263     *
264     * @param PDO $db Store database connection
265     * @param int $commentId Comment ID
266     * @return bool True if successful
267     */
268    public static function approve(PDO $db, int $commentId): bool
269    {
270        try {
271            $stmt = $db->prepare("
272                UPDATE support_article_comments
273                SET is_approved = 1
274                WHERE id = :id
275            ");
276
277            return $stmt->execute([':id' => $commentId]);
278        } catch (PDOException $e) {
279            error_log("Comment::approve error: " . $e->getMessage());
280            return false;
281        }
282    }
283
284    /**
285     * Get pending comments (not approved) across all articles
286     *
287     * @param PDO $db Store database connection
288     * @param int $limit Maximum number of comments to return
289     * @return array Array of Comment objects
290     */
291    public static function getPending(PDO $db, int $limit = 50): array
292    {
293        try {
294            $stmt = $db->prepare("
295                SELECT
296                    c.*,
297                    e.employeeFirstName,
298                    e.employeeLastName
299                FROM support_article_comments c
300                LEFT JOIN employees e ON c.employee_id = e.employeeID
301                WHERE c.is_approved = 0
302                ORDER BY c.created_at DESC
303                LIMIT :limit
304            ");
305
306            $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
307            $stmt->execute();
308
309            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
310            $comments = [];
311
312            foreach ($rows as $row) {
313                $comment = new self($db);
314                $comment->id = (int) $row['id'];
315                $comment->articleId = (int) $row['article_id'];
316                $comment->employeeId = (int) $row['employee_id'];
317
318                $comment->employeeName = trim(($row['employeeFirstName'] ?? '') . ' ' . ($row['employeeLastName'] ?? ''));
319
320                $comment->comment = $row['comment'];
321                $comment->isApproved = (bool) $row['is_approved'];
322                $comment->createdAt = $row['created_at'];
323                $comment->updatedAt = $row['updated_at'];
324
325                $comments[] = $comment;
326            }
327
328            return $comments;
329        } catch (PDOException $e) {
330            error_log("Comment::getPending error: " . $e->getMessage());
331            return [];
332        }
333    }
334}