• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / auth / 26937880755

04 Jun 2026 07:38AM UTC coverage: 75.983% (+4.4%) from 71.569%
26937880755

push

github

web-flow
Merge pull request #56 from daycry/development

feat

613 of 719 new or added lines in 42 files covered. (85.26%)

3 existing lines in 3 files now uncovered.

5179 of 6816 relevant lines covered (75.98%)

69.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.07
/src/Traits/BaseControllerTrait.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Auth.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Auth\Traits;
15

16
use CodeIgniter\Exceptions\ExceptionInterface;
17
use CodeIgniter\Exceptions\PageNotFoundException;
18
use CodeIgniter\HTTP\RequestInterface;
19
use CodeIgniter\HTTP\ResponseInterface;
20
use Config\Mimes;
21
use Config\Services;
22
use Daycry\Auth\Libraries\Utils;
23
use Daycry\Auth\Services\AttemptHandler;
24
use Daycry\Auth\Services\ExceptionHandler;
25
use Daycry\Auth\Services\RequestLogger;
26
use Daycry\Encryption\Encryption;
27
use Psr\Log\LoggerInterface;
28
use Throwable;
29

30
/**
31
 * BaseControllerTrait that delegates to specialized services
32
 *
33
 * This version follows Single Responsibility Principle by using dedicated services
34
 * for logging, attempt handling, and exception management.
35
 */
36
trait BaseControllerTrait
37
{
38
    use Validation;
39

40
    protected Encryption $encryption;
41
    protected RequestLogger $requestLogger;
42
    protected AttemptHandler $attemptHandler;
43
    protected ExceptionHandler $exceptionHandler;
44
    protected array $args;
45
    protected mixed $content         = null;
46
    protected bool $requestFinalized = false;
47

48
    /**
49
     * Hook for early checks - can be overridden by implementing classes
50
     */
51
    protected function earlyChecks(): void
44✔
52
    {
53
        // Override in child classes if needed
54
    }
44✔
55

56
    /**
57
     * Initialize controller with services
58
     */
59
    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger): void
44✔
60
    {
61
        // Load required helpers
62
        helper(['security', 'auth']);
44✔
63

64
        // Initialize services
65
        $this->encryption       = new Encryption();
44✔
66
        $this->requestLogger    = new RequestLogger();
44✔
67
        $this->attemptHandler   = new AttemptHandler();
44✔
68
        $this->exceptionHandler = new ExceptionHandler();
44✔
69

70
        // Call parent initialization
71
        parent::initController($request, $response, $logger);
44✔
72

73
        // Set response format if method exists (for API controllers)
74
        if (method_exists($this, 'setFormat')) {
44✔
75
            $output = $this->request->negotiate('media', setting('Format.supportedResponseFormats'));
×
76
            $output = Mimes::guessExtensionFromType($output);
×
77
            $this->setFormat($output);
×
78
        }
79

80
        // Extract request parameters
81
        $this->args    = Utils::getAllParams();
44✔
82
        $this->content = $this->args['body'] ?? null;
44✔
83

84
        // Run early checks
85
        $this->earlyChecks();
44✔
86
    }
87

88
    /**
89
     * Cleanup and logging on destruction.
90
     *
91
     * Delegates to {@see finalizeRequest()}, which is guarded so that a failure
92
     * can never escape the destructor: an exception thrown from `__destruct`
93
     * during PHP shutdown is an uncatchable fatal.
94
     */
95
    public function __destruct()
24✔
96
    {
97
        $this->finalizeRequest();
24✔
98
    }
99

100
    /**
101
     * Performs end-of-request bookkeeping: request logging, invalid-attempt
102
     * handling and validator reset.
103
     *
104
     * Idempotent (safe to call more than once) and never throws — any failure
105
     * is logged instead. Can also be invoked from an `after` filter for
106
     * deterministic timing instead of relying on `__destruct`.
107
     */
108
    public function finalizeRequest(): void
24✔
109
    {
110
        if ($this->requestFinalized) {
24✔
NEW
111
            return;
×
112
        }
113
        $this->requestFinalized = true;
24✔
114

115
        try {
116
            if (isset($this->request) && $this->request) {
24✔
117
                $this->requestLogger->logRequest($this->response);
24✔
118

119
                if (! $this->requestLogger->isRequestAuthorized()) {
23✔
120
                    $this->attemptHandler->handleInvalidAttempt($this->request);
1✔
121
                }
122
            }
123

124
            if (isset($this->validator) && $this->validator) {
23✔
125
                $this->validator->reset();
23✔
126
            }
127
        } catch (Throwable $e) {
1✔
128
            log_message('error', 'Request finalization failed: {message}', [
1✔
129
                'message' => $e->getMessage(),
1✔
130
            ]);
1✔
131
        }
132
    }
133

134
    /**
135
     * Get CSRF token for forms
136
     */
137
    protected function getToken(): array
4✔
138
    {
139
        return ['name' => csrf_token(), 'hash' => csrf_hash()];
4✔
140
    }
141

142
    /**
143
     * Main request handler with exception management
144
     */
145
    public function _remap(string $method, ...$params)
17✔
146
    {
147
        try {
148
            if (! method_exists($this, $method)) {
17✔
149
                throw PageNotFoundException::forPageNotFound();
1✔
150
            }
151

152
            // Validate attempts if enabled
153
            $this->attemptHandler->validateAttempts($this->response);
16✔
154

155
            // Execute the method
156
            $data = $this->{$method}(...$params);
16✔
157

158
            // Handle different response types
159
            if ($data instanceof ResponseInterface) {
16✔
160
                return $data;
15✔
161
            }
162

163
            // Return JSON for AJAX requests
164
            if (method_exists($this->request, 'isAJAX') && $this->request->isAJAX() && (is_array($data) || is_object($data))) {
1✔
165
                return $this->response->setJSON($data);
×
166
            }
167

168
            // Return regular response
169
            return $this->response->setBody($data);
1✔
170
        } catch (ExceptionInterface $ex) {
1✔
171
            return $this->exceptionHandler->handleException(
1✔
172
                $ex,
1✔
173
                $this->request,
1✔
174
                $this->response,
1✔
175
                $this->validator ?? null,
1✔
176
                $this,
1✔
177
            );
1✔
178
        }
179
    }
180

181
    /**
182
     * Mark request as unauthorized
183
     */
184
    protected function setRequestUnauthorized(): void
2✔
185
    {
186
        $this->requestLogger->setRequestAuthorized(false);
2✔
187
    }
188

189
    /**
190
     * Check if request is authorized
191
     */
192
    protected function isRequestAuthorized(): bool
1✔
193
    {
194
        return $this->requestLogger->isRequestAuthorized();
1✔
195
    }
196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc