demos-europe/edt-paths

创建实体和实体属性之间路径的工具。


README

创建实体和实体属性之间路径的工具。

提供PHP类,允许您使用phpdoc标签注释类作为路径段,并引用其他路径段来定义有向图,可用于构建具有IDE支持的属性路径。

概述

此组件允许您将类标记为路径段,并在其他类中将此类引用为关系。

例如,假设我们有一个名为 Comment 的类,它与 Article 类有关联,而 Article 类又与 Author 类有关联。如果我们想使用关系属性名称构建路径,可以手动定义如下数组:['article', 'author']。为此,您不仅需要在编写路径时知道属性名称,还需要在属性名称更改时调整所有路径。

另一种选择是在每个类中定义字符串常量,每个常量包含每个属性的名称。在这种情况下,您可以这样做:[Comment::ARTICLE, Article::AUTHOR]。这样,您可以更改常量的值而无需手动调整每个路径。此外,您的IDE可以帮助您找到应用程序中每个属性的每个使用情况。

此组件扩展了这些优势,并使用phpdoc @property-read标签而不是常量。因此,您可以定义如下表达式的路径:$comment→article→author→getAsNames()。结果将与上面的示例相同。这样,您的IDE在每个段提供可用关系的列表,并跟踪每个@property-read的使用情况,允许轻松重命名属性。

要使类作为路径段并添加有效的@property-read标签,您只需要在类中添加PropertyAutoPathTrait作为use。之后,您可以添加具有目标类类型的@property-read标签,如下所示,对于Article类。

/**
 * @property-read Author $author
 * @property-read Comment $comments
 */
class Article
{
    use \EDT\PathBuilding\PropertyAutoPathTrait;

    private $text;

    public function __construct(string $text)
    {
        $this->text = $text;
    }

    public function getText(): string
    {
        return $this->text;
    }
}

默认情况下,您的类的构造函数将被忽略,并返回一个未完全初始化的实例。这意味着您可能无法使用路径的结果实例进行任何其他操作,除了进一步构建路径。因此,上面的类将适用于 $comment→article→authors→getAsNames(),但将失败于 $comment→article→getText()

但是,如果您将工厂回调传递给特性,路径段将使用该回调创建,从而产生您类的完整可用的实例。这样的工厂将取决于您的系统架构。以下示例只能提供一个粗略的概念,您的解决方案可能不同。

/**
 * @property-read Author $author
 * @property-read Comment $comments
 */
class Article
{
    use \EDT\PathBuilding\PropertyAutoPathTrait;

    private $text;

    public function __construct(string $text, ArticleRepository $articleRepository)
    {
        $this->childCreateCallback =
        static function (string $class, $parent, string $parentPropertyName) use ($articleRepository) {
            if ($parent instanceof Comment) {
                $articleId = $parent->getArticleId();
                $article = $articleRepository->getArticle($articleId);
                $article->setParent($parent);
                $article->setParentPropertyName($parentPropertyName);
                return $article;
            }
            if ($parent instanceof Author) {
                return $this->createChild($class, $parent, $parentPropertyName);
            }
            // ... more class checks
        };
        $this->text = $text;
    }

    public function getText(): string
    {
        return $this->text;
    }
}

请注意,此示例在多对多关系的情况下将回退到未完全初始化的实例。这是因为在路径如 $author→articles 的情况下,否则需要选择一个 Article 实例。这样的路径仍然可以用于进一步构建路径,如 $author→articles→comments→getAsNames()。但如前所述,如果使用实际类的实际方法,则可能会失败,例如在以下访问中:$author→articles→getText()。这是一个已知的限制,被认为是可接受的,因为主要用途是构建路径,而不是替换获取实际实例的获取器。

支持的标签

上面的例子使用了 property-read 标签来向您的路径类添加属性。这是默认设置,因为它似乎在路径构建用例中最为合理。然而,如果您愿意,也可以将其更改为其他标签,如下所示。

/**
 * @property Author $author
 * @property Comment $comments
 */
class Article
{
    use \EDT\PathBuilding\PropertyAutoPathTrait;

    protected function getDocblockTraitEvaluator(): DocblockPropertyByTraitEvaluator
    {
        if (null === $this->docblockTraitEvaluator) {
            $this->docblockTraitEvaluator = PropertyEvaluatorPool::getInstance()->getEvaluator(PropertyAutoPathTrait::class, ['property']); // replaces the default 'property-read'
        }

        return $this->docblockTraitEvaluator;
    }
}

您还可以设置多个标签,例如下面的 property-readproperty 标签。

/**
 * @property Author $author
 * @property Comment $comments
 */
class Article
{
    use \EDT\PathBuilding\PropertyAutoPathTrait;

    protected function getDocblockTraitEvaluator(): DocblockPropertyByTraitEvaluator
    {
        if (null === $this->docblockTraitEvaluator) {
            $this->docblockTraitEvaluator = PropertyEvaluatorPool::getInstance()->getEvaluator(PropertyAutoPathTrait::class, ['property-read', 'property']);
        }

        return $this->docblockTraitEvaluator;
    }
}

支持的标签有

  • property

  • property-read

  • property-write

  • param

  • var

致谢和感谢

构思和实现由 Christian Dressler 完成,特此感谢 eFrane