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

api-platform / core / 15255731762

26 May 2025 01:55PM UTC coverage: 0.0% (-26.5%) from 26.526%
15255731762

Pull #7176

github

web-flow
Merge 66f6cf4d2 into 79edced67
Pull Request #7176: Merge 4.1

0 of 387 new or added lines in 28 files covered. (0.0%)

11394 existing lines in 372 files now uncovered.

0 of 51334 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/src/Symfony/Tests/Doctrine/EventListener/PurgeHttpCacheListenerTest.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\Symfony\Tests\Doctrine\EventListener;
15

16
use ApiPlatform\HttpCache\PurgerInterface;
17
use ApiPlatform\Metadata\Exception\InvalidArgumentException;
18
use ApiPlatform\Metadata\Exception\ItemNotFoundException;
19
use ApiPlatform\Metadata\GetCollection;
20
use ApiPlatform\Metadata\IriConverterInterface;
21
use ApiPlatform\Metadata\ResourceClassResolverInterface;
22
use ApiPlatform\Metadata\UrlGeneratorInterface;
23
use ApiPlatform\Symfony\Doctrine\EventListener\PurgeHttpCacheListener;
24
use ApiPlatform\Symfony\Tests\Fixtures\NotAResource;
25
use ApiPlatform\Symfony\Tests\Fixtures\TestBundle\Entity\ContainNonResource;
26
use ApiPlatform\Symfony\Tests\Fixtures\TestBundle\Entity\Dummy;
27
use ApiPlatform\Symfony\Tests\Fixtures\TestBundle\Entity\DummyNoGetOperation;
28
use ApiPlatform\Symfony\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
29
use Doctrine\ORM\EntityManagerInterface;
30
use Doctrine\ORM\Event\OnFlushEventArgs;
31
use Doctrine\ORM\Event\PreUpdateEventArgs;
32
use Doctrine\ORM\Mapping\ClassMetadata;
33
use Doctrine\ORM\UnitOfWork;
34
use PHPUnit\Framework\TestCase;
35
use Prophecy\Argument;
36
use Prophecy\PhpUnit\ProphecyTrait;
37
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
38

39
/**
40
 * @author Kévin Dunglas <dunglas@gmail.com>
41
 */
42
class PurgeHttpCacheListenerTest extends TestCase
43
{
44
    use ProphecyTrait;
45

46
    public function testOnFlush(): void
47
    {
48
        $toInsert1 = new Dummy();
×
49
        $toInsert2 = new Dummy();
×
50

51
        $toUpdate1 = new Dummy();
×
52
        $toUpdate1->setId(1);
×
53
        $toUpdate2 = new Dummy();
×
54
        $toUpdate2->setId(2);
×
55

56
        $toDelete1 = new Dummy();
×
57
        $toDelete1->setId(3);
×
58
        $toDelete2 = new Dummy();
×
59
        $toDelete2->setId(4);
×
60

61
        $toDeleteNoPurge = new DummyNoGetOperation();
×
62
        $toDeleteNoPurge->setId(5);
×
63

64
        $purgerProphecy = $this->prophesize(PurgerInterface::class);
×
65
        $purgerProphecy->purge(['/dummies', '/dummies/1', '/dummies/2', '/dummies/3', '/dummies/4'])->shouldBeCalled();
×
66

67
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
NEW
68
        $iriConverterProphecy->getIriFromResource(Argument::type(Dummy::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willReturn('/dummies')->shouldBeCalled();
×
69
        $iriConverterProphecy->getIriFromResource($toUpdate1)->willReturn('/dummies/1')->shouldBeCalled();
×
70
        $iriConverterProphecy->getIriFromResource($toUpdate2)->willReturn('/dummies/2')->shouldBeCalled();
×
71
        $iriConverterProphecy->getIriFromResource($toDelete1)->willReturn('/dummies/3')->shouldBeCalled();
×
72
        $iriConverterProphecy->getIriFromResource($toDelete2)->willReturn('/dummies/4')->shouldBeCalled();
×
NEW
73
        $iriConverterProphecy->getIriFromResource(Argument::type(DummyNoGetOperation::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willThrow(new InvalidArgumentException())->shouldBeCalled();
×
74
        $iriConverterProphecy->getIriFromResource(Argument::any())->willThrow(new ItemNotFoundException());
×
75

76
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
77
        $resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true)->shouldBeCalled();
×
78

79
        $uowProphecy = $this->prophesize(UnitOfWork::class);
×
80
        $uowProphecy->getScheduledEntityInsertions()->willReturn([$toInsert1, $toInsert2])->shouldBeCalled();
×
81
        $uowProphecy->getScheduledEntityUpdates()->willReturn([$toUpdate1, $toUpdate2])->shouldBeCalled();
×
82
        $uowProphecy->getScheduledEntityDeletions()->willReturn([$toDelete1, $toDelete2, $toDeleteNoPurge])->shouldBeCalled();
×
83

84
        $emProphecy = $this->prophesize(EntityManagerInterface::class);
×
85
        $emProphecy->getUnitOfWork()->willReturn($uowProphecy->reveal())->shouldBeCalled();
×
86
        $dummyClassMetadata = new ClassMetadata(Dummy::class);
×
87
        // @phpstan-ignore-next-line
88
        $dummyClassMetadata->associationMappings = [
×
89
            'relatedDummy' => [],
×
90
            'relatedOwningDummy' => [],
×
91
        ];
×
92
        $emProphecy->getClassMetadata(Dummy::class)->willReturn($dummyClassMetadata)->shouldBeCalled();
×
93
        $emProphecy->getClassMetadata(DummyNoGetOperation::class)->willReturn(new ClassMetadata(DummyNoGetOperation::class))->shouldBeCalled();
×
94
        $eventArgs = new OnFlushEventArgs($emProphecy->reveal());
×
95

96
        $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
×
97
        $propertyAccessorProphecy->isReadable(Argument::type(Dummy::class), 'relatedDummy')->willReturn(true);
×
98
        $propertyAccessorProphecy->isReadable(Argument::type(Dummy::class), 'relatedOwningDummy')->willReturn(false);
×
99
        $propertyAccessorProphecy->getValue(Argument::type(Dummy::class), 'relatedDummy')->willReturn(null)->shouldBeCalled();
×
100
        $propertyAccessorProphecy->getValue(Argument::type(Dummy::class), 'relatedOwningDummy')->willReturn(null)->shouldNotBeCalled();
×
101

102
        $listener = new PurgeHttpCacheListener($purgerProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal());
×
103
        $listener->onFlush($eventArgs);
×
104
        $listener->postFlush();
×
105

NEW
106
        $iriConverterProphecy->getIriFromResource(Argument::type(Dummy::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->shouldHaveBeenCalled();
×
NEW
107
        $iriConverterProphecy->getIriFromResource(Argument::type(DummyNoGetOperation::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->shouldHaveBeenCalled();
×
108
    }
109

110
    public function testPreUpdate(): void
111
    {
112
        $oldRelatedDummy = new RelatedDummy();
×
113
        $oldRelatedDummy->setId(1);
×
114

115
        $newRelatedDummy = new RelatedDummy();
×
116
        $newRelatedDummy->setId(2);
×
117

118
        $dummy = new Dummy();
×
119
        $dummy->setId(1);
×
120

121
        $purgerProphecy = $this->prophesize(PurgerInterface::class);
×
122
        $purgerProphecy->purge(['/dummies', '/dummies/1', '/related_dummies/old', '/related_dummies/new'])->shouldBeCalled();
×
123

124
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
NEW
125
        $iriConverterProphecy->getIriFromResource(Argument::type(Dummy::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willReturn('/dummies')->shouldBeCalled();
×
126
        $iriConverterProphecy->getIriFromResource($dummy)->willReturn('/dummies/1')->shouldBeCalled();
×
127
        $iriConverterProphecy->getIriFromResource($oldRelatedDummy)->willReturn('/related_dummies/old')->shouldBeCalled();
×
128
        $iriConverterProphecy->getIriFromResource($newRelatedDummy)->willReturn('/related_dummies/new')->shouldBeCalled();
×
129

130
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
131
        $resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true)->shouldBeCalled();
×
132

UNCOV
133
        $emProphecy = $this->prophesize(EntityManagerInterface::class);
×
134

135
        $classMetadata = new ClassMetadata(Dummy::class);
×
136
        $classMetadata->mapManyToOne(['fieldName' => 'relatedDummy', 'targetEntity' => RelatedDummy::class]);
×
137
        $emProphecy->getClassMetadata(Dummy::class)->willReturn($classMetadata)->shouldBeCalled();
×
138

139
        $changeSet = ['relatedDummy' => [$oldRelatedDummy, $newRelatedDummy]];
×
140
        $eventArgs = new PreUpdateEventArgs($dummy, $emProphecy->reveal(), $changeSet);
×
141

142
        $listener = new PurgeHttpCacheListener($purgerProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal());
×
143
        $listener->preUpdate($eventArgs);
×
144
        $listener->postFlush();
×
145
    }
146

147
    public function testNothingToPurge(): void
148
    {
149
        $dummyNoGetOperation = new DummyNoGetOperation();
×
150
        $dummyNoGetOperation->setId(1);
×
151

152
        $purgerProphecy = $this->prophesize(PurgerInterface::class);
×
153
        $purgerProphecy->purge([])->shouldNotBeCalled();
×
154

155
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
NEW
156
        $iriConverterProphecy->getIriFromResource(Argument::type(DummyNoGetOperation::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willThrow(new InvalidArgumentException())->shouldBeCalled();
×
157
        $iriConverterProphecy->getIriFromResource($dummyNoGetOperation)->shouldNotBeCalled();
×
158

159
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
NEW
160
        $resourceClassResolverProphecy->getResourceClass(Argument::type(DummyNoGetOperation::class))->willReturn(DummyNoGetOperation::class)->shouldNotBeCalled();
×
161

162
        $emProphecy = $this->prophesize(EntityManagerInterface::class);
×
163

164
        $classMetadata = new ClassMetadata(DummyNoGetOperation::class);
×
165
        $emProphecy->getClassMetadata(DummyNoGetOperation::class)->willReturn($classMetadata)->shouldBeCalled();
×
166

167
        $changeSet = ['lorem' => 'ipsum'];
×
168
        $eventArgs = new PreUpdateEventArgs($dummyNoGetOperation, $emProphecy->reveal(), $changeSet);
×
169

170
        $listener = new PurgeHttpCacheListener($purgerProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal());
×
171
        $listener->preUpdate($eventArgs);
×
172
        $listener->postFlush();
×
173
    }
174

175
    public function testNotAResourceClass(): void
176
    {
177
        $containNonResource = new ContainNonResource();
×
NEW
178
        $nonResource1 = new NotAResource('foo', 'bar');
×
NEW
179
        $nonResource2 = new NotAResource('baz', 'qux');
×
NEW
180
        $collectionOfNotAResource = [$nonResource1, $nonResource2];
×
181

182
        $purgerProphecy = $this->prophesize(PurgerInterface::class);
×
NEW
183
        $purgerProphecy->purge(['/dummies'])->shouldBeCalled();
×
184

185
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
NEW
186
        $iriConverterProphecy->getIriFromResource(Argument::type(ContainNonResource::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willReturn('/dummies')->shouldBeCalled();
×
NEW
187
        $iriConverterProphecy->getIriFromResource($nonResource1)->willThrow(new InvalidArgumentException())->shouldBeCalled();
×
NEW
188
        $iriConverterProphecy->getIriFromResource($nonResource2)->willThrow(new InvalidArgumentException())->shouldBeCalled();
×
189

190
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
NEW
191
        $resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true)->shouldBeCalled();
×
192

193
        $uowProphecy = $this->prophesize(UnitOfWork::class);
×
194
        $uowProphecy->getScheduledEntityInsertions()->willReturn([$containNonResource])->shouldBeCalled();
×
195
        $uowProphecy->getScheduledEntityUpdates()->willReturn([])->shouldBeCalled();
×
196
        $uowProphecy->getScheduledEntityDeletions()->willReturn([])->shouldBeCalled();
×
197

198
        $emProphecy = $this->prophesize(EntityManagerInterface::class);
×
199
        $emProphecy->getUnitOfWork()->willReturn($uowProphecy->reveal())->shouldBeCalled();
×
200

201
        $dummyClassMetadata = new ClassMetadata(ContainNonResource::class);
×
202
        // @phpstan-ignore-next-line
203
        $dummyClassMetadata->associationMappings = [
×
204
            'notAResource' => [],
×
205
            'collectionOfNotAResource' => ['targetEntity' => NotAResource::class],
×
206
        ];
×
207
        $emProphecy->getClassMetadata(ContainNonResource::class)->willReturn($dummyClassMetadata);
×
208
        $eventArgs = new OnFlushEventArgs($emProphecy->reveal());
×
209

210
        $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
×
211
        $propertyAccessorProphecy->isReadable(Argument::type(ContainNonResource::class), 'notAResource')->willReturn(true);
×
NEW
212
        $propertyAccessorProphecy->isReadable(Argument::type(ContainNonResource::class), 'collectionOfNotAResource')->willReturn(true);
×
NEW
213
        $propertyAccessorProphecy->getValue(Argument::type(ContainNonResource::class), 'notAResource')->shouldBeCalled()->willReturn($nonResource1);
×
NEW
214
        $propertyAccessorProphecy->getValue(Argument::type(ContainNonResource::class), 'collectionOfNotAResource')->shouldBeCalled()->willReturn($collectionOfNotAResource);
×
215

216
        $listener = new PurgeHttpCacheListener($purgerProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal());
×
217
        $listener->onFlush($eventArgs);
×
NEW
218
        $listener->postFlush();
×
219
    }
220

221
    public function testAddTagsForCollection(): void
222
    {
NEW
223
        $dummy1 = new Dummy();
×
NEW
224
        $dummy1->setId(1);
×
NEW
225
        $dummy2 = new Dummy();
×
NEW
226
        $dummy2->setId(2);
×
NEW
227
        $collection = [$dummy1, $dummy2];
×
228

NEW
229
        $purgerProphecy = $this->prophesize(PurgerInterface::class);
×
NEW
230
        $purgerProphecy->purge(['/dummies', '/dummies/1', '/dummies/2'])->shouldBeCalled();
×
231

NEW
232
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
NEW
233
        $iriConverterProphecy->getIriFromResource(Argument::type(Dummy::class), UrlGeneratorInterface::ABS_PATH, new GetCollection())->willReturn('/dummies')->shouldBeCalled();
×
NEW
234
        $iriConverterProphecy->getIriFromResource($dummy1)->willReturn('/dummies/1')->shouldBeCalled();
×
NEW
235
        $iriConverterProphecy->getIriFromResource($dummy2)->willReturn('/dummies/2')->shouldBeCalled();
×
236

NEW
237
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
NEW
238
        $resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true)->shouldBeCalled();
×
239

NEW
240
        $dummyWithCollection = new Dummy();
×
NEW
241
        $dummyWithCollection->setId(3);
×
242

NEW
243
        $uowProphecy = $this->prophesize(UnitOfWork::class);
×
NEW
244
        $uowProphecy->getScheduledEntityInsertions()->willReturn([$dummyWithCollection])->shouldBeCalled();
×
NEW
245
        $uowProphecy->getScheduledEntityUpdates()->willReturn([])->shouldBeCalled();
×
NEW
246
        $uowProphecy->getScheduledEntityDeletions()->willReturn([])->shouldBeCalled();
×
247

NEW
248
        $emProphecy = $this->prophesize(EntityManagerInterface::class);
×
NEW
249
        $emProphecy->getUnitOfWork()->willReturn($uowProphecy->reveal())->shouldBeCalled();
×
250

NEW
251
        $dummyClassMetadata = new ClassMetadata(Dummy::class);
×
252
        // @phpstan-ignore-next-line
NEW
253
        $dummyClassMetadata->associationMappings = [
×
NEW
254
            'relatedDummies' => ['targetEntity' => Dummy::class],
×
NEW
255
        ];
×
NEW
256
        $emProphecy->getClassMetadata(Dummy::class)->willReturn($dummyClassMetadata)->shouldBeCalled();
×
NEW
257
        $eventArgs = new OnFlushEventArgs($emProphecy->reveal());
×
258

NEW
259
        $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
×
NEW
260
        $propertyAccessorProphecy->isReadable(Argument::type(Dummy::class), 'relatedDummies')->willReturn(true);
×
NEW
261
        $propertyAccessorProphecy->getValue(Argument::type(Dummy::class), 'relatedDummies')->willReturn($collection)->shouldBeCalled();
×
262

NEW
263
        $listener = new PurgeHttpCacheListener($purgerProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal());
×
NEW
264
        $listener->onFlush($eventArgs);
×
NEW
265
        $listener->postFlush();
×
266
    }
267
}
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