oasys/core 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

oasys/core

最新稳定版本:v1.0.0

Composer 安装命令:

composer require oasys/core

包简介

Minimal PSR-compatible HTTP framework with routing, middleware pipeline, and exception handling

README 文档

README

Minimal HTTP framework for modern PHP.

Works with any PSR-7 messages, PSR-15 middleware, and PSR-11 container.

  • Manual and attribute-based routing
  • Controller and method level middleware pipeline
  • Exception-to-handler mapping
  • Small dependency-free kernel

Installation

Example using PHP-DI container and Guzzle's request/response:

composer require oasys/core
composer require php-di/php-di
composer require guzzlehttp/psr7

Quick start

public/index.php:

<?php declare(strict_types=1);

use App\Controller\IndexController;
use Oasys\Kernel;
use Oasys\Routing\ExceptionMapper;
use Oasys\Routing\Router;
use DI\ContainerBuilder;
use GuzzleHttp\Psr7\ServerRequest;

require __DIR__ . '/../vendor/autoload.php';

// Build DI container
$builder = new ContainerBuilder();

$container = $builder->build();

// Build router and register routes
$router = new Router();

$router->get('/', [IndexController::class, 'home']);

// Map default exception handler
$exceptionMapper = new ExceptionMapper([IndexController::class, 'error']);

// Build kernel
$kernel = new Kernel(
    $container,
    $router,
    $exceptionMapper
);

// Build request
$request = ServerRequest::fromGlobals();

// Resolve request
$response = $kernel->resolve($request);

// Emit response
Kernel::send($response);

src/Controller/IndexController.php:

<?php declare(strict_types=1);

namespace App\Controller;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class IndexController
{
    public function home(ServerRequestInterface $request): ResponseInterface
    {
        return new Response(
            200,
            ['Content-Type' => 'text/plain; charset=utf-8'],
            "Welcome home\n"
        );
    }

    public function error(ServerRequestInterface $request): ResponseInterface
    {
        return new Response(
            500,
            ['Content-Type' => 'text/plain; charset=utf-8'],
            "Internal server error\n"
        );
    }
}

Routing

Manual routes

You can register routes manually

$router->get('/', [IndexController::class, 'home']);
$router->post('/contact-form', [ContactController::class, 'send']);
// put(), patch(), delete(), head(), options(), connect(), trace()

You can daisy-chain routes

$router
    ->get('/', [IndexController::class, 'home'])
    ->post('/contact-form', [ContactController::class, 'send']);

Route attributes

Alternatively, you can use attributes on controller method

use Oasys\Routing\Attributes\Get;
// Post, Put, Patch, Delete, Head, Options, Connect, Trace

#[Get('/')]
public function home(ServerRequestInterface $request): ResponseInterface
{
    // ...
}

...and auto-wire routes

$router->bind(IndexController::class);

You can use multiple attributes on a single method

#[Post('/contact-form')]
#[Put('/contact-form')]
public function send(ServerRequestInterface $request): ResponseInterface
{
    // ...
}

Path aliases

You can create dynamic route using alias by registering its pattern

$router = new Router([
    'id' => '\d+',
    // other aliases...
]);

...and then use placeholder in the path

$router->get('/user/{id}', [UserController::class, 'show']);

// or

#[Get('/user/{id}')]
public function show(ServerRequestInterface $request): ResponseInterface
{
    // ...
}

Middleware

You can use any PSR-15 middleware

<?php declare(strict_types=1);

namespace App\Middleware;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class TimingMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $start    = microtime(true);
        $response = $handler->handle($request);
        $elapsed  = number_format((microtime(true) - $start) * 1000, 2);

        return $response->withHeader('X-Response-Time-ms', (string) $elapsed);
    }
}

Scope

You can apply middleware using MiddlewareAttribute

Class-level attributes apply to all methods; method-level attributes apply only to that action

use Oasys\Middleware\MiddlewareAttribute as Middleware;

#[Middleware(TimingMiddleware::class)]
final class ProfileController
{
    #[Middleware(AuthMiddleware::class)]
    public function show(ServerRequestInterface $request): ResponseInterface
    {
        // ...
    }
}

Parameters

You can supply parameters to the middleware

#[Middleware(ContentTypeMiddleware::class, 'application/json' /* , other parameters...*/)]
public function show(ServerRequestInterface $request): ResponseInterface
{
    // ...
}

...and access them in the constructor

<?php declare(strict_types=1);

namespace App\Middleware;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class ContentTypeMiddleware implements MiddlewareInterface
{
    public function __construct(
        protected string $supported

        // other parameters...
    ) {}

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if ($request->getHeaderLine('Content-Type') !== $this->supported) {
            return new Response(
                400,
                ['Content-Type' => 'text/plain'],
                sprintf("Bad request: required Content-Type is: %s\n", $this->supported)
            );
        }

        return $handler->handle($request);
    }
}

Exception handling

Register default handler for any exception thrown during runtime

$exceptionMapper = new ExceptionMapper([ErrorController::class, 'serverError']);

You can register individual handlers for specific exception types

$exceptionMapper->register(NotFoundException::class, [ErrorController::class, 'notFound']);
$exceptionMapper->register(ValidationException::class, [ErrorController::class, 'badRequest']);

You can daisy-chain mapping

$exceptionMapper
    ->register(NotFoundException::class, [ErrorController::class, 'notFound'])
    ->register(ValidationException::class, [ErrorController::class, 'badRequest']);

When resolving a handler, ExceptionMapper will:

  • use a handler registered for the exact exception class
  • otherwise walk up the inheritance chain and use the first parent class that has a handler
  • otherwise fall back to the default handler registered in constructor

Any exception thrown inside controllers or middleware is passed to the handler via request attribute

<?php declare(strict_types=1);

namespace App\Controller;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

final class ErrorController
{
    public function serverError(ServerRequestInterface $request): ResponseInterface
    {
        /** @var Throwable|null $e */
        $e = $request->getAttribute(Throwable::class);

        return new Response(
            500,
            ['Content-Type' => 'text/plain; charset=utf-8'],
            sprintf("Internal Server Error: %s\n", $e?->getMessage())
        );
    }
}

Summary

  • Define controllers returning PSR-7 ResponseInterface
  • Add routing attributes to methods and auto-wire routes, or register routes manually on Router
  • Use MiddlewareAttribute to attach PSR-15 middleware to controllers and actions
  • Use ExceptionMapper to send exceptions to dedicated controllers
  • Let Kernel wire everything together and emit the response with Kernel::send()

统计信息

  • 总下载量: 2
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-12-06