diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 948ea04..7de7c9d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -132,7 +132,7 @@ jobs:
run: tar -xvf /tmp/github-actions/build.tar ./
- name: PHP Mess Detector
- uses: php-actions/phpmd@v1
+ uses: php-actions/phpmd@v2
with:
php_version: ${{ matrix.php }}
path: src/
diff --git a/composer.json b/composer.json
index cf6ee88..63dbf65 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,7 @@
"phpgt/typesafegetter": "^1.3"
},
"require-dev": {
- "phpstan/phpstan": "^1.10",
+ "phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^10.1",
"phpmd/phpmd": "^2.13",
"squizlabs/php_codesniffer": "^3.7"
diff --git a/composer.lock b/composer.lock
index 0160b61..a6e3f05 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d32bb34f857ad466056beaa4e80cf68a",
+ "content-hash": "90f742569783bb1b522aa97fe7d3d045",
"packages": [
{
"name": "phpgt/typesafegetter",
@@ -589,20 +589,20 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.12.25",
+ "version": "2.1.14",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "e310849a19e02b8bfcbb63147f495d8f872dd96f"
+ "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e310849a19e02b8bfcbb63147f495d8f872dd96f",
- "reference": "e310849a19e02b8bfcbb63147f495d8f872dd96f",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f2e03099cac24ff3b379864d171c5acbfc6b9a2",
+ "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2",
"shasum": ""
},
"require": {
- "php": "^7.2|^8.0"
+ "php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
@@ -643,7 +643,7 @@
"type": "github"
}
],
- "time": "2025-04-27T12:20:45+00:00"
+ "time": "2025-05-02T15:32:28+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -2840,12 +2840,12 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": {},
+ "stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.1"
},
- "platform-dev": {},
- "plugin-api-version": "2.6.0"
+ "platform-dev": [],
+ "plugin-api-version": "2.3.0"
}
diff --git a/phpcs.xml b/phpcs.xml
index b771656..ad96b86 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -25,7 +25,6 @@
-
diff --git a/src/Flash.php b/src/Flash.php
new file mode 100644
index 0000000..0e1e7c6
--- /dev/null
+++ b/src/Flash.php
@@ -0,0 +1,32 @@
+session->get("queue.$name");
+ if(!$queue) {
+ $queue = new SplQueue();
+ $this->session->set("queue.$name", $queue);
+ }
+
+ $queue->enqueue(new FlashMessage($name, $message));
+ }
+
+ public function consume(string $name):?FlashMessage {
+ /** @var null|SplQueue $queue */
+ $queue = $this->session->get("queue.$name");
+ try {
+ return $queue->dequeue();
+ }
+ catch(RuntimeException $e) {
+ $this->session->remove("queue.$name");
+ return null;
+ }
+ }
+
+}
diff --git a/src/FlashMessage.php b/src/FlashMessage.php
new file mode 100644
index 0000000..7475eff
--- /dev/null
+++ b/src/FlashMessage.php
@@ -0,0 +1,9 @@
+config["use_trans_sid"] && !$this->config["use_cookies"]) {
+ if(($this->config["use_trans_sid"] ?? null)
+ && !$this->config["use_cookies"]) {
return $_GET[$this->config["name"]] ?? session_create_id();
}
return session_create_id() ?: "";
@@ -196,7 +197,7 @@ private function getSessionOptions(
"serialize_handler" => "php_serialize",
"use_only_cookies" => $config["use_only_cookies"],
"use_cookies" => $config["use_cookies"],
- "use_trans_sid" => $config["use_trans_sid"],
+ "use_trans_sid" => $config["use_trans_sid"] ?? false,
"cookie_lifetime" => $config["cookie_lifetime"],
"cookie_path" => $config["cookie_path"],
"cookie_domain" => $config["cookie_domain"],
diff --git a/src/SessionStore.php b/src/SessionStore.php
index e1a32f3..e934303 100644
--- a/src/SessionStore.php
+++ b/src/SessionStore.php
@@ -1,20 +1,24 @@
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ */
+class SessionStore
+ extends ArrayIterator
+ implements SessionContainer, TypeSafeGetter, Countable {
use NullableTypeSafeGetter;
protected string $name;
protected Session $session;
/** @var array */
protected array $stores;
- /** @var array */
- protected array $data;
protected ?SessionStore $parentStore;
public function __construct(
@@ -26,23 +30,23 @@ public function __construct(
$this->session = $session;
$this->parentStore = $parentStore;
$this->stores = [];
- $this->data = [];
- }
-
- public function count():int {
- return count($this->data);
+ parent::__construct();
}
public function setData(string $key, mixed $value):void {
- $this->data[$key] = $value;
+ $this->offsetSet($key, $value);
}
public function getData(string $key):mixed {
- return $this->data[$key] ?? null;
+ if(!$this->offsetExists($key)) {
+ return null;
+ }
+
+ return $this->offsetGet($key);
}
public function containsData(string $key):bool {
- return isset($this->data[$key]);
+ return $this->offsetExists($key);
}
public function containsStore(string $key):bool {
@@ -50,7 +54,7 @@ public function containsStore(string $key):bool {
}
public function removeData(string $key):void {
- unset($this->data[$key]);
+ $this->offsetUnset($key);
}
public function removeStore(string $key):void {
diff --git a/test/FlashTest.php b/test/FlashTest.php
new file mode 100644
index 0000000..8056d6d
--- /dev/null
+++ b/test/FlashTest.php
@@ -0,0 +1,69 @@
+expects(self::once())
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn(null);
+ $sessionStore->expects(self::once())
+ ->method("set")
+ ->with(
+ self::equalTo("queue.test"),
+ self::isInstanceOf(SplQueue::class)
+ );
+
+ $sut = new Flash($sessionStore);
+ $sut->put("test", "Test message");
+ }
+
+ public function testConsume_none():void {
+ $queue = self::createMock(SplQueue::class);
+ $queue->expects(self::once())
+ ->method("dequeue")
+ ->willThrowException(new RuntimeException("Can't shift from an empty datastructure"));
+ $sessionStore = self::createMock(SessionStore::class);
+ $sessionStore->expects(self::once())
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn($queue);
+ $sut = new Flash($sessionStore);
+ $flashMessage = $sut->consume("test");
+ self::assertNull($flashMessage);
+ }
+
+ public function testConsume():void {
+ $fm1 = new FlashMessage("test", "First");
+ $fm2 = new FlashMessage("test", "Second");
+
+ $queue = self::createMock(SplQueue::class);
+ $queue->expects(self::exactly(3))
+ ->method("dequeue")
+ ->willReturnOnConsecutiveCalls($fm1, $fm2);
+
+ $sessionStore = self::createMock(SessionStore::class);
+ $sessionStore->expects(self::exactly(3))
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn($queue);
+ $sessionStore->expects(self::once())
+ ->method("remove")
+ ->with("queue.test");
+ $sut = new Flash($sessionStore);
+
+ $flashMessage = $sut->consume("test");
+ self::assertInstanceOf(FlashMessage::class, $flashMessage);
+ self::assertSame("First", $flashMessage->message);
+ $flashMessage = $sut->consume("test");
+ self::assertInstanceOf(FlashMessage::class, $flashMessage);
+ self::assertSame("Second", $flashMessage->message);
+ $flashMessage = $sut->consume("test");
+ self::assertNull($flashMessage);
+ }
+}
diff --git a/test/phpunit/SessionStoreTest.php b/test/phpunit/SessionStoreTest.php
index 27417b0..2124cb3 100644
--- a/test/phpunit/SessionStoreTest.php
+++ b/test/phpunit/SessionStoreTest.php
@@ -151,4 +151,25 @@ public function testCount():void {
self::assertCount(3, $sut);
}
+
+
+ public function testSessionStoreIsIterable():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $rawData = [
+ "key1" => "value1",
+ "key2" => "value2",
+ "key3" => "value3",
+ ];
+
+ foreach($rawData as $key => $value) {
+ $sut->set($key, $value);
+ }
+
+ foreach($sut as $key => $value) {
+ self::assertArrayHasKey($key, $rawData);
+ self::assertSame($rawData[$key], $value);
+ }
+ }
}