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

api-platform / core / 14854964964

06 May 2025 08:21AM UTC coverage: 6.873% (-1.6%) from 8.459%
14854964964

Pull #7122

github

web-flow
Merge c6177db2c into f55606b01
Pull Request #7122: Cherry picks from main (deprecations)

0 of 35 new or added lines in 9 files covered. (0.0%)

2031 existing lines in 148 files now uncovered.

10887 of 158407 relevant lines covered (6.87%)

6.19 hits per line

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

0.0
/src/Doctrine/Odm/State/LinksHandlerTrait.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\Doctrine\Odm\State;
15

16
use ApiPlatform\Doctrine\Common\State\LinksHandlerTrait as CommonLinksHandlerTrait;
17
use ApiPlatform\Metadata\Exception\RuntimeException;
18
use ApiPlatform\Metadata\Link;
19
use ApiPlatform\Metadata\Operation;
20
use ApiPlatform\State\Util\StateOptionsTrait;
21
use Doctrine\ODM\MongoDB\Aggregation\Builder;
22
use Doctrine\ODM\MongoDB\DocumentManager;
23
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
24
use Doctrine\Persistence\ManagerRegistry;
25

26
/**
27
 * @internal
28
 */
29
trait LinksHandlerTrait
30
{
31
    use CommonLinksHandlerTrait;
32
    use StateOptionsTrait;
33

34
    private ManagerRegistry $managerRegistry;
35

36
    private function handleLinks(Builder $aggregationBuilder, array $identifiers, array $context, string $resourceClass, ?Operation $operation = null): void
37
    {
UNCOV
38
        if (!$identifiers) {
×
UNCOV
39
            return;
×
40
        }
41

UNCOV
42
        $links = $this->getLinks($resourceClass, $operation, $context);
×
43

UNCOV
44
        if (!$links) {
×
45
            return;
×
46
        }
47

UNCOV
48
        foreach ($links as $i => $link) {
×
UNCOV
49
            if (null !== $link->getExpandedValue()) {
×
UNCOV
50
                unset($links[$i]);
×
51
            }
52
        }
53

UNCOV
54
        $executeOptions = $operation->getExtraProperties()['doctrine_mongodb']['execute_options'] ?? [];
×
55

UNCOV
56
        $this->buildAggregation($resourceClass, array_reverse($links), array_reverse($identifiers), $context, $executeOptions, $resourceClass, $aggregationBuilder, $operation);
×
57
    }
58

59
    /**
60
     * @throws RuntimeException
61
     */
62
    private function buildAggregation(string $toClass, array $links, array $identifiers, array $context, array $executeOptions, string $previousAggregationClass, Builder $previousAggregationBuilder, ?Operation $operation = null): Builder
63
    {
UNCOV
64
        if (!$operation) {
×
65
            trigger_deprecation('api-platform/core', '3.2', 'In API Platform 4 the last argument "operation" will be required and this trait will be internal. Use the "handleLinks" feature instead.');
×
66
        }
67

UNCOV
68
        if (\count($links) <= 0) {
×
UNCOV
69
            return $previousAggregationBuilder;
×
70
        }
71

72
        /** @var Link $link */
UNCOV
73
        $link = array_shift($links);
×
74

UNCOV
75
        $fromClass = $link->getFromClass();
×
UNCOV
76
        $fromProperty = $link->getFromProperty();
×
UNCOV
77
        $toProperty = $link->getToProperty();
×
UNCOV
78
        $identifierProperties = $link->getIdentifiers();
×
UNCOV
79
        $hasCompositeIdentifiers = 1 < \count($identifierProperties);
×
80

UNCOV
81
        $aggregationClass = $fromClass;
×
UNCOV
82
        if ($toProperty) {
×
UNCOV
83
            $aggregationClass = $toClass;
×
84
        }
85

UNCOV
86
        $lookupProperty = $toProperty ?? $fromProperty;
×
UNCOV
87
        $lookupPropertyAlias = $lookupProperty ? "{$lookupProperty}_lkup" : null;
×
88

UNCOV
89
        $manager = $this->managerRegistry->getManagerForClass($aggregationClass);
×
UNCOV
90
        if (!$manager instanceof DocumentManager) {
×
UNCOV
91
            if ($operation) {
×
UNCOV
92
                $aggregationClass = $this->getLinkFromClass($link, $operation);
×
UNCOV
93
                $manager = $this->managerRegistry->getManagerForClass($aggregationClass);
×
94
            }
95

UNCOV
96
            if (!$manager instanceof DocumentManager) {
×
97
                throw new RuntimeException(\sprintf('The manager for "%s" must be an instance of "%s".', $aggregationClass, DocumentManager::class));
×
98
            }
99
        }
100

UNCOV
101
        $classMetadata = $manager->getClassMetadata($aggregationClass);
×
102

UNCOV
103
        if (!$classMetadata instanceof ClassMetadata) {
×
104
            throw new RuntimeException(\sprintf('The class metadata for "%s" must be an instance of "%s".', $aggregationClass, ClassMetadata::class));
×
105
        }
106

UNCOV
107
        $aggregation = $previousAggregationBuilder;
×
UNCOV
108
        if ($aggregationClass !== $previousAggregationClass) {
×
UNCOV
109
            $aggregation = $manager->createAggregationBuilder($aggregationClass);
×
110
        }
111

UNCOV
112
        if ($lookupProperty && $classMetadata->hasAssociation($lookupProperty)) {
×
UNCOV
113
            $aggregation->lookup($lookupProperty)->alias($lookupPropertyAlias);
×
114
        }
115

UNCOV
116
        if ($toProperty) {
×
UNCOV
117
            foreach ($identifierProperties as $identifierProperty) {
×
UNCOV
118
                $aggregation->match()->field(\sprintf('%s.%s', $lookupPropertyAlias, 'id' === $identifierProperty ? '_id' : $identifierProperty))->equals($this->getIdentifierValue($identifiers, $hasCompositeIdentifiers ? $identifierProperty : null));
×
119
            }
120
        } else {
UNCOV
121
            foreach ($identifierProperties as $identifierProperty) {
×
UNCOV
122
                $aggregation->match()->field($identifierProperty)->equals($this->getIdentifierValue($identifiers, $hasCompositeIdentifiers ? $identifierProperty : null));
×
123
            }
124
        }
125

126
        // Recurse aggregations
UNCOV
127
        $aggregation = $this->buildAggregation($fromClass, $links, $identifiers, $context, $executeOptions, $aggregationClass, $aggregation, $operation);
×
128

UNCOV
129
        if (null === $fromProperty || null !== $toProperty) {
×
UNCOV
130
            return $aggregation;
×
131
        }
132

UNCOV
133
        $results = $aggregation->getAggregation($executeOptions)->getIterator()->toArray();
×
UNCOV
134
        $in = [];
×
UNCOV
135
        foreach ($results as $result) {
×
UNCOV
136
            foreach ($result[$lookupPropertyAlias] ?? [] as $lookupResult) {
×
UNCOV
137
                $in[] = $lookupResult['_id'];
×
138
            }
139
        }
UNCOV
140
        $previousAggregationBuilder->match()->field('_id')->in($in);
×
141

UNCOV
142
        return $previousAggregationBuilder;
×
143
    }
144

145
    private function getLinkFromClass(Link $link, Operation $operation): string
146
    {
UNCOV
147
        $documentClass = $this->getStateOptionsClass($operation, $operation->getClass(), Options::class);
×
UNCOV
148
        $fromClass = $link->getFromClass();
×
UNCOV
149
        if ($fromClass === $operation->getClass() && $documentClass) {
×
UNCOV
150
            return $documentClass;
×
151
        }
152

153
        $operation = $this->resourceMetadataCollectionFactory->create($fromClass)->getOperation();
×
154

155
        if ($documentClass = $this->getStateOptionsClass($operation, null, Options::class)) {
×
156
            return $documentClass;
×
157
        }
158

159
        throw new \Exception('Can not found a doctrine class for this link.');
×
160
    }
161
}
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

© 2026 Coveralls, Inc