• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 18343625207

08 Oct 2025 11:48AM UTC coverage: 24.542% (-0.02%) from 24.561%
18343625207

push

github

web-flow
fix(state): object mapper on delete operation (#7447)

fixes #7434

1 of 49 new or added lines in 2 files covered. (2.04%)

7084 existing lines in 207 files now uncovered.

14004 of 57061 relevant lines covered (24.54%)

26.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.79
/src/Metadata/Resource/Factory/PhpDocResourceMetadataCollectionFactory.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Metadata\Resource\Factory;
15

16
use ApiPlatform\Metadata\Operations;
17
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
18
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
19
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
20
use PHPStan\PhpDocParser\Lexer\Lexer;
21
use PHPStan\PhpDocParser\Parser\ConstExprParser;
22
use PHPStan\PhpDocParser\Parser\PhpDocParser;
23
use PHPStan\PhpDocParser\Parser\TokenIterator;
24
use PHPStan\PhpDocParser\Parser\TypeParser;
25
use PHPStan\PhpDocParser\ParserConfig;
26

27
/**
28
 * Extracts descriptions from PHPDoc.
29
 *
30
 * @author Kévin Dunglas <dunglas@gmail.com>
31
 */
32
final class PhpDocResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
33
{
34
    private readonly ?PhpDocParser $phpDocParser;
35
    private readonly ?Lexer $lexer;
36

37
    /** @var array<string, PhpDocNode> */
38
    private array $docBlocks = [];
39

40
    public function __construct(private readonly ResourceMetadataCollectionFactoryInterface $decorated)
41
    {
UNCOV
42
        $phpDocParser = null;
768✔
UNCOV
43
        $lexer = null;
768✔
UNCOV
44
        if (class_exists(PhpDocParser::class) && class_exists(ParserConfig::class)) {
768✔
UNCOV
45
            $config = new ParserConfig([]);
768✔
UNCOV
46
            $phpDocParser = new PhpDocParser($config, new TypeParser($config, new ConstExprParser($config)), new ConstExprParser($config));
768✔
UNCOV
47
            $lexer = new Lexer($config);
768✔
48
        } elseif (class_exists(PhpDocParser::class)) {
×
49
            $phpDocParser = new PhpDocParser(new TypeParser(new ConstExprParser()), new ConstExprParser()); // @phpstan-ignore-line
×
50
            $lexer = new Lexer(); // @phpstan-ignore-line
×
51
        }
UNCOV
52
        $this->phpDocParser = $phpDocParser;
768✔
UNCOV
53
        $this->lexer = $lexer;
768✔
54
    }
55

56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function create(string $resourceClass): ResourceMetadataCollection
60
    {
UNCOV
61
        $resourceMetadataCollection = $this->decorated->create($resourceClass);
112✔
62

UNCOV
63
        foreach ($resourceMetadataCollection as $key => $resourceMetadata) {
112✔
UNCOV
64
            if (null !== $resourceMetadata->getDescription()) {
110✔
UNCOV
65
                continue;
6✔
66
            }
67

UNCOV
68
            $description = $this->getShortDescription($resourceClass);
110✔
69

UNCOV
70
            if (!$description) {
110✔
UNCOV
71
                return $resourceMetadataCollection;
106✔
72
            }
73

UNCOV
74
            $resourceMetadataCollection[$key] = $resourceMetadata->withDescription($description);
16✔
75

UNCOV
76
            $operations = $resourceMetadata->getOperations() ?? new Operations();
16✔
UNCOV
77
            foreach ($operations as $operationName => $operation) {
16✔
UNCOV
78
                if (null !== $operation->getDescription()) {
16✔
79
                    continue;
×
80
                }
81

UNCOV
82
                $operations->add($operationName, $operation->withDescription($description));
16✔
83
            }
84

UNCOV
85
            $resourceMetadataCollection[$key] = $resourceMetadataCollection[$key]->withOperations($operations);
16✔
86

UNCOV
87
            if (!$resourceMetadata->getGraphQlOperations()) {
16✔
UNCOV
88
                continue;
8✔
89
            }
90

UNCOV
91
            foreach ($graphQlOperations = $resourceMetadata->getGraphQlOperations() as $operationName => $operation) {
16✔
UNCOV
92
                if (null !== $operation->getDescription()) {
16✔
UNCOV
93
                    continue;
16✔
94
                }
95

UNCOV
96
                $graphQlOperations[$operationName] = $operation->withDescription($description);
16✔
97
            }
98

UNCOV
99
            $resourceMetadataCollection[$key] = $resourceMetadataCollection[$key]->withGraphQlOperations($graphQlOperations);
16✔
100
        }
101

UNCOV
102
        return $resourceMetadataCollection;
30✔
103
    }
104

105
    /**
106
     * Gets the short description of the class.
107
     */
108
    private function getShortDescription(string $class): ?string
109
    {
UNCOV
110
        if (!$docBlock = $this->getDocBlock($class)) {
110✔
UNCOV
111
            return null;
106✔
112
        }
113

UNCOV
114
        foreach ($docBlock->children as $docChild) {
16✔
UNCOV
115
            if ($docChild instanceof PhpDocTextNode && !empty($docChild->text)) {
16✔
UNCOV
116
                return $docChild->text;
16✔
117
            }
118
        }
119

UNCOV
120
        return null;
2✔
121
    }
122

123
    private function getDocBlock(string $class): ?PhpDocNode
124
    {
UNCOV
125
        if (isset($this->docBlocks[$class])) {
110✔
UNCOV
126
            return $this->docBlocks[$class];
8✔
127
        }
128

UNCOV
129
        if (!$this->phpDocParser || !$this->lexer) {
110✔
130
            return null;
×
131
        }
132

133
        try {
UNCOV
134
            $reflectionClass = new \ReflectionClass($class);
110✔
135
        } catch (\ReflectionException) {
×
136
            return null;
×
137
        }
138

UNCOV
139
        $rawDocNode = $reflectionClass->getDocComment();
110✔
UNCOV
140
        if (!$rawDocNode) {
110✔
UNCOV
141
            return null;
106✔
142
        }
143

UNCOV
144
        $tokens = new TokenIterator($this->lexer->tokenize($rawDocNode));
16✔
UNCOV
145
        $phpDocNode = $this->phpDocParser->parse($tokens);
16✔
UNCOV
146
        $tokens->consumeTokenType(Lexer::TOKEN_END);
16✔
147

UNCOV
148
        return $this->docBlocks[$class] = $phpDocNode;
16✔
149
    }
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc