diff --git a/features/access.feature b/features/access.feature index 9960f38..1aaddb8 100644 --- a/features/access.feature +++ b/features/access.feature @@ -2,19 +2,28 @@ Feature: Session access Scenario: Check data does not exist When data does not exist Then property check returns false + And array access check returns false Scenario: Check data exist When data exists Then property check returns true + And array access check returns true Scenario: Read data that exists When data exists Then property read returns data + And array access read returns data Scenario: Read data that does not exist When data does not exist Then property read triggers error And property read returns null + And array access read triggers error + And array access read returns null Scenario: Null coalesce when data does not exist When data does not exist Then property read with null coalesce returns null - Scenario: Write data + And array access read with null coalesce returns null + Scenario: Write property data When data does not exist Then property write succeeds + Scenario: Write array access data + When data does not exist + Then array access write succeeds diff --git a/src/Session.php b/src/Session.php index 02db40e..0077a42 100644 --- a/src/Session.php +++ b/src/Session.php @@ -5,9 +5,10 @@ namespace Compwright\PhpSession; use Countable; +use ArrayAccess; use RuntimeException; -class Session implements Countable +class Session implements ArrayAccess, Countable { protected string $name; @@ -94,6 +95,48 @@ public function __unset(string $name): void unset($this->contents[$name]); } + public function offsetSet($name, $value): void + { + if (!$this->isInitialized()) { + throw new RuntimeException('Session not initialized'); + } + + if (!$this->writeable) { + throw new RuntimeException('Cannot alter session after it is closed'); + } + + $this->modified = true; + $this->contents[$name] = $value; + } + + public function offsetExists($name): bool + { + if (!$this->isInitialized()) { + throw new RuntimeException('Session not initialized'); + } + + return isset($this->contents[$name]); + } + + public function offsetUnset($name): void + { + if (!$this->isInitialized()) { + throw new RuntimeException('Session not initialized'); + } + + if (!$this->writeable) { + throw new RuntimeException('Cannot alter session after it is closed'); + } + + $this->modified = true; + unset($this->contents[$name]); + } + + public function offsetGet($name): mixed + { + return $this->contents[$name]; + } + /** * @param ?array $contents */ diff --git a/tests/behavior/AccessContext.php b/tests/behavior/AccessContext.php index fd91a08..d3c4bc5 100644 --- a/tests/behavior/AccessContext.php +++ b/tests/behavior/AccessContext.php @@ -101,4 +101,72 @@ public function propertyWriteSucceeds(): void Assert::assertCount(1, $this->session); Assert::assertTrue(isset($this->session->bar)); } + + /** + * @Then array access check returns true + */ + public function arrayAccessCheckReturnsTrue(): void + { + Assert::assertTrue(isset($this->session['foo'])); + } + + /** + * @Then array access check returns false + */ + public function arrayAccessCheckReturnsFalse(): void + { + Assert::assertFalse(isset($this->session['foo'])); + } + + /** + * @Then array access read returns data + */ + public function arrayAccessReadReturnsData(): void + { + Assert::assertEquals('bar', $this->session['foo']); + } + + /** + * @Then array access read triggers error + */ + public function arrayAccessReadTriggersNoticeError(): void + { + try { + $errorThrown = false; + $bar = $this->session['bar']; + // @phpstan-ignore-next-line + } catch (Throwable $e) { + $errorThrown = true; + } finally { + Assert::assertTrue($errorThrown); + } + } + + /** + * @Then array access read returns null + */ + public function arrayAccessReadReturnsNull(): void + { + $bar = @$this->session['foo']; + Assert::assertSame(null, $bar); + } + + /** + * @Then array access read with null coalesce returns null + */ + public function arrayAccessReadWithNullCoalesceReturnsNull(): void + { + $bar = $this->session['foo'] ?? null; + Assert::assertSame(null, $bar); + } + + /** + * @Then array access write succeeds + */ + public function arrayAccessWriteSucceeds(): void + { + $this->session['bar'] = 'baz'; + Assert::assertCount(1, $this->session); + Assert::assertTrue(isset($this->session['bar'])); + } }