Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
64.44% covered (warning)
64.44%
29 / 45
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
CookieConsentsController
64.44% covered (warning)
64.44%
29 / 45
50.00% covered (danger)
50.00%
1 / 2
16.44
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 edit
62.79% covered (warning)
62.79%
27 / 43
0.00% covered (danger)
0.00%
0 / 1
15.15
1<?php
2declare(strict_types=1);
3
4namespace App\Controller;
5
6use Cake\Event\EventInterface;
7use Cake\Http\Response;
8
9/**
10 * CookieConsents Controller
11 *
12 * @property \App\Model\Table\CookieConsentsTable $CookieConsents
13 */
14class CookieConsentsController extends AppController
15{
16    /**
17     * Configures authentication for specific actions.
18     *
19     * @param \Cake\Event\EventInterface $event The event instance.
20     * @return void
21     */
22    public function beforeFilter(EventInterface $event): void
23    {
24        parent::beforeFilter($event);
25
26        $this->Authentication->allowUnauthenticated(['edit']);
27    }
28
29    /**
30     * Edit cookie consent preferences and manage GDPR compliance.
31     *
32     * Handles both GET and POST/PUT/PATCH requests for cookie consent management.
33     * For GET requests, displays the current consent settings if they exist.
34     * For POST/PUT/PATCH requests, creates a new consent record for GDPR audit trail
35     * and updates the user's cookie preferences. Supports both regular and AJAX requests.
36     *
37     * The method handles two types of consent:
38     * - Essential only: Basic cookies required for site functionality
39     * - Essential and Analytics: Includes analytics tracking consent
40     *
41     * @return \Cake\Http\Response|null Returns Response object for redirects/AJAX or null for normal view render
42     * @throws \RuntimeException When cookie creation fails
43     */
44    public function edit(): ?Response
45    {
46        $userId = $this->request->getAttribute('identity') ?
47            $this->request->getAttribute('identity')->getIdentifier() : null;
48
49        $cookieConsent = null;
50        $consentCookie = $this->request->getCookie('consent_cookie');
51        if ($consentCookie) {
52            $consentData = json_decode($consentCookie, true);
53            $cookieConsent = $this->CookieConsents->newEntity($consentData);
54            $cookieConsent->session_id = $this->request->getSession()->id();
55        }
56
57        if ($this->request->is(['patch', 'post', 'put'])) {
58            // Always create a new record for GDPR audit trail
59            $newConsent = $this->CookieConsents->newEntity($this->request->getData());
60
61            $newConsent->session_id = $this->request->getSession()->id();
62            $newConsent->user_id = $userId;
63            $newConsent->ip_address = $this->request->clientIp();
64            $newConsent->user_agent = $this->request->getHeaderLine('User-Agent');
65
66            $consentType = $this->request->getData('consent_type');
67            if ($consentType === 'essential') {
68                $newConsent->analytics_consent = false;
69                $newConsent->functional_consent = false;
70                $newConsent->marketing_consent = false;
71            }
72            if ($consentType === 'all') {
73                $newConsent->analytics_consent = true;
74                $newConsent->functional_consent = true;
75                $newConsent->marketing_consent = true;
76            }
77
78            if ($this->CookieConsents->save($newConsent)) {
79                $this->Flash->success(__('Your cookie preferences have been saved.'));
80
81                // Save a cookie with the consent information
82                $cookie = $this->CookieConsents->createConsentCookie($newConsent);
83                $this->response = $this->response->withCookie($cookie);
84
85                if ($this->request->is('ajax')) {
86                    return $this->response->withType('application/json')
87                        ->withStringBody(json_encode(['success' => true]));
88                }
89
90                return $this->redirect(['action' => 'edit']);
91            }
92
93            if ($this->request->is('ajax')) {
94                return $this->response->withType('application/json')
95                    ->withStringBody(json_encode([
96                        'success' => false,
97                        'errors' => $cookieConsent->getErrors(),
98                    ]));
99            }
100
101            $this->Flash->error(__('Your cookie preferences could not be saved. Please, try again.'));
102        }
103
104        $this->set(compact('cookieConsent'));
105
106        if ($this->request->is('ajax')) {
107            $this->viewBuilder()->setLayout('ajax');
108
109            return $this->render('edit');
110        }
111
112        return null;
113    }
114}