Skip to content

Commit 0e62680

Browse files
committed
Enabler: Full refactoring [BC break!]
1 parent f3e716d commit 0e62680

File tree

6 files changed

+94
-55
lines changed

6 files changed

+94
-55
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"nette/tester": "^2.4"
4242
},
4343
"scripts": {
44-
"phpstan": "phpstan analyze src --level 8",
44+
"phpstan": "phpstan analyze src -c phpstan.neon --level 8",
4545
"tester": "tester tests"
4646
}
4747
}

phpstan.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#Parameter \#3 \$options of function setcookie expects .+#'
5+
path: src/Enabler.php
6+
count: 2

src/Detector.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
namespace Redbitcz\DebugMode;
1010

11-
use InvalidArgumentException;
12-
use LogicException;
13-
1411
class Detector
1512
{
1613
/** Name of Environment variable used to detect Debug mode */
@@ -52,7 +49,7 @@ class Detector
5249
public function __construct(int $mode = self::MODE_SIMPLE, ?Enabler $enabler = null)
5350
{
5451
if ($enabler === null && $mode & self::MODE_ENABLER) {
55-
throw new InvalidArgumentException('Enabler mode requires Enabler instance in constructor');
52+
throw new MissingEnablerException('Enabler mode requires the Enabler instance in constructor');
5653
}
5754

5855
$this->enabler = $enabler;
@@ -62,7 +59,7 @@ public function __construct(int $mode = self::MODE_SIMPLE, ?Enabler $enabler = n
6259
public function getEnabler(): Enabler
6360
{
6461
if ($this->enabler === null) {
65-
throw new LogicException('Detector constructed without Enabler');
62+
throw new MissingEnablerException('Unable to get Enabler because Detector constructed without it');
6663
}
6764

6865
return $this->enabler;
@@ -184,7 +181,7 @@ public static function detect(
184181
?bool $default = false
185182
): ?bool {
186183
if ($tempDir === null && $mode & self::MODE_ENABLER) {
187-
throw new InvalidArgumentException('Enabler mode requires `tempDir` argument');
184+
throw new MissingEnablerException('Enabler mode requires \'tempDir\' argument');
188185
}
189186

190187
$enabler = $tempDir === null ? null : new Enabler($tempDir);

src/Enabler.php

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace Redbitcz\DebugMode;
1010

1111
use Nette\IOException;
12+
use Nette\Utils\DateTime as NetteDateTime;
1213
use Nette\Utils\FileSystem;
1314
use Nette\Utils\Json;
1415
use Nette\Utils\JsonException;
@@ -20,40 +21,63 @@ class Enabler
2021
private const DEBUG_COOKIE_NAME = 'app-debug-token';
2122
private const TOKEN_LENGTH = 30;
2223
private const ID_LENGTH = 15;
23-
private const TTL = 3600;
24-
// TODO: Make configurable TLS requirements
25-
private const REQUIRE_HTTPS = false;
24+
private const DEFAULT_TTL = '1 hour';
2625

27-
/** @var string */
28-
private $tempDir;
26+
private string $tempDir;
27+
private ?bool $override;
2928

30-
/** @var bool|null */
31-
private $override;
29+
/** @var array<string, string|bool> */
30+
private array $cookieOptions = [
31+
'path' => '/',
32+
'domain' => '',
33+
'secure' => true,
34+
'httponly' => true,
35+
'samesite' => 'Strict',
36+
];
3237

3338
public function __construct(string $tempDir)
3439
{
3540
$this->tempDir = $tempDir;
3641
}
3742

38-
public function activate(bool $isDebug): void
43+
/** @return static */
44+
public function setSecure(bool $secure = true): self
45+
{
46+
$this->cookieOptions['secure'] = $secure;
47+
return $this;
48+
}
49+
50+
/**
51+
* @return $this
52+
* @see setcookie()
53+
*/
54+
public function setCookieOptions(
55+
?string $path = null,
56+
?string $domain = null,
57+
?bool $secure = null,
58+
?bool $httponly = null,
59+
?string $samesite = null
60+
): self {
61+
$this->cookieOptions = [
62+
'path' => $path ?? $this->cookieOptions['path'],
63+
'domain' => $domain ?? $this->cookieOptions['domain'],
64+
'secure' => $secure ?? $this->cookieOptions['secure'],
65+
'httponly' => $httponly ?? $this->cookieOptions['httponly'],
66+
'samesite' => $samesite ?? $this->cookieOptions['samesite'],
67+
];
68+
return $this;
69+
}
70+
71+
public function activate(bool $isDebug, ?string $time = self::DEFAULT_TTL): void
3972
{
4073
if ($tokenName = $this->getTokenName()) {
4174
$this->destroyToken($tokenName);
4275
}
4376

44-
$tokenName = $this->createToken($isDebug);
45-
setcookie(
46-
self::DEBUG_COOKIE_NAME,
47-
$tokenName,
48-
[
49-
'expires' => time() + self::TTL,
50-
'path' => '/',
51-
'domain' => '',
52-
'secure' => self::REQUIRE_HTTPS,
53-
'httponly' => true,
54-
'samesite' => 'Strict',
55-
]
56-
);
77+
$tokenExpires = (int)NetteDateTime::from($time ?? self::DEFAULT_TTL)->format('U');
78+
$cookieExpires = $time === null ? 0 : $tokenExpires;
79+
$tokenName = $this->createToken($isDebug, $tokenExpires);
80+
setcookie(self::DEBUG_COOKIE_NAME, $tokenName, ['expires' => $cookieExpires] + $this->cookieOptions);
5781

5882
$this->override = $isDebug;
5983
}
@@ -65,19 +89,7 @@ public function deactivate(): void
6589
$this->destroyToken($tokenName);
6690
}
6791

68-
setcookie(
69-
self::DEBUG_COOKIE_NAME,
70-
'',
71-
[
72-
'expires' => 0,
73-
'path' => '/',
74-
'domain' => '',
75-
'secure' => self::REQUIRE_HTTPS,
76-
'httponly' => true,
77-
'samesite' => 'Strict',
78-
]
79-
);
80-
92+
setcookie(self::DEBUG_COOKIE_NAME, '', ['expires' => time()] + $this->cookieOptions);
8193
$this->override = null;
8294
}
8395

@@ -117,10 +129,10 @@ private function checkToken(string $name): ?bool
117129
return $this->getListTokenValue($name, $list);
118130
}
119131

120-
private function createToken(bool $value): string
132+
private function createToken(bool $value, int $expires): string
121133
{
122134
$list = $this->loadList();
123-
$name = $this->addListToken($value, $list);
135+
$name = $this->addListToken($value, $expires, $list);
124136
$this->saveList($list);
125137

126138
return $name;
@@ -144,22 +156,18 @@ private function loadList(): array
144156
}
145157

146158
/**
147-
* @param bool $value
148159
* @param array<int, array> $list
149-
* @return string
150160
*/
151-
private function addListToken(bool $value, array &$list): string
161+
private function addListToken(bool $value, int $expires, array &$list): string
152162
{
153163
/** @var string $name */
154-
[$name, $token] = $this->generateToken($value);
164+
[$name, $token] = $this->generateToken($value, $expires);
155165
$list[] = $token;
156166
return $name;
157167
}
158168

159169
/**
160-
* @param string $name
161170
* @param array<int, array> $list
162-
* @return bool|null
163171
*/
164172
private function getListTokenValue(string $name, array $list): ?bool
165173
{
@@ -175,7 +183,6 @@ private function getListTokenValue(string $name, array $list): ?bool
175183

176184

177185
/**
178-
* @param string $name
179186
* @param array<int, array> $list
180187
*/
181188
private function dropListToken(string $name, array &$list): void
@@ -209,8 +216,6 @@ function ($token) {
209216

210217
/**
211218
* @param array<string, string|bool|int> $token
212-
* @param string|null $name
213-
* @return bool
214219
*/
215220
private function isTokenValid(array $token, ?string $name = null): bool
216221
{
@@ -233,16 +238,15 @@ private function isTokenValid(array $token, ?string $name = null): bool
233238
}
234239

235240
/**
236-
* @param bool $value
237241
* @return array<int, string|array>
238242
*/
239-
private function generateToken(bool $value): array
243+
private function generateToken(bool $value, int $expires): array
240244
{
241245
$name = $this->generateTokenName();
242246
$token = [
243247
'id' => $this->getIdByName($name),
244248
'hash' => $this->getHashByName($name),
245-
'expire' => time() + self::TTL,
249+
'expire' => $expires,
246250
'value' => $value
247251
];
248252

src/MissingEnablerException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redbitcz\DebugMode;
6+
7+
class MissingEnablerException extends \LogicException
8+
{
9+
}

tests/DetectorTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Redbitcz\DebugMode\Detector;
88
use Redbitcz\DebugMode\Enabler;
9+
use Redbitcz\DebugMode\MissingEnablerException;
910
use Tester\Assert;
1011
use Tester\Helpers;
1112
use Tester\TestCase;
@@ -189,6 +190,28 @@ public function testEnabler($testValue): void
189190
$detector->getEnabler()->override($testValue);
190191
Assert::equal($testValue, $detector->isDebugModeByEnabler());
191192
}
193+
194+
public function testMissingEnablerMode(): void
195+
{
196+
Assert::exception(function () {
197+
$detector = new Detector(Detector::MODE_FULL);
198+
}, MissingEnablerException::class);
199+
}
200+
201+
public function testMissingEnabler(): void
202+
{
203+
Assert::exception(function () {
204+
$detector = new Detector(Detector::MODE_SIMPLE);
205+
$detector->getEnabler();
206+
}, MissingEnablerException::class);
207+
}
208+
209+
public function testMissingEnablerShortcut(): void
210+
{
211+
Assert::exception(function () {
212+
Detector::detect(Detector::MODE_FULL);
213+
}, MissingEnablerException::class);
214+
}
192215
}
193216

194217
(new DetectorTest())->run();

0 commit comments

Comments
 (0)