From 9c9efd0c19d05c55bffd077e14c713f3af85f555 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 8 Feb 2022 08:44:00 +0100 Subject: [PATCH] Added SessionMap to aid in session programming --- modules/Collection/src/IsKeyedEnumerable.php | 2 + modules/Core/src/Handler/HandledRequest.php | 5 +- .../src/Handler/HandledRequestBuilder.php | 11 ++- modules/Http/src/Contract/ParameterMap.php | 2 +- modules/Http/src/Contract/ServerRequest.php | 5 +- .../src/Contract/ServerRequestBuilder.php | 8 +- modules/Http/src/Contract/SessionMap.php | 18 ++++ modules/Http/src/ParameterMap.php | 10 +- modules/Http/src/ParameterSource.php | 1 - modules/Http/src/ServerRequest.php | 13 ++- modules/Http/src/ServerRequestBuilder.php | 45 ++++++--- modules/Http/src/SessionMap.php | 99 +++++++++++++++++++ 12 files changed, 187 insertions(+), 32 deletions(-) create mode 100644 modules/Http/src/Contract/SessionMap.php create mode 100644 modules/Http/src/SessionMap.php diff --git a/modules/Collection/src/IsKeyedEnumerable.php b/modules/Collection/src/IsKeyedEnumerable.php index 2dcb4844..50ffa1cf 100644 --- a/modules/Collection/src/IsKeyedEnumerable.php +++ b/modules/Collection/src/IsKeyedEnumerable.php @@ -435,6 +435,7 @@ public function lastOrDefault(mixed $default, ?callable $predicate = null): mixe */ public function max(callable $selector): int|float|string { + /** @var Iterator $iterator */ $iterator = $this->getIterator(); $iterator->rewind(); if (!$iterator->valid()) { @@ -460,6 +461,7 @@ public function max(callable $selector): int|float|string */ public function min(callable $selector): int|float|string { + /** @var Iterator $iterator */ $iterator = $this->getIterator(); $iterator->rewind(); if (!$iterator->valid()) { diff --git a/modules/Core/src/Handler/HandledRequest.php b/modules/Core/src/Handler/HandledRequest.php index d15b7522..ff2b1093 100644 --- a/modules/Core/src/Handler/HandledRequest.php +++ b/modules/Core/src/Handler/HandledRequest.php @@ -6,6 +6,7 @@ use Elephox\Http\Contract\CookieMap; use Elephox\Http\Contract\HeaderMap; use Elephox\Http\Contract\ParameterMap; +use Elephox\Http\Contract\SessionMap; use Elephox\Http\Contract\UploadedFileMap; use Elephox\Http\ServerRequest; use Elephox\Http\RequestMethod; @@ -26,10 +27,11 @@ public function __construct( Url $url, ParameterMap $parameters, CookieMap $cookies, + ?SessionMap $session, UploadedFileMap $uploadedFiles, public readonly Contract\MatchedUrlTemplate $template ) { - parent::__construct($protocolVersion, $headers, $body, $method, $url, $parameters, $cookies, $uploadedFiles); + parent::__construct($protocolVersion, $headers, $body, $method, $url, $parameters, $cookies, $session, $uploadedFiles); } #[Pure] @@ -49,6 +51,7 @@ public function with(): Contract\HandledRequestBuilder $this->url, $this->parameters, $this->cookies, + $this->session, $this->uploadedFiles, $this->template, ); diff --git a/modules/Core/src/Handler/HandledRequestBuilder.php b/modules/Core/src/Handler/HandledRequestBuilder.php index 258878a3..9f2bddb3 100644 --- a/modules/Core/src/Handler/HandledRequestBuilder.php +++ b/modules/Core/src/Handler/HandledRequestBuilder.php @@ -32,7 +32,8 @@ public static function fromRequest(Request $request): static $request->getMethod(), $request->getUrl(), $request instanceof ServerRequest ? $request->getParameters() : null, - $request instanceof ServerRequest ? $request->getCookieMap() : null, + $request instanceof ServerRequest ? $request->getCookies() : null, + $request instanceof ServerRequest ? $request->getSession() : null, $request instanceof ServerRequest ? $request->getUploadedFiles() : null, $request instanceof Contract\HandledRequest ? $request->getMatchedTemplate() : null, ); @@ -46,11 +47,12 @@ public function __construct( ?RequestMethod $method = null, ?Url $url = null, ?HttpContract\ParameterMap $parameters = null, - ?HttpContract\CookieMap $cookieMap = null, + ?HttpContract\CookieMap $cookies = null, + ?HttpContract\SessionMap $session = null, ?HttpContract\UploadedFileMap $uploadedFiles = null, protected ?Contract\MatchedUrlTemplate $matchedTemplate = null ) { - parent::__construct($protocolVersion, $headers, $body, $method, $url, $parameters, $cookieMap, $uploadedFiles); + parent::__construct($protocolVersion, $headers, $body, $method, $url, $parameters, $cookies, $session, $uploadedFiles); } public function matchedTemplate(Contract\MatchedUrlTemplate $matchedUrlTemplate): static @@ -69,7 +71,8 @@ public function get(): Contract\HandledRequest $this->method ?? RequestMethod::GET, $this->url ?? throw self::missingParameterException("url"), $this->parameters ?? new ParameterMap(), - $this->cookieMap ?? new CookieMap(), + $this->cookies ?? new CookieMap(), + $this->session, $this->uploadedFiles ?? new UploadedFileMap(), $this->matchedTemplate ?? throw self::missingParameterException("template") ); diff --git a/modules/Http/src/Contract/ParameterMap.php b/modules/Http/src/Contract/ParameterMap.php index 32df2dee..56af6f97 100644 --- a/modules/Http/src/Contract/ParameterMap.php +++ b/modules/Http/src/Contract/ParameterMap.php @@ -9,7 +9,7 @@ interface ParameterMap extends ArrayAccess { - public static function fromGlobals(?array $post = null, ?array $get = null, ?array $session = null, ?array $server = null, ?array $env = null): ParameterMap; + public static function fromGlobals(?array $post = null, ?array $get = null, ?array $server = null, ?array $env = null): ParameterMap; public function get(string $key, ?ParameterSource $source = null): mixed; diff --git a/modules/Http/src/Contract/ServerRequest.php b/modules/Http/src/Contract/ServerRequest.php index 49915a12..51be9fc6 100644 --- a/modules/Http/src/Contract/ServerRequest.php +++ b/modules/Http/src/Contract/ServerRequest.php @@ -19,8 +19,11 @@ public function with(): ServerRequestBuilder; public function getParameters(): ParameterMap; #[Pure] - public function getCookieMap(): CookieMap; + public function getCookies(): CookieMap; #[Pure] public function getUploadedFiles(): UploadedFileMap; + + #[Pure] + public function getSession(): ?SessionMap; } diff --git a/modules/Http/src/Contract/ServerRequestBuilder.php b/modules/Http/src/Contract/ServerRequestBuilder.php index c01e4d5a..470515ef 100644 --- a/modules/Http/src/Contract/ServerRequestBuilder.php +++ b/modules/Http/src/Contract/ServerRequestBuilder.php @@ -16,15 +16,19 @@ public static function fromGlobals(): ServerRequest; public function parameter(string $key, int|string|array $value, ParameterSource $source): static; - public function parameterMap(ParameterMap $parameterMap): static; + public function parameters(ParameterMap $parameters): static; public function cookie(Cookie $cookie): static; - public function cookieMap(CookieMap $cookieMap): static; + public function cookies(CookieMap $cookies): static; public function uploadedFile(string $name, UploadedFile $uploadedFile): static; public function uploadedFiles(UploadedFileMap $uploadedFiles): static; + public function sessionParam(string $name, mixed $value): static; + + public function session(SessionMap $session): static; + public function get(): ServerRequest; } diff --git a/modules/Http/src/Contract/SessionMap.php b/modules/Http/src/Contract/SessionMap.php new file mode 100644 index 00000000..9d34b9ae --- /dev/null +++ b/modules/Http/src/Contract/SessionMap.php @@ -0,0 +1,18 @@ + + */ +interface SessionMap extends GenericMap +{ + /** + * @param null|array $session + * @return null|SessionMap + */ + public static function fromGlobals(?array $session = null, bool $recreate = false): ?SessionMap; +} diff --git a/modules/Http/src/ParameterMap.php b/modules/Http/src/ParameterMap.php index 2fa02bdc..2f0b101a 100644 --- a/modules/Http/src/ParameterMap.php +++ b/modules/Http/src/ParameterMap.php @@ -95,11 +95,10 @@ public function all(?ParameterSource $source = null): GenericEnumerable return new Enumerable($iterator); } - public static function fromGlobals(?array $post = null, ?array $get = null, ?array $session = null, ?array $server = null, ?array $env = null): Contract\ParameterMap + public static function fromGlobals(?array $post = null, ?array $get = null, ?array $server = null, ?array $env = null): Contract\ParameterMap { $post ??= $_POST; $get ??= $_GET; - $session ??= $_SESSION ?? []; $server ??= $_SERVER; $env ??= $_ENV; @@ -161,13 +160,6 @@ public static function fromGlobals(?array $post = null, ?array $get = null, ?arr $map->put($name, ParameterSource::Post, $value); } - /** - * @var mixed $value - */ - foreach ($session as $name => $value) { - $map->put($name, ParameterSource::Session, $value); - } - /** * @var mixed $value */ diff --git a/modules/Http/src/ParameterSource.php b/modules/Http/src/ParameterSource.php index 2dc00349..d9d0da25 100644 --- a/modules/Http/src/ParameterSource.php +++ b/modules/Http/src/ParameterSource.php @@ -10,7 +10,6 @@ enum ParameterSource { case Post; case Get; - case Session; case Server; case Env; } diff --git a/modules/Http/src/ServerRequest.php b/modules/Http/src/ServerRequest.php index 5981f8c8..74f0bd1d 100644 --- a/modules/Http/src/ServerRequest.php +++ b/modules/Http/src/ServerRequest.php @@ -6,6 +6,7 @@ use Elephox\Http\Contract\CookieMap; use Elephox\Http\Contract\HeaderMap; use Elephox\Http\Contract\ParameterMap; +use Elephox\Http\Contract\SessionMap; use Elephox\Http\Contract\UploadedFileMap; use Elephox\Stream\Contract\Stream; use JetBrains\PhpStorm\Immutable; @@ -29,6 +30,7 @@ public function __construct( Url $url, public readonly ParameterMap $parameters, public readonly CookieMap $cookies, + public readonly ?SessionMap $session, public readonly UploadedFileMap $uploadedFiles ) { parent::__construct($protocolVersion, $headers, $body, $method, $url); @@ -45,7 +47,8 @@ public function with(): Contract\ServerRequestBuilder $this->url, $this->parameters, $this->cookies, - $this->uploadedFiles + $this->session, + $this->uploadedFiles, ); } @@ -56,7 +59,7 @@ public function getParameters(): ParameterMap } #[Pure] - public function getCookieMap(): CookieMap + public function getCookies(): CookieMap { return $this->cookies; } @@ -66,4 +69,10 @@ public function getUploadedFiles(): UploadedFileMap { return $this->uploadedFiles; } + + #[Pure] + public function getSession(): ?SessionMap + { + return $this->session; + } } diff --git a/modules/Http/src/ServerRequestBuilder.php b/modules/Http/src/ServerRequestBuilder.php index 9bc4ec86..a9980d69 100644 --- a/modules/Http/src/ServerRequestBuilder.php +++ b/modules/Http/src/ServerRequestBuilder.php @@ -25,7 +25,8 @@ public function __construct( ?RequestMethod $method = null, ?Url $url = null, protected ?Contract\ParameterMap $parameters = null, - protected ?Contract\CookieMap $cookieMap = null, + protected ?Contract\CookieMap $cookies = null, + protected ?Contract\SessionMap $session = null, protected ?Contract\UploadedFileMap $uploadedFiles = null ) { parent::__construct($protocolVersion, $headers, $body, $method, $url); @@ -42,27 +43,45 @@ public function parameter(string $key, array|int|string $value, ParameterSource return $this; } - public function parameterMap(Contract\ParameterMap $parameterMap): static + public function parameters(Contract\ParameterMap $parameters): static { - $this->parameters = $parameterMap; + $this->parameters = $parameters; return $this; } public function cookie(Cookie $cookie): static { - if ($this->cookieMap === null) { - $this->cookieMap = new CookieMap(); + if ($this->cookies === null) { + $this->cookies = new CookieMap(); } - $this->cookieMap->put($cookie->getName(), $cookie); + $this->cookies->put($cookie->getName(), $cookie); return $this; } - public function cookieMap(Contract\CookieMap $cookieMap): static + public function cookies(Contract\CookieMap $cookies): static { - $this->cookieMap = $cookieMap; + $this->cookies = $cookies; + + return $this; + } + + public function sessionParam(string $name, mixed $value): static + { + if ($this->session === null) { + $this->session = SessionMap::start([]); + } + + $this->session->put($name, $value); + + return $this; + } + + public function session(?Contract\SessionMap $session): static + { + $this->session = $session; return $this; } @@ -94,7 +113,8 @@ public function get(): Contract\ServerRequest $this->method ?? RequestMethod::GET, $this->url ?? throw self::missingParameterException("url"), $this->parameters ?? new ParameterMap(), - $this->cookieMap ?? new CookieMap(), + $this->cookies ?? new CookieMap(), + $this->session, $this->uploadedFiles ?? new UploadedFileMap() ); } @@ -103,6 +123,7 @@ public static function fromGlobals( ?Contract\ParameterMap $parameters = null, ?Contract\HeaderMap $headers = null, ?Contract\CookieMap $cookies = null, + ?Contract\SessionMap $session = null, ?Contract\UploadedFileMap $files = null, ?string $protocolVersion = AbstractMessageBuilder::DefaultProtocolVersion, ?Stream $body = null, @@ -113,12 +134,14 @@ public static function fromGlobals( $parameters ??= ParameterMap::fromGlobals(); $headers ??= HeaderMap::fromGlobals(); $cookies ??= CookieMap::fromGlobals(); + $session ??= SessionMap::fromGlobals(); $files ??= UploadedFileMap::fromGlobals(); $builder = new self(); - $builder->parameterMap($parameters); + $builder->parameters($parameters); $builder->headerMap($headers); - $builder->cookieMap($cookies); + $builder->cookies($cookies); + $builder->session($session); $builder->uploadedFiles($files); if ($body === null) { diff --git a/modules/Http/src/SessionMap.php b/modules/Http/src/SessionMap.php new file mode 100644 index 00000000..430cf6c6 --- /dev/null +++ b/modules/Http/src/SessionMap.php @@ -0,0 +1,99 @@ + $value) { + $map->put($key, $value); + } + + return $map; + } + + public static function start(): Contract\SessionMap + { + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + + return new SessionMap(); + } + + public static function destroy(): void + { + if (session_status() === PHP_SESSION_ACTIVE) { + session_destroy(); + } + } + + /** + * @uses IsKeyedEnumerable + */ + use IsKeyedEnumerable; + use DeepCloneable; + + private function __construct() + { + } + + public function put(mixed $key, mixed $value): bool + { + /** @psalm-suppress MixedAssignment */ + $_SESSION[$key] = $value; + + return true; + } + + public function get(mixed $key): mixed + { + /** @psalm-suppress MixedReturnStatement */ + return $_SESSION[$key] ?? null; + } + + public function has(mixed $key): bool + { + return isset($_SESSION[$key]); + } + + public function remove(mixed $key): bool + { + if (!$this->has($key)) { + return false; + } + + unset($_SESSION[$key]); + + return true; + } + + public function getIterator(): ArrayIterator + { + return new ArrayIterator($_SESSION); + } +}