Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
improve: add SessionAdapter for hyperf compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
albertcht committed Jan 29, 2025
1 parent e6e9c5c commit b814da8
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/foundation/src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,8 @@ protected function registerCoreContainerAliases(): void
\SwooleTW\Hyperf\Router\UrlGenerator::class => ['url'],
\Hyperf\ViewEngine\Contract\FactoryInterface::class => ['view'],
\Hyperf\ViewEngine\Compiler\CompilerInterface::class => ['blade.compiler'],
\Hyperf\Contract\SessionInterface::class => ['session.store'],
\SwooleTW\Hyperf\Session\Contracts\Factory::class => ['session'],
\SwooleTW\Hyperf\Session\Contracts\Session::class => ['session.store'],
\SwooleTW\Hyperf\Foundation\Console\Contracts\Schedule::class => ['schedule'],
\SwooleTW\Hyperf\Mail\Contracts\Factory::class => [
'mail.manager',
Expand Down
79 changes: 79 additions & 0 deletions src/framework/src/View/Middleware/ValidationExceptionHandle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

declare(strict_types=1);

namespace SwooleTW\Hyperf\View\Middleware;

use Hyperf\Contract\MessageBag as MessageBagContract;
use Hyperf\Contract\MessageProvider;
use Hyperf\Support\MessageBag;
use Hyperf\Validation\ValidationException;
use Hyperf\ViewEngine\Contract\FactoryInterface;
use Hyperf\ViewEngine\ViewErrorBag;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use SwooleTW\Hyperf\Session\Contracts\Session as SessionContract;
use Throwable;

class ValidationExceptionHandle implements MiddlewareInterface
{
public function __construct(
protected ContainerInterface $container,
protected SessionContract $session,
protected FactoryInterface $view,
protected ResponseInterface $response
) {
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
$response = $handler->handle($request);
} catch (Throwable $throwable) {
if ($throwable instanceof ValidationException) {
/* @var ValidationException $throwable */
$this->withErrors($throwable->errors(), $throwable->errorBag);

/* @phpstan-ignore-next-line */
return $this->response->redirect(
$this->session->previousUrl()
);
}

throw $throwable;
}

return $response;
}

public function withErrors($provider, $key = 'default'): static
{
$value = $this->parseErrors($provider);

$errors = $this->session->get('errors', new ViewErrorBag());

if (! $errors instanceof ViewErrorBag) {
$errors = new ViewErrorBag();
}

/* @phpstan-ignore-next-line */
$this->session->flash(
'errors',
$errors->put($key, $value)
);

return $this;
}

protected function parseErrors($provider): MessageBagContract
{
if ($provider instanceof MessageProvider) {
return $provider->getMessageBag();
}

return new MessageBag((array) $provider);
}
}
19 changes: 19 additions & 0 deletions src/session/src/AdapterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace SwooleTW\Hyperf\Session;

use Hyperf\Contract\SessionInterface;
use Psr\Container\ContainerInterface;
use SwooleTW\Hyperf\Session\Contracts\Session as SessionContract;

class AdapterFactory
{
public function __invoke(ContainerInterface $container): SessionInterface
{
return new SessionAdapter(
$container->get(SessionContract::class)
);
}
}
2 changes: 1 addition & 1 deletion src/session/src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function __invoke(): array
'dependencies' => [
Factory::class => SessionManager::class,
SessionContract::class => StoreFactory::class,
SessionInterface::class => StoreFactory::class,
SessionInterface::class => AdapterFactory::class,
],
'publish' => [
[
Expand Down
2 changes: 1 addition & 1 deletion src/session/src/Contracts/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function getId(): ?string;
/**
* Set the session ID.
*/
public function setId(string $id): static;
public function setId(string $id): void;

/**
* Start the session, reading the data from a handler.
Expand Down
228 changes: 228 additions & 0 deletions src/session/src/SessionAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php

declare(strict_types=1);

namespace SwooleTW\Hyperf\Session;

use Hyperf\Contract\SessionInterface;
use Psr\Container\ContainerInterface;
use RuntimeException;
use SwooleTW\Hyperf\Session\Contracts\Session as SessionContract;

class SessionAdapter implements SessionInterface
{
public function __invoke(ContainerInterface $container): SessionInterface
{
return new static(
$container->get(SessionContract::class)
);
}

public function __construct(
protected SessionContract $session,
) {
}

/**
* Starts the session storage.
*
* @return bool True if session started
* @throws RuntimeException if session fails to start
*/
public function start(): bool
{
return $this->session->start();
}

/**
* Returns the session ID.
*
* @return string The session ID
*/
public function getId(): string
{
return $this->session->getId();
}

/**
* Sets the session ID.
*/
public function setId(string $id): void
{
$this->session->setId($id);
}

/**
* Returns the session name.
*/
public function getName(): string
{
return $this->session->getName();
}

/**
* Sets the session name.
*/
public function setName(string $name): void
{
$this->session->setName($name);
}

/**
* Invalidates the current session.
*
* Clears all session attributes and flashes and regenerates the
* session and deletes the old session from persistence.
*
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return bool True if session invalidated, false if error
*/
public function invalidate(?int $lifetime = null): bool
{
return $this->session->invalidate();
}

/**
* Migrates the current session to a new session id while maintaining all
* session attributes.
*
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return bool True if session migrated, false if error
*/
public function migrate(bool $destroy = false, ?int $lifetime = null): bool
{
return $this->session->migrate($destroy);
}

/**
* Force the session to be saved and closed.
*
* This method is generally not required for real sessions as
* the session will be automatically saved at the end of
* code execution.
*/
public function save(): void
{
$this->session->save();
}

/**
* Checks if an attribute is defined.
*
* @param string $name The attribute name
*
* @return bool true if the attribute is defined, false otherwise
*/
public function has(string $name): bool
{
return $this->session->has($name);
}

/**
* Returns an attribute.
*
* @param string $name The attribute name
* @param mixed $default The default value if not found
*/
public function get(string $name, $default = null): mixed
{
return $this->session->get($name, $default);
}

/**
* Sets an attribute.
* @param mixed $value
*/
public function set(string $name, $value): void
{
$this->session->put($name, $value);
}

/**
* Put a key / value pair or array of key / value pairs in the session.
*
* @param array|string $key
* @param null|mixed $value
*/
public function put($key, $value = null): void
{
$this->session->put($key, $value);
}

/**
* Returns attributes.
*/
public function all(): array
{
return $this->session->all();
}

/**
* Sets attributes.
*/
public function replace(array $attributes): void
{
$this->session->put($attributes);
}

/**
* Removes an attribute, returning its value.
*
* @return mixed The removed value or null when it does not exist
*/
public function remove(string $name): mixed
{
return $this->session->remove($name);
}

/**
* Remove one or many items from the session.
*
* @param array|string $keys
*/
public function forget($keys): void
{
$this->session->forget($keys);
}

/**
* Clears all attributes.
*/
public function clear(): void
{
$this->session->flush();
}

/**
* Checks if the session was started.
*/
public function isStarted(): bool
{
return $this->session->isStarted();
}

/**
* Get the previous URL from the session.
*/
public function previousUrl(): ?string
{
return $this->session->previousUrl();
}

/**
* Set the "previous" URL in the session.
*/
public function setPreviousUrl(string $url): void
{
$this->session->setPreviousUrl($url);
}
}
4 changes: 1 addition & 3 deletions src/session/src/Store.php
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,12 @@ public function getId(): ?string
/**
* Set the session ID.
*/
public function setId(?string $id): static
public function setId(?string $id): void
{
Context::set(
'_session.store.id',
$this->isValidId($id) ? $id : $this->generateSessionId()
);

return $this;
}

/**
Expand Down
8 changes: 6 additions & 2 deletions tests/Session/EncryptedSessionStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ public function testSessionIsProperlyEncrypted()

public function getSession(): EncryptedStore
{
return (new EncryptedStore(
$store = new EncryptedStore(
$this->getSessionName(),
m::mock(SessionHandlerInterface::class),
m::mock(Encrypter::class)
))->setId($this->getSessionId());
);

$store->setId($this->getSessionId());

return $store;
}

protected function getSessionId(): string
Expand Down
Loading

0 comments on commit b814da8

Please sign in to comment.