honeystone/context

Laravel的应用上下文管理器。

1.0.0 2024-07-20 21:25 UTC

This package is auto-updated.

Last update: 2024-09-26 22:14:42 UTC


README

Static Badge GitHub License Latest Version on Packagist Packagist Dependency Version Packagist Dependency Version Static Badge

我们开发了honeystone/context,用于管理多租户应用中的应用上下文。它提供了一个简单、流畅的API,用于通过'上下文解析器'初始化、扩展和切换上下文。此外,上下文在队列作业中自动可用,并且可以用于限定Eloquent模型。

这个包几年前是为我们自己的多租户应用开发的。我们最近决定将其发布,希望它对更广泛的Laravel社区有用。我们欢迎贡献、反馈和建设性的批评。

入门

首先阅读简要博客文章,该文章演示了如何在多租户应用中使用此包。

支持我们

Support Us

我们致力于提供由Honeystone团队维护的高质量开源包。如果您想支持我们的努力,只需使用我们的包、推荐它们并做出贡献。

如果您在项目中需要任何帮助,或需要任何定制开发,请联系我们

安装

composer require honeystone/context

使用

一个典型的用例是在您的中间件中声明和初始化上下文。然后您可以像这样访问上下文数据

$team = context('team');
$project = context('project');

定义上下文

在解析之前需要定义上下文

context()->define()
    ->require('team', Team::class)
    ->require('project', Project::class);

这些上下文定义是'必需的',因此如果它们无法解析,将会抛出CouldNotResolveRequiredContextException异常。对于未定义的上下文,将抛出UndefinedContextException异常。

您还可以定义'接受的',但不是'必需的'上下文

context()->define()
    ->accept('team', Team::class)
    ->accept('project', Project::class);

或者根据其他上下文的存在来接受/要求

context()->define()
    ->require('team', Team::class)
    ->requireWhenProvided('team', 'project', Project::class); //Or acceptWhenProvided

初始化上下文

要初始化上下文,您需要提供一个解析器

context()->initialize(new MyResolver());

以下是一个示例解析器类

<?php

declare(strict_types=1);

namespace App\Context\Resolvers;

use Honeystone\Context\ContextResolver;

class MyResolver extends ContextResolver
{
    public function __construct(
        private ?Team = null,
        private ?Project = null,
    ) {}

    public function resolveTeam(): Team
    {
        //your resolution logic

        return $this->team;
    }

    public function resolveProject(): Project
    {
        //your resolution logic

        return $this->project;
    }

    public static function deserialize(array $data): static
    {
        //you must also declare a deserialization method,
        //to reinstate the serialised data

        return new static($team, $project);
    }
}

您可以根据这种方式自定义序列化逻辑

class MyResolver extends ContextResolver
{
    //...

    public function serializeTeam(Team $team): int
    {
        return $team->id;
    }
}

您可以根据这种方式验证解析上下文的完整性

class MyResolver extends ContextResolver
{
    //...

    public function checkProject(
        DefinesContext $definition,
        Project $project,
        array $resolved,
    ): bool {
        return $project->id === $resolved['team']->project_id;
    }
}

您还可以重新初始化或注销当前上下文

context()->reinitialize(new AnotherResolver());

context()->deinitialize();

扩展上下文

可以使用另一个解析器扩展当前上下文

context()->define()->accept('site', Site::class);

context()->extend(new AnotherResolver());

临时切换上下文

使用闭包

context()->initialize(new MyResolver());

context()->temporarilyInitialize(new AnotherResolver())
    ->run(function () {
        //do something
    });

使用start和end方法

context()->initialize(new MyResolver());

$tmpContext = context()->temporarilyInitialize(new AnotherResolver());

$tmpContext->start();

//do something

$tmpContext->end();

事件和接收器

Honeystone\Context\Events\ContextChanged事件在上下文更改时发出。

您还可以指定当设置单个上下文值时通知的接收器

context()->receive('team', new MyReceiver());

以下是一个示例接收器

<?php

declare(strict_types=1);

namespace App\Context\Receivers;

use Honeystone\Context\Contracts\ReceivesContext;

class TeamReceiver implements ReceivesContext
{
    public function receiveContext(string $name, ?object $context): void
    {
        //process received context
    }
}

使用上下文限定模型

您可以使用当前上下文来限定您的Eloquent模型。

以下是一个示例

<?php

declare(strict_types=1);

namespace App\Models;

use Honeystone\Context\Models\Concerns\BelongsToContext;
use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    use BelongsToContext;

    protected static array $context = ['team'];

    //optionally specify context aliases
    protected static array $context = ['team' => 'my_team'];

    //optionally configure a context foreign key
    protected function getTeamContextForeignKey(Team $team): string
    {
        return 'my_team_id'; //the default is generated like this
    }

    //optionally configure a context owner id
    protected function getTeamContextOwnerId(Team $team): int
    {
        return $context->id; //defaults to the id prop
    }

    //optionally configure the relationship name
    protected function getTeamContextRelationName(Team $team): string
    {
        return 'my_team'; //the default is generated like this
    }
}

已知问题

  • 测试需要改进

Laravel的"上下文"

当创建此解决方案时,Laravel上下文不存在。函数名冲突是不幸的,但并不是真正的问题。您只需确保导入该函数。

use function Honeystone\Context\context;

尽管名称会邀请比较,但这些包解决的是不同的问题。Laravel上下文是一个通用的全局数据存储。这个包专门用于解决具有更复杂逻辑的上下文对象,并使用它们来限定应用,例如在多租户应用中。

变更日志

更改列表可以在CHANGELOG.md文件中找到。

许可证

MIT © Honeystone Consulting Ltd