Skip to content

Commit 22f2d5b

Browse files
authored
Merge pull request #600 from armanist/issue/595-php-8-1-minimum
Issue/595 Raise the minimum PHP version to 8.1 and test 8.1, 8.2 and 8.3 in CI
2 parents 77e2fe9 + 3acc171 commit 22f2d5b

8 files changed

Lines changed: 147 additions & 13 deletions

File tree

‎.github/workflows/php.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
matrix:
1717
operating-system: [ ubuntu-latest ]
18-
php-versions: [ '8.0', '8.1', '8.2' ]
18+
php-versions: [ '8.1', '8.2', '8.3' ]
1919
redis-version: [ 6 ]
2020

2121
runs-on: ${{ matrix.operating-system }}

‎composer.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
}
2424
],
2525
"require": {
26-
"php": "^8.0",
26+
"php": "^8.1",
2727
"ext-pdo": "*",
2828
"ext-curl": "*",
2929
"ext-json": "*",

‎phpstan.neon.dist‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
parameters:
2-
phpVersion: 80000
2+
phpVersion: 80100
33
level: 8
44

55
scanFiles:

‎rector.php‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;
66
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
7+
use Rector\CodingStyle\Rector\FuncCall\FunctionFirstClassCallableRector;
8+
use Rector\Php81\Rector\Array_\ArrayToFirstClassCallableRector;
9+
use Rector\Php81\Rector\Property\ReadOnlyPropertyRector;
710
use Rector\Set\ValueObject\LevelSetList;
811
use Rector\Set\ValueObject\SetList;
912
use Rector\Config\RectorConfig;
@@ -13,12 +16,15 @@
1316
__DIR__ . '/src',
1417
])
1518
->withSets([
16-
LevelSetList::UP_TO_PHP_80,
19+
LevelSetList::UP_TO_PHP_81,
1720
SetList::TYPE_DECLARATION,
1821
])
1922
->withRules([
2023
DeclareStrictTypesRector::class,
2124
])
2225
->withSkip([
2326
ClassPropertyAssignToConstructorPromotionRector::class,
27+
ReadOnlyPropertyRector::class,
28+
FunctionFirstClassCallableRector::class,
29+
ArrayToFirstClassCallableRector::class,
2430
]);

‎src/HttpClient/ResponseHeaders.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function offsetUnset($offset): void
8282
* @param string $offset
8383
* @return mixed|null
8484
*/
85-
public function offsetGet($offset)
85+
public function offsetGet($offset): mixed
8686
{
8787
return $this->data[strtolower($offset)] ?? null;
8888
}
@@ -95,7 +95,7 @@ public function count(): int
9595
/**
9696
* @return mixed
9797
*/
98-
public function current()
98+
public function current(): mixed
9999
{
100100
return current($this->data);
101101
}
@@ -108,7 +108,7 @@ public function next(): void
108108
/**
109109
* @return string|null
110110
*/
111-
public function key()
111+
public function key(): mixed
112112
{
113113
$key = key($this->data);
114114

‎src/Session/Adapters/Database/DatabaseHandler.php‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,19 @@ public function destroy($id): bool
8585
}
8686

8787
/**
88-
* @inheritDoc
88+
* Deletes the expired sessions
89+
* @return int|false The number of deleted sessions, or false when they cannot be deleted
8990
*/
90-
public function gc($max_lifetime)
91+
public function gc($max_lifetime): int|false
9192
{
9293
$old = time() - $max_lifetime;
9394

94-
$result = $this->sessionModel->criteria('ttl', '<', $old)->deleteMany();
95+
$expired = $this->sessionModel->criteria('ttl', '<', $old)->count();
9596

96-
if ($result === false) {
97-
return false;
97+
if ($expired === 0) {
98+
return 0;
9899
}
99100

100-
return 0;
101+
return $this->sessionModel->criteria('ttl', '<', $old)->deleteMany() ? $expired : false;
101102
}
102103
}

‎tests/Unit/HttpClient/ResponseHeadersTest.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Quantum\HttpClient\ResponseHeaders;
66
use Quantum\Tests\Unit\AppTestCase;
7+
use ReflectionMethod;
78

89
class ResponseHeadersTest extends AppTestCase
910
{
@@ -33,4 +34,31 @@ public function testResponseHeadersCanUnsetCaseInsensitively(): void
3334
$this->assertCount(0, $headers);
3435
$this->assertNull($headers['Content-Type']);
3536
}
37+
38+
/**
39+
* @dataProvider interfaceMethodProvider
40+
*/
41+
public function testResponseHeadersDeclaresTheReturnTypeOfItsInterfaceMethods(string $method): void
42+
{
43+
$this->assertTrue((new ReflectionMethod(ResponseHeaders::class, $method))->hasReturnType());
44+
}
45+
46+
/**
47+
* @return array<string, array{0: string}>
48+
*/
49+
public function interfaceMethodProvider(): array
50+
{
51+
return [
52+
'offsetSet' => ['offsetSet'],
53+
'offsetExists' => ['offsetExists'],
54+
'offsetUnset' => ['offsetUnset'],
55+
'offsetGet' => ['offsetGet'],
56+
'count' => ['count'],
57+
'current' => ['current'],
58+
'next' => ['next'],
59+
'key' => ['key'],
60+
'valid' => ['valid'],
61+
'rewind' => ['rewind'],
62+
];
63+
}
3664
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace Quantum\Tests\Unit\Session\Adapters\Database;
4+
5+
use Quantum\Session\Adapters\Database\DatabaseHandler;
6+
use Quantum\Database\Adapters\Idiorm\IdiormDbal;
7+
use Quantum\Tests\Unit\Session\TestCaseHelper;
8+
use Quantum\Database\Contracts\DbalInterface;
9+
use Quantum\Model\Factories\ModelFactory;
10+
use Quantum\Tests\Unit\AppTestCase;
11+
use ReflectionMethod;
12+
use Mockery;
13+
14+
class DatabaseHandlerTest extends AppTestCase
15+
{
16+
use TestCaseHelper;
17+
18+
public function setUp(): void
19+
{
20+
parent::setUp();
21+
22+
IdiormDbal::connect(['driver' => 'sqlite', 'database' => ':memory:']);
23+
24+
$this->_createSessionsTable();
25+
}
26+
27+
public function tearDown(): void
28+
{
29+
ModelFactory::createDynamicModel('sessions')->deleteMany();
30+
31+
parent::tearDown();
32+
}
33+
34+
public function testDatabaseHandlerGcDeletesTheExpiredSessionsAndReturnsTheirNumber(): void
35+
{
36+
$this->insertSession('expired-1', time() - 7200);
37+
$this->insertSession('expired-2', time() - 5400);
38+
$this->insertSession('active', time());
39+
40+
$this->assertSame(2, $this->createHandler()->gc(3600));
41+
42+
$this->assertSame([['session_id' => 'active']], IdiormDbal::query('SELECT session_id FROM sessions'));
43+
}
44+
45+
public function testDatabaseHandlerGcReturnsZeroWhenNoSessionHasExpired(): void
46+
{
47+
$this->insertSession('active', time());
48+
49+
$this->assertSame(0, $this->createHandler()->gc(3600));
50+
51+
$this->assertSame([['session_id' => 'active']], IdiormDbal::query('SELECT session_id FROM sessions'));
52+
}
53+
54+
public function testDatabaseHandlerGcReturnsFalseWhenTheSessionsCannotBeDeleted(): void
55+
{
56+
$model = Mockery::mock(DbalInterface::class);
57+
$model->shouldReceive('criteria')->with('ttl', '<', Mockery::type('int'))->andReturnSelf();
58+
$model->shouldReceive('count')->andReturn(2);
59+
$model->shouldReceive('deleteMany')->andReturn(false);
60+
61+
$this->assertFalse((new DatabaseHandler($model))->gc(3600));
62+
}
63+
64+
/**
65+
* @dataProvider interfaceMethodProvider
66+
*/
67+
public function testDatabaseHandlerDeclaresTheReturnTypeOfItsInterfaceMethods(string $method): void
68+
{
69+
$this->assertTrue((new ReflectionMethod(DatabaseHandler::class, $method))->hasReturnType());
70+
}
71+
72+
/**
73+
* A handler serves one session, so every check gets a handler of its own
74+
*/
75+
private function createHandler(): DatabaseHandler
76+
{
77+
return new DatabaseHandler(ModelFactory::createDynamicModel('sessions')->getOrmInstance());
78+
}
79+
80+
private function insertSession(string $id, int $ttl): void
81+
{
82+
IdiormDbal::execute('INSERT INTO sessions (session_id, data, ttl) VALUES (?, ?, ?)', [$id, 'data', $ttl]);
83+
}
84+
85+
/**
86+
* @return array<string, array{0: string}>
87+
*/
88+
public function interfaceMethodProvider(): array
89+
{
90+
return [
91+
'open' => ['open'],
92+
'close' => ['close'],
93+
'read' => ['read'],
94+
'write' => ['write'],
95+
'destroy' => ['destroy'],
96+
'gc' => ['gc'],
97+
];
98+
}
99+
}

0 commit comments

Comments
 (0)