Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
ConsentService
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
3 / 3
7
100.00% covered (success)
100.00%
1 / 1
 getConsentData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 handleConsentCookie
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 startSessionIfNeeded
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2declare(strict_types=1);
3
4namespace App\Service;
5
6use Cake\Http\ServerRequest;
7use InvalidArgumentException;
8use RuntimeException;
9
10/**
11 * ConsentService handles cookie consent and session management logic.
12 *
13 * This service extracts business logic from controllers to provide
14 * reusable consent handling functionality across the application.
15 */
16class ConsentService
17{
18    /**
19     * Gets consent data for view variables.
20     *
21     * This method handles the complete consent data flow:
22     * - Ensures session is started
23     * - Retrieves session ID
24     * - Processes consent cookie if present
25     * - Returns data ready for view consumption
26     *
27     * @param \Cake\Http\ServerRequest $request The request object
28     * @return array Array containing sessionId and consentData for view
29     * @throws \RuntimeException If session cannot be started
30     * @throws \InvalidArgumentException If cookie data cannot be decoded
31     */
32    public function getConsentData(ServerRequest $request): array
33    {
34        $sessionId = $this->startSessionIfNeeded($request);
35        $consentData = $this->handleConsentCookie($request);
36
37        return compact('sessionId', 'consentData');
38    }
39
40    /**
41     * Handles consent cookie parsing and validation.
42     *
43     * Retrieves the consent cookie from the request and decodes it.
44     * Returns null if no cookie is present or if decoding fails.
45     *
46     * @param \Cake\Http\ServerRequest $request The request object
47     * @return array|null Decoded consent data or null if not present/invalid
48     * @throws \InvalidArgumentException If cookie data cannot be decoded
49     */
50    public function handleConsentCookie(ServerRequest $request): ?array
51    {
52        $consentCookie = $request->getCookie('consent_cookie');
53
54        if (!$consentCookie) {
55            return null;
56        }
57
58        $consentData = json_decode($consentCookie, true);
59
60        if (json_last_error() !== JSON_ERROR_NONE) {
61            throw new InvalidArgumentException('Invalid consent cookie data: ' . json_last_error_msg());
62        }
63
64        return $consentData;
65    }
66
67    /**
68     * Starts session if not already started and returns session ID.
69     *
70     * Ensures the session is properly initialized before accessing
71     * session data. This is essential for consent tracking.
72     *
73     * @param \Cake\Http\ServerRequest $request The request object
74     * @return string The session ID
75     * @throws \RuntimeException If session cannot be started
76     */
77    public function startSessionIfNeeded(ServerRequest $request): string
78    {
79        $session = $request->getSession();
80
81        if (!$session->started()) {
82            if (!$session->start()) {
83                throw new RuntimeException('Unable to start session for consent tracking');
84            }
85        }
86
87        return $session->id();
88    }
89}