icanhazstring/symfony-time-machine

Symfony扩展包,用于更改应用程序的日期和时间功能

支持包维护!
其他
icanhazstring

安装次数: 1,361

依赖者: 0

建议者: 0

安全: 0

星标: 7

关注者: 2

分支: 0

公开问题: 9

类型:symfony-bundle


README

Symfony扩展包,用于更改应用程序的日期和时间功能

动机

编写应用程序的测试相对简单且容易。但针对基于大量DateTime对象的测试怎么办呢?

已经有symfony/clock提供了ClockInterface接口,你可以用它注入NativeClockMockClock到你的服务中。

但这只适用于测试。如果你想要进行端到端的测试呢?你可以更改服务器的系统时间,是的,但这有一个更简单的方法,就是使用这个symfony-time-machine

安装

composer require icanhazstring/symfony-time-machine

如果自动注册不起作用,将包添加到你的config/bundles.php

<?php

return [
    Icanhazstring\SymfonyTimeMachine\TimeMachineBundle => ['all' => true],
];

工作原理

此包依赖于你的应用程序中存在作为服务的ClockInterface。因此,你需要在你的services.yaml中添加类似以下内容

services:
  Symfony\Component\Clock\ClockInterface:
    class: Symfony\Component\Clock\NativeClock

此包将此服务设置为public: true,因为这是在请求时更改服务所必需的。

现在每次启动TimeKernel时,它将使用从请求查询/cookie中的time-machine或环境变量TIME_MACHINE中解析的日期时间字符串替换ClockInterface

使用方法

Web使用

对于Web使用,你需要稍微修改一下你的public/index.php

<?php

use App\Kernel;
use Icanhazstring\SymfonyTimeMachine\TimeKernel;

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
    (new TimeKernel($kernel))->fromContext($context)->boot();

    return $kerneL;
};

控制台使用

对于控制台使用,修改bin/console

return function (array $context) {
    $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
    (new TimeKernel($kernel))->fromContext($context)->boot();

    return new Application($kernel);
};

注册额外的TimeMachineHandler

有时你需要修改应用程序中的其他服务,与time-machine一起。为此,你可以实现实现TimeMachineHandler接口的服务。

这些服务将在容器中更改ClockInterface之后被调用。`TimeKernel`将使用`HandlerRegistry`调用所有可用服务的`TimeMachineHandler::handle()`。

例如,你可以在你的应用程序中为所有openapi路径添加time-machine查询参数,如这里使用api-platform所示。

final class PathModifier implements OpenApiPathModifier, TimeMachineHandler
{
    public function __construct(private readonly OpenApiFactory $openApiFactory)
    {
    }

    public function handles(string $path, PathItem $pathItem): bool
    {
        return true;
    }

    public function modify(PathItem $pathItem): PathItem
    {
        /** @var array<string, null|Operation> $operations */
        $operations = [
            'get' => $pathItem->getGet(),
            'post' => $pathItem->getPost(),
        ];

        foreach ($operations as $method => $operation) {
            if ($operation === null) {
                continue;
            }

            $queryParameters = $operation->getParameters();
            $queryParameters[] = new Parameter(
                name: 'time-machine',
                in: 'query',
                description: 'Sets the applications datetime to a specific value.',
                required: false,
                schema: ['type' => 'string', 'default' => 'now']
            );

            $wither = 'with'.ucfirst($method);
            /** @var PathItem $pathItem */
            $pathItem = $pathItem->{$wither}($operation->withParameters($queryParameters));
        }

        return $pathItem;
    }

    public function handle(): void
    {
        $this->openApiFactory->addModifier($this);
    }
}