PHPackages                             phpsoftbox/application - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. phpsoftbox/application

ActiveLibrary[Framework](/categories/framework)

phpsoftbox/application
======================

Application core for the PhpSoftBox framework

0128↓87.5%PHP

Since Jun 22Pushed 1w agoCompare

[ Source](https://github.com/phpsoftbox/application)[ Packagist](https://packagist.org/packages/phpsoftbox/application)[ RSS](/packages/phpsoftbox-application/feed)WikiDiscussions master Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

Application
===========

[](#application)

Минимальное приложение для работы с PSR-15 пайплайном.

Быстрый старт
-------------

[](#быстрый-старт)

```
use PhpSoftBox\Application\Application;
use PhpSoftBox\Application\ErrorHandler\JsonExceptionHandler;
use PhpSoftBox\Application\ErrorHandler\HtmlExceptionHandler;
use PhpSoftBox\Application\ErrorHandler\ContentNegotiationExceptionHandler;
use PhpSoftBox\Application\Middleware\ErrorHandlerMiddleware;
use PhpSoftBox\Router\Router;

$router = new Router($resolver, $dispatcher, $collector);
$exceptionHandler = new ContentNegotiationExceptionHandler(
    new JsonExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
    new HtmlExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
);

$app = new Application($router, [
    new ErrorHandlerMiddleware($exceptionHandler),
]);

$response = $app->handle($request);
```

Настройка формата ошибок (Deciders)
-----------------------------------

[](#настройка-формата-ошибок-deciders)

`ContentNegotiationExceptionHandler` поддерживает реестр deciders для выбора формата ответа на ошибку. Decider возвращает `ExceptionFormat::JSON`, `ExceptionFormat::HTML` или `null` (тогда срабатывает стандартная логика по `Accept` и `X-Requested-With`).

```
use PhpSoftBox\Application\ErrorHandler\ContentNegotiationExceptionHandler;
use PhpSoftBox\Application\ErrorHandler\ExceptionFormat;
use PhpSoftBox\Application\ErrorHandler\ExceptionFormatDeciderInterface;
use PhpSoftBox\Application\ErrorHandler\ExceptionFormatDeciderRegistry;
use PhpSoftBox\Application\ErrorHandler\HtmlExceptionHandler;
use PhpSoftBox\Application\ErrorHandler\JsonExceptionHandler;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

final class ApiExceptionDecider implements ExceptionFormatDeciderInterface
{
    public function __invoke(Throwable $exception, ServerRequestInterface $request): ?ExceptionFormat
    {
        $path = ltrim($request->getUri()->getPath(), '/');
        if (str_starts_with($path, 'api/')) {
            return ExceptionFormat::JSON;
        }

        if ($request->getHeaderLine('X-Inertia') !== '') {
            return ExceptionFormat::HTML;
        }

        return null;
    }
}

$deciders = new ExceptionFormatDeciderRegistry([
    new ApiExceptionDecider(),
]);

$exceptionHandler = new ContentNegotiationExceptionHandler(
    new JsonExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
    new HtmlExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
    $deciders,
);
```

Репортинг ошибок в ErrorHub
---------------------------

[](#репортинг-ошибок-в-errorhub)

```
use PhpSoftBox\Application\ErrorHandler\DefaultExceptionHandler;
use PhpSoftBox\Application\ErrorHandler\ErrorHubExceptionReporter;
use PhpSoftBox\Application\ErrorHandler\LoggerExceptionReporter;
use PhpSoftBox\Application\Middleware\ErrorHandlerMiddleware;

$errorhubReporter = new ErrorHubExceptionReporter(
    baseUrl: 'https://errorhub.getstash-dev.ru',
    projectKey: 'YOUR_PROJECT_KEY',
    token: 'YOUR_BEARER_TOKEN', // опционально
    username: null, // опционально (basic auth)
    password: null,
    tags: ['env:prod', 'app:backend'],
);

$fallback = new ContentNegotiationExceptionHandler(
    new JsonExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
    new HtmlExceptionHandler($responseFactory, $streamFactory, includeDetails: true),
);

$exceptionHandler = new DefaultExceptionHandler(
    fallbackHandler: $fallback,
    responseFactory: $responseFactory,
    session: $session,
    reporters: [
        new LoggerExceptionReporter($logger),
        $errorhubReporter,
    ],
);

$app = new Application($router, [
    new ErrorHandlerMiddleware($exceptionHandler),
]);
```

Если нужно добавить теги на уровне конкретного исключения:

```
use PhpSoftBox\Application\ErrorHandler\ErrorHubExceptionInterface;
use PhpSoftBox\Application\ErrorHandler\ErrorHubExceptionTrait;

final class BillingException extends \RuntimeException implements ErrorHubExceptionInterface
{
    use ErrorHubExceptionTrait;
}

$e = new BillingException('Payment failed');
$e->setErrorHubTags(['module:billing']);
$e->setErrorHubContext(['order_id' => 42]);
```

RouterFactory + RouteCache
--------------------------

[](#routerfactory--routecache)

```
use PhpSoftBox\Application\RouterFactory;
use PhpSoftBox\Router\Cache\RouteCache;
use PhpSoftBox\Router\Dispatcher;

$cache = new RouteCache($cacheStorage);
$factory = new RouterFactory(new Dispatcher(), $cache);

$router = $factory->create(function ($routes) {
    $routes->get('/users', [UserController::class, 'index']);
});
```

AppFactory
----------

[](#appfactory)

```
use PhpSoftBox\Application\AppFactory;

$app = AppFactory::createFromContainer($container, environment: 'prod');

if (!$app->routesCached()) {
    require __DIR__ . '/routes.php';
}
```

Регистрация middleware
----------------------

[](#регистрация-middleware)

```
use PhpSoftBox\Application\Application;
use PhpSoftBox\Application\Middleware\ErrorHandlerMiddleware;
use PhpSoftBox\Application\Middleware\RequestSizeLimitMiddleware;
use PhpSoftBox\Session\SessionMiddleware;

$app = new Application($router, container: $container);

$app->add(new ErrorHandlerMiddleware($exceptionHandler), priority: 100);
$app->add(RequestSizeLimitMiddleware::class);

$app->alias('session', SessionMiddleware::class);
$app->middlewareGroup('web', ['session']);
```

Группы middleware
-----------------

[](#группы-middleware)

```
$webApp = $app->withMiddlewareGroups(['web']);
$response = $webApp->handle($request);
```

Регистрация роутов через Application
------------------------------------

[](#регистрация-роутов-через-application)

```
$app->get('/users', [UserController::class, 'index']);
$app->post('/users', [UserController::class, 'store']);
```

Методы проксируются в `RouteCollector`, если приложение создано с `Router`.

Middleware для контроллеров
---------------------------

[](#middleware-для-контроллеров)

```
$app->controllerMiddleware(UserController::class, ['auth']);
$app->controllerMiddleware(UserController::class, ['admin'], only: ['store', 'update']);
```

Рекомендуемый путь привязки Middleware — регистрация через Router на маршруты/группы; контроллеры/экшены используйте точечно.

Группы middleware для маршрутов
-------------------------------

[](#группы-middleware-для-маршрутов)

```
use PhpSoftBox\Application\Middleware\KernelRouteMiddlewareResolver;
use PhpSoftBox\Router\Dispatcher;
use PhpSoftBox\Router\Router;

$app->alias('auth', \PhpSoftBox\Auth\Middleware\AuthMiddleware::class);
$app->middlewareGroup('api', ['auth']);

$dispatcher = new Dispatcher(
    handlerResolver: null,
    middlewareResolver: new KernelRouteMiddlewareResolver($app->middlewareManager(), $container),
);

$router = new Router($resolver, $dispatcher, $collector);

$collector->group('/api', function ($routes) {
    $routes->get('/users', [UserController::class, 'index']);
}, ['api']);
```

Ответы
------

[](#ответы)

В приложении доступны готовые ответы:

- `JsonResponse`
- `HtmlResponse`
- `XmlResponse`
- `TextResponse`

Пример:

```
use PhpSoftBox\Application\Response\JsonResponse;

return new JsonResponse(['ok' => true]);
```

Ошибки роутера
--------------

[](#ошибки-роутера)

`InvalidRouteParameterException` (например, когда параметр не проходит валидацию) в прод-режиме возвращает 404 `Not Found`. В debug-режиме сообщение исключения возвращается в ответе.

Авторизация приватных каналов Broadcaster
-----------------------------------------

[](#авторизация-приватных-каналов-broadcaster)

Обычно требуется эндпоинт `/broadcast/auth`, который выдаёт `auth` для приватных каналов. Пример с `PushrChannelAuth`:

```
use PhpSoftBox\Broadcaster\Pushr\PushrChannelAuth;
use PhpSoftBox\Http\Message\Response;
use Psr\Http\Message\ServerRequestInterface;
use function json_encode;

$app->post('/broadcast/auth', function (ServerRequestInterface $request, \PhpSoftBox\Broadcaster\Channel\ChannelRegistry $channels): Response {
    $data = (array) ($request->getParsedBody() ?? []);

    $socketId = (string) ($data['socket_id'] ?? '');
    $channel = (string) ($data['channel'] ?? '');
    $channelData = $data['channel_data'] ?? null;

    $authorization = $channels->authorize($channel, $request);
    if (!$authorization->authorized()) {
        return new Response(403);
    }

    $channelData = $authorization->channelData() ?? $channelData;

    $auth = PushrChannelAuth::token('app-1', 'secret-1', $socketId, $channel, $channelData);

    return new Response(200, ['Content-Type' => 'application/json'], json_encode([
        'auth' => $auth,
        'channel_data' => $channelData,
    ]));
});
```

`socket_id` клиент получает из события `connection` после подключения к WebSocket.

###  Health Score

24

—

LowBetter than 31% of packages

Maintenance64

Regular maintenance activity

Popularity13

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/0279d150240c97d210034878b0467462246dc14d29b5618157ff6a8be49a50e3?d=identicon)[inspector-who](/maintainers/inspector-who)

---

Top Contributors

[![inspector-who](https://avatars.githubusercontent.com/u/6973963?v=4)](https://github.com/inspector-who "inspector-who (1 commits)")

### Embed Badge

![Health badge](/badges/phpsoftbox-application/health.svg)

```
[![Health](https://phpackages.com/badges/phpsoftbox-application/health.svg)](https://phpackages.com/packages/phpsoftbox-application)
```

###  Alternatives

[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k39.6M299](/packages/laravel-dusk)[nineinchnick/edatatables

Grid widget for the Yii Framework, wrapper for the DataTables jQuery plugin

173.2k](/packages/nineinchnick-edatatables)[link-cloud/fast-hyperf

LinkCloud Fast Hyperf

241.2k1](/packages/link-cloud-fast-hyperf)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
