Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
CategoryManager
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 7
210
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
 getAll
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getById
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBySlug
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getArticleCount
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 getCategoriesWithCounts
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 slugExists
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace BuyerKiosk\Support;
4
5use \PDO;
6use \PDOException;
7
8/**
9 * CategoryManager - Manager class for support categories
10 *
11 * Handles category retrieval, article counts, and management
12 * operations for the knowledge base system.
13 */
14class CategoryManager
15{
16    /**
17     * @var PDO Database connection
18     */
19    private $db;
20
21    /**
22     * Constructor
23     *
24     * @param PDO $db Database connection (kiosk_buykiosk)
25     */
26    public function __construct(PDO $db)
27    {
28        $this->db = $db;
29    }
30
31    /**
32     * Get all categories
33     *
34     * @param bool $activeOnly Whether to return only active categories
35     * @return array Array of Category objects
36     */
37    public function getAll(bool $activeOnly = false): array
38    {
39        return Category::getAll($this->db, $activeOnly);
40    }
41
42    /**
43     * Get category by ID
44     *
45     * @param int $id Category ID
46     * @return Category|null Category object or null if not found
47     */
48    public function getById(int $id): ?Category
49    {
50        return Category::getById($this->db, $id);
51    }
52
53    /**
54     * Get category by slug
55     *
56     * @param string $slug Category slug
57     * @return Category|null Category object or null if not found
58     */
59    public function getBySlug(string $slug): ?Category
60    {
61        try {
62            $stmt = $this->db->prepare("
63                SELECT * FROM support_categories
64                WHERE slug = :slug AND is_active = 1
65            ");
66            $stmt->execute([':slug' => $slug]);
67
68            $row = $stmt->fetch(PDO::FETCH_ASSOC);
69            if (!$row) {
70                return null;
71            }
72
73            return Category::fromArray($row);
74        } catch (PDOException $e) {
75            error_log("CategoryManager::getBySlug error: " . $e->getMessage());
76            return null;
77        }
78    }
79
80    /**
81     * Get article count for a category
82     *
83     * @param int $categoryId Category ID
84     * @return int Number of articles in category
85     */
86    public function getArticleCount(int $categoryId): int
87    {
88        try {
89            $stmt = $this->db->prepare("
90                SELECT COUNT(*) as cnt
91                FROM support_articles
92                WHERE category_id = :categoryId
93            ");
94            $stmt->execute([':categoryId' => $categoryId]);
95            $result = $stmt->fetch(PDO::FETCH_ASSOC);
96
97            return (int) $result['cnt'];
98        } catch (PDOException $e) {
99            error_log("CategoryManager::getArticleCount error: " . $e->getMessage());
100            return 0;
101        }
102    }
103
104    /**
105     * Get categories with article counts
106     *
107     * Returns all active categories with the count of published articles in each
108     *
109     * @return array Array of category data with articleCount
110     */
111    public function getCategoriesWithCounts(): array
112    {
113        try {
114            $stmt = $this->db->query("
115                SELECT
116                    c.*,
117                    COUNT(a.id) as articleCount
118                FROM support_categories c
119                LEFT JOIN support_articles a ON c.id = a.category_id AND a.status = 'published'
120                WHERE c.is_active = 1
121                GROUP BY c.id
122                ORDER BY c.sort_order ASC, c.name ASC
123            ");
124
125            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
126            $categories = [];
127
128            foreach ($rows as $row) {
129                $category = Category::fromArray($row);
130                $categoryData = $category->toArray();
131                $categoryData['articleCount'] = (int) $row['articleCount'];
132                $categories[] = $categoryData;
133            }
134
135            return $categories;
136        } catch (PDOException $e) {
137            error_log("CategoryManager::getCategoriesWithCounts error: " . $e->getMessage());
138            return [];
139        }
140    }
141
142    /**
143     * Check if slug exists
144     *
145     * @param string $slug Category slug to check
146     * @param int|null $excludeId Optional category ID to exclude from check
147     * @return bool True if slug exists
148     */
149    public function slugExists(string $slug, ?int $excludeId = null): bool
150    {
151        try {
152            $sql = "SELECT COUNT(*) as cnt FROM support_categories WHERE slug = :slug";
153            $params = [':slug' => $slug];
154
155            if ($excludeId !== null) {
156                $sql .= " AND id != :excludeId";
157                $params[':excludeId'] = $excludeId;
158            }
159
160            $stmt = $this->db->prepare($sql);
161            $stmt->execute($params);
162            $result = $stmt->fetch(PDO::FETCH_ASSOC);
163
164            return $result['cnt'] > 0;
165        } catch (PDOException $e) {
166            error_log("CategoryManager::slugExists error: " . $e->getMessage());
167            return false;
168        }
169    }
170}