Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
ComebackCashFactory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 16
552
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getDatabase
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getStore
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getAblyService
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 createEventService
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 createCouponService
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 createRedemptionService
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 createEventServiceStatic
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 createCouponServiceStatic
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 createRedemptionServiceStatic
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 createAblyServiceStatic
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setDatabase
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setStore
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setAblyService
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setSmsQueue
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getTypeNum
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace BuyerKiosk\ComebackCash;
4
5use PDO;
6use BuyerKiosk\BuyerKiosk\Controllers\StoreController;
7use BuyerKiosk\ComebackCash\Services\EventService;
8use BuyerKiosk\ComebackCash\Services\CouponService;
9use BuyerKiosk\ComebackCash\Services\RedemptionService;
10use BuyerKiosk\ComebackCash\Services\ComebackCashAbly;
11use BuyerKiosk\ComebackCash\Services\SmsQueueInterface;
12
13/**
14 * ComebackCashFactory - Dependency injection factory for Comeback Cash services
15 *
16 * This factory creates service instances with proper dependency wiring.
17 * It handles store-level database connections and integrations like Ably.
18 *
19 * Usage:
20 * ```php
21 * $factory = new ComebackCashFactory($typeNum);
22 * $eventService = $factory->createEventService();
23 * $couponService = $factory->createCouponService();
24 * $redemptionService = $factory->createRedemptionService();
25 * ```
26 *
27 * Or use static convenience methods:
28 * ```php
29 * $eventService = ComebackCashFactory::createEventServiceStatic($typeNum);
30 * ```
31 *
32 * @package BuyerKiosk\ComebackCash
33 */
34class ComebackCashFactory
35{
36    /**
37     * @var string Store identifier (e.g., 'ou00', 'pa00')
38     */
39    private string $typeNum;
40
41    /**
42     * @var PDO|null Cached database connection
43     */
44    private ?PDO $db = null;
45
46    /**
47     * @var \Store|null Cached store object
48     */
49    private $store = null;
50
51    /**
52     * @var ComebackCashAbly|null Cached Ably service
53     */
54    private ?ComebackCashAbly $ably = null;
55
56    /**
57     * @var EventService|null Cached event service
58     */
59    private ?EventService $eventService = null;
60
61    /**
62     * @var CouponService|null Cached coupon service
63     */
64    private ?CouponService $couponService = null;
65
66    /**
67     * @var RedemptionService|null Cached redemption service
68     */
69    private ?RedemptionService $redemptionService = null;
70
71    /**
72     * @var SmsQueueInterface|null Optional SMS queue service
73     */
74    private ?SmsQueueInterface $smsQueue = null;
75
76    /**
77     * Constructor
78     *
79     * @param string $typeNum Store identifier (e.g., 'ou00', 'pa00')
80     * @param SmsQueueInterface|null $smsQueue Optional SMS queue service
81     */
82    public function __construct(string $typeNum, ?SmsQueueInterface $smsQueue = null)
83    {
84        $this->typeNum = $typeNum;
85        $this->smsQueue = $smsQueue;
86    }
87
88    /**
89     * Get the database connection for this store
90     *
91     * @return PDO Database connection
92     * @throws \RuntimeException If database connection fails
93     */
94    public function getDatabase(): PDO
95    {
96        if ($this->db !== null) {
97            return $this->db;
98        }
99
100        $store = $this->getStore();
101        $dbName = $store->getDbName();
102
103        $this->db = dbConnectByName($dbName);
104
105        if ($this->db === null) {
106            throw new \RuntimeException("Failed to connect to database for store: {$this->typeNum}");
107        }
108
109        return $this->db;
110    }
111
112    /**
113     * Get the Store object for this typeNum
114     *
115     * @return \Store Store object
116     */
117    public function getStore()
118    {
119        if ($this->store !== null) {
120            return $this->store;
121        }
122
123        $storeController = new StoreController($this->typeNum);
124        $this->store = $storeController->getStore();
125
126        return $this->store;
127    }
128
129    /**
130     * Get the Ably service instance
131     *
132     * The Ably service is created with the EventService injected for
133     * retrieving active events during broadcast.
134     *
135     * @return ComebackCashAbly Ably service instance
136     */
137    public function getAblyService(): ComebackCashAbly
138    {
139        if ($this->ably !== null) {
140            return $this->ably;
141        }
142
143        // Create Ably service - it will auto-initialize from environment
144        $this->ably = new ComebackCashAbly($this->typeNum);
145
146        // Inject EventService for retrieving active events during broadcast
147        $this->ably->setEventService($this->createEventService());
148
149        return $this->ably;
150    }
151
152    // =========================================================================
153    // SERVICE CREATION METHODS
154    // =========================================================================
155
156    /**
157     * Create an EventService instance
158     *
159     * EventService only needs the database connection.
160     *
161     * @return EventService
162     */
163    public function createEventService(): EventService
164    {
165        if ($this->eventService !== null) {
166            return $this->eventService;
167        }
168
169        $this->eventService = new EventService($this->getDatabase());
170
171        return $this->eventService;
172    }
173
174    /**
175     * Create a CouponService instance
176     *
177     * CouponService needs:
178     * - Database connection
179     * - EventService for finding active events
180     * - Optional SmsQueueInterface for notifications
181     *
182     * @return CouponService
183     */
184    public function createCouponService(): CouponService
185    {
186        if ($this->couponService !== null) {
187            return $this->couponService;
188        }
189
190        $this->couponService = new CouponService(
191            $this->getDatabase(),
192            $this->createEventService(),
193            $this->smsQueue
194        );
195
196        return $this->couponService;
197    }
198
199    /**
200     * Create a RedemptionService instance
201     *
202     * RedemptionService needs:
203     * - Database connection
204     * - CouponService for coupon operations
205     *
206     * @return RedemptionService
207     */
208    public function createRedemptionService(): RedemptionService
209    {
210        if ($this->redemptionService !== null) {
211            return $this->redemptionService;
212        }
213
214        $this->redemptionService = new RedemptionService(
215            $this->getDatabase(),
216            $this->createCouponService()
217        );
218
219        return $this->redemptionService;
220    }
221
222    // =========================================================================
223    // STATIC CONVENIENCE METHODS
224    // =========================================================================
225
226    /**
227     * Create an EventService via static method
228     *
229     * Convenience method for quick one-off service creation.
230     *
231     * @param string $typeNum Store identifier
232     * @return EventService
233     */
234    public static function createEventServiceStatic(string $typeNum): EventService
235    {
236        $factory = new self($typeNum);
237        return $factory->createEventService();
238    }
239
240    /**
241     * Create a CouponService via static method
242     *
243     * Convenience method for quick one-off service creation.
244     *
245     * @param string $typeNum Store identifier
246     * @param SmsQueueInterface|null $smsQueue Optional SMS queue
247     * @return CouponService
248     */
249    public static function createCouponServiceStatic(string $typeNum, ?SmsQueueInterface $smsQueue = null): CouponService
250    {
251        $factory = new self($typeNum, $smsQueue);
252        return $factory->createCouponService();
253    }
254
255    /**
256     * Create a RedemptionService via static method
257     *
258     * Convenience method for quick one-off service creation.
259     *
260     * @param string $typeNum Store identifier
261     * @param SmsQueueInterface|null $smsQueue Optional SMS queue
262     * @return RedemptionService
263     */
264    public static function createRedemptionServiceStatic(string $typeNum, ?SmsQueueInterface $smsQueue = null): RedemptionService
265    {
266        $factory = new self($typeNum, $smsQueue);
267        return $factory->createRedemptionService();
268    }
269
270    /**
271     * Create an Ably service via static method
272     *
273     * Convenience method for quick one-off service creation.
274     *
275     * @param string $typeNum Store identifier
276     * @return ComebackCashAbly
277     */
278    public static function createAblyServiceStatic(string $typeNum): ComebackCashAbly
279    {
280        $factory = new self($typeNum);
281        return $factory->getAblyService();
282    }
283
284    // =========================================================================
285    // INJECTION SETTERS (for testing)
286    // =========================================================================
287
288    /**
289     * Set the database connection (for testing)
290     *
291     * @param PDO $db Database connection
292     * @return self
293     */
294    public function setDatabase(PDO $db): self
295    {
296        $this->db = $db;
297        return $this;
298    }
299
300    /**
301     * Set the store object (for testing)
302     *
303     * @param \Store $store Store object
304     * @return self
305     */
306    public function setStore($store): self
307    {
308        $this->store = $store;
309        return $this;
310    }
311
312    /**
313     * Set the Ably service (for testing)
314     *
315     * @param ComebackCashAbly $ably Ably service
316     * @return self
317     */
318    public function setAblyService(ComebackCashAbly $ably): self
319    {
320        $this->ably = $ably;
321        return $this;
322    }
323
324    /**
325     * Set the SMS queue service (for production or testing)
326     *
327     * @param SmsQueueInterface $smsQueue SMS queue service
328     * @return self
329     */
330    public function setSmsQueue(SmsQueueInterface $smsQueue): self
331    {
332        $this->smsQueue = $smsQueue;
333        return $this;
334    }
335
336    /**
337     * Get the type number for this factory
338     *
339     * @return string Store identifier
340     */
341    public function getTypeNum(): string
342    {
343        return $this->typeNum;
344    }
345}