欧洲演示/edt-access-definitions

用于规范对实体及其属性的访问的工具。


README

允许在CRUD应用中精细定义实体及其属性被允许如何访问。

提供基于查询组件的PHP类,以提供实施访问限制和简单别名从包装模式到后端对象模式的手段。根据用例,可选地使用路径构建组件可以简化使用。

概述

此组件提供定义称为“类型”的途径,以便对应于您的应用程序中的对象。您的“类型”将根据访问用户的授权或您的应用程序中的其他状态限制对对象模式和实例的访问。它在CRUD应用中显示出其主要优势,但也适用于其他类型的应用程序。

例如,假设一个非常简单的CMS软件。它有一个与作者双向多对一关系相连的Article类。

查询

假设对于您的业务层,您需要区分处于草稿状态的文档,因此只能由其作者可见,以及所有人可见的完成文档。您可以通过集中授权在ArticleType类中来集中处理允许用户访问哪些文档,而不是在业务层中分散这些潜在的重复检查。

在初始设置之后,您可以使用它与条件一起查询数据源中的实例,类似于查询组件

use EDT\Wrapping\Contracts\Types\TransferableTypeInterface;
use EDT\ConditionFactory\ConditionFactoryInterface;

function getArticleType(): ArticleType {
    // returns the Type defining access limitations to your Article objects
}
function getEntityProvider(): EntityProviderInterface {
    // returns the instance to access your data source
}
function getConditionFactory(): ConditionFactoryInterface {
    // returns a factory for conditions adjusted to your data source
}

// initializations
$articleType = getArticleType();
$conditionFactory = getConditionFactory();
$typeProvider = new PrefilledTypeProvider([$articleType]);
$pathProcessor = new SchemaPathProcessor(new PropertyPathProcessorFactory(), $typeProvider);

// create a condition for your business logic
$nameCondition = $conditionFactory->propertyHasValue('jacob', 'author', 'accountName');

// check if the path used in the condition is allowed to be accessed
// and resolve aliases if used in the path
$pathProcessor->mapFilterConditions($articleType, [$nameCondition]);
// add the access condition defined by the type itself
$conditions[] = $pathProcessor->processAccessCondition($articleType);

// get the entities matching not only the name condition
// but also all conditions defined by the article type itself
$filteredEntities = $entityFetcher->getEntities($conditions);

这三个辅助函数留空,因为它们的实现取决于您的实际用例

  1. getArticleType返回您的ArticleType,您可以通过扩展TransferableTypeInterface并使用您喜欢的样式(手动、作为Symfony服务、通过配置加载等)来实现。不同接口的概述及其实现方式请参阅如何实现类型

  2. getEntityProvidergetConditionFactory返回的实例取决于您的数据源。有关可能的类,请参阅提供者和工厂设置

如本例所示,我们明确指定了一个条件,只获取由jacob撰写的文档。然而,如果配置了正确的ArticleType,我们将实际上得到一个子集的结果,其中只包含当前用户允许访问的文档。例如,如果当前登录的用户不是jacob,她或他只会收到不再处于草稿状态的文档。另一方面,jacob将得到他所有的文档。此隐式条件将自动执行,只需在ArticleType中设置一次,每次使用ArticleType访问Article对象时都会应用。

包装

如果您为对象类编写的Type不包含任何关系,仅包含原始类型,那么访问实际的实例可能没问题。然而,在Article对象的情况下,我们需要阻止用户通过ArticleType获取任意文章,然后访问其实际的作者实例。这将允许无限制地访问该作者的任何Article实例,无论ArticleType中的任何设置。

因此,您可以使用相应的类型包装您的实体实例。包装器提供的属性访问权限取决于ArticleType及其与其他Types的关系。例如,我们可能不想完全禁止在ArticleType中访问作者,而是配置一个UserType。与ArticleType一样,UserType可以限制对数据和模式的访问。这样,我们可以允许访问作者以获取他们的公开姓名,但可以防止访问他们的草稿。

function getWrapperFactory(): WrapperObjectFactory {
    // the wrapper factory initialized with the necessary parameters
}

$wrapperFactory = getWrapperFactory();
$wrappedEntities = array_map(function (Article $articleEntity) use ($articleType): WrapperObject {
    return $this->getWrapperFactory()->createWrapper($articleEntity, $articleType);
}, $articleEntities);

请注意,无论如何访问,Types的限制都是存在的。例如,当您使用UserType限制了用户内部电子邮件地址的访问权限时,无论User对象的包装器是通过包装的Article、包装的Comment还是手动包装获得的,限制总是会应用。

致谢

由Christian Dressler构思和实施,谨向eFrane致以深深的感谢。