1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of the Sonata Project package. |
7
|
|
|
* |
8
|
|
|
* (c) Thomas Rabaix <[email protected]> |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, please view the LICENSE |
11
|
|
|
* file that was distributed with this source code. |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace Sonata\AdminBundle\Tests\Admin; |
15
|
|
|
|
16
|
|
|
use PHPUnit\Framework\TestCase; |
17
|
|
|
use Sonata\AdminBundle\Admin\AdminInterface; |
18
|
|
|
use Sonata\AdminBundle\Admin\Pool; |
19
|
|
|
use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface; |
20
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
21
|
|
|
|
22
|
|
|
class PoolTest extends TestCase |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* @var Pool |
26
|
|
|
*/ |
27
|
|
|
private $pool = null; |
28
|
|
|
|
29
|
|
|
public function setUp(): void |
30
|
|
|
{ |
31
|
|
|
$this->pool = new Pool($this->getContainer(), 'Sonata Admin', '/path/to/pic.png', ['foo' => 'bar']); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
public function testGetGroups(): void |
35
|
|
|
{ |
36
|
|
|
$this->pool->setAdminServiceIds(['sonata.user.admin.group1']); |
37
|
|
|
|
38
|
|
|
$this->pool->setAdminGroups([ |
39
|
|
|
'adminGroup1' => ['sonata.user.admin.group1' => []], |
40
|
|
|
]); |
41
|
|
|
|
42
|
|
|
$result = $this->pool->getGroups(); |
43
|
|
|
$this->assertArrayHasKey('adminGroup1', $result); |
44
|
|
|
$this->assertArrayHasKey('sonata.user.admin.group1', $result['adminGroup1']); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
public function testHasGroup(): void |
48
|
|
|
{ |
49
|
|
|
$this->pool->setAdminGroups([ |
50
|
|
|
'adminGroup1' => [], |
51
|
|
|
]); |
52
|
|
|
|
53
|
|
|
$this->assertTrue($this->pool->hasGroup('adminGroup1')); |
54
|
|
|
$this->assertFalse($this->pool->hasGroup('adminGroup2')); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function testGetDashboardGroups(): void |
58
|
|
|
{ |
59
|
|
|
$admin_group1 = $this->createMock(AdminInterface::class); |
60
|
|
|
$admin_group1->expects($this->once())->method('showIn')->willReturn(true); |
61
|
|
|
|
62
|
|
|
$admin_group2 = $this->createMock(AdminInterface::class); |
63
|
|
|
$admin_group2->expects($this->once())->method('showIn')->willReturn(false); |
64
|
|
|
|
65
|
|
|
$admin_group3 = $this->createMock(AdminInterface::class); |
66
|
|
|
$admin_group3->expects($this->once())->method('showIn')->willReturn(false); |
67
|
|
|
|
68
|
|
|
$container = $this->createMock(ContainerInterface::class); |
69
|
|
|
|
70
|
|
|
$container->expects($this->any())->method('get')->will($this->onConsecutiveCalls( |
71
|
|
|
$admin_group1, $admin_group2, $admin_group3 |
72
|
|
|
)); |
73
|
|
|
|
74
|
|
|
$pool = new Pool($container, 'Sonata Admin', '/path/to/pic.png'); |
75
|
|
|
$pool->setAdminServiceIds(['sonata.user.admin.group1', 'sonata.user.admin.group2', 'sonata.user.admin.group3']); |
76
|
|
|
|
77
|
|
|
$pool->setAdminGroups([ |
78
|
|
|
'adminGroup1' => [ |
79
|
|
|
'items' => ['itemKey' => $this->getItemArray('sonata.user.admin.group1')], |
80
|
|
|
], |
81
|
|
|
'adminGroup2' => [ |
82
|
|
|
'items' => ['itemKey' => $this->getItemArray('sonata.user.admin.group2')], |
83
|
|
|
], |
84
|
|
|
'adminGroup3' => [ |
85
|
|
|
'items' => ['itemKey' => $this->getItemArray('sonata.user.admin.group3')], |
86
|
|
|
], |
87
|
|
|
]); |
88
|
|
|
|
89
|
|
|
$groups = $pool->getDashboardGroups(); |
90
|
|
|
|
91
|
|
|
$this->assertCount(1, $groups); |
92
|
|
|
$this->assertSame($admin_group1, $groups['adminGroup1']['items']['itemKey']); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
public function testGetAdminsByGroupWhenGroupNotSet(): void |
96
|
|
|
{ |
97
|
|
|
$this->expectException(\InvalidArgumentException::class); |
98
|
|
|
|
99
|
|
|
$this->pool->setAdminGroups([ |
100
|
|
|
'adminGroup1' => [], |
101
|
|
|
]); |
102
|
|
|
|
103
|
|
|
$this->pool->getAdminsByGroup('adminGroup2'); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public function testGetAdminsByGroupWhenGroupIsEmpty(): void |
107
|
|
|
{ |
108
|
|
|
$this->pool->setAdminGroups([ |
109
|
|
|
'adminGroup1' => [], |
110
|
|
|
]); |
111
|
|
|
|
112
|
|
|
$this->assertSame([], $this->pool->getAdminsByGroup('adminGroup1')); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
public function testGetAdminsByGroup(): void |
116
|
|
|
{ |
117
|
|
|
$this->pool->setAdminServiceIds(['sonata.admin1', 'sonata.admin2', 'sonata.admin3']); |
118
|
|
|
$this->pool->setAdminGroups([ |
119
|
|
|
'adminGroup1' => [ |
120
|
|
|
'items' => [ |
121
|
|
|
$this->getItemArray('sonata.admin1'), |
122
|
|
|
$this->getItemArray('sonata.admin2'), |
123
|
|
|
], |
124
|
|
|
], |
125
|
|
|
'adminGroup2' => [ |
126
|
|
|
'items' => [$this->getItemArray('sonata.admin3')], |
127
|
|
|
], |
128
|
|
|
]); |
129
|
|
|
|
130
|
|
|
$this->assertCount(2, $this->pool->getAdminsByGroup('adminGroup1')); |
131
|
|
|
$this->assertCount(1, $this->pool->getAdminsByGroup('adminGroup2')); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
public function testGetAdminForClassWhenAdminClassIsNotSet(): void |
135
|
|
|
{ |
136
|
|
|
$this->pool->setAdminClasses(['someclass' => 'sonata.user.admin.group1']); |
137
|
|
|
$this->assertFalse($this->pool->hasAdminByClass('notexists')); |
138
|
|
|
$this->assertNull($this->pool->getAdminByClass('notexists')); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
public function testGetAdminForClassWithInvalidFormat(): void |
142
|
|
|
{ |
143
|
|
|
$this->expectException(\RuntimeException::class); |
144
|
|
|
|
145
|
|
|
$this->pool->setAdminClasses(['someclass' => 'sonata.user.admin.group1']); |
146
|
|
|
$this->assertTrue($this->pool->hasAdminByClass('someclass')); |
147
|
|
|
|
148
|
|
|
$this->pool->getAdminByClass('someclass'); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
public function testGetAdminForClassWithTooManyRegisteredAdmin(): void |
152
|
|
|
{ |
153
|
|
|
$this->expectException(\RuntimeException::class); |
154
|
|
|
|
155
|
|
|
$this->pool->setAdminClasses([ |
156
|
|
|
'someclass' => ['sonata.user.admin.group1', 'sonata.user.admin.group2'], |
157
|
|
|
]); |
158
|
|
|
|
159
|
|
|
$this->assertTrue($this->pool->hasAdminByClass('someclass')); |
160
|
|
|
$this->pool->getAdminByClass('someclass'); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function testGetAdminForClassWhenAdminClassIsSet(): void |
164
|
|
|
{ |
165
|
|
|
$this->pool->setAdminServiceIds(['sonata.user.admin.group1']); |
166
|
|
|
$this->pool->setAdminClasses([ |
167
|
|
|
'someclass' => ['sonata.user.admin.group1'], |
168
|
|
|
]); |
169
|
|
|
|
170
|
|
|
$this->assertTrue($this->pool->hasAdminByClass('someclass')); |
171
|
|
|
$this->assertInstanceOf(AdminInterface::class, $this->pool->getAdminByClass('someclass')); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
public function testGetInstanceWithUndefinedServiceId(): void |
175
|
|
|
{ |
176
|
|
|
$this->expectException(\InvalidArgumentException::class); |
177
|
|
|
$this->expectExceptionMessage('Admin service "sonata.news.admin.post" not found in admin pool.'); |
178
|
|
|
|
179
|
|
|
$this->pool->getInstance('sonata.news.admin.post'); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
public function testGetInstanceWithUndefinedServiceIdAndExistsOther(): void |
183
|
|
|
{ |
184
|
|
|
$this->pool->setAdminServiceIds([ |
185
|
|
|
'sonata.news.admin.post', |
186
|
|
|
'sonata.news.admin.category', |
187
|
|
|
]); |
188
|
|
|
|
189
|
|
|
$this->expectException(\InvalidArgumentException::class); |
190
|
|
|
$this->expectExceptionMessage('Admin service "sonata.news.admin.pos" not found in admin pool. ' |
191
|
|
|
.'Did you mean "sonata.news.admin.post" ' |
192
|
|
|
.'or one of those: [sonata.news.admin.category]?'); |
193
|
|
|
|
194
|
|
|
$this->pool->getInstance('sonata.news.admin.pos'); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
public function testGetAdminByAdminCode(): void |
198
|
|
|
{ |
199
|
|
|
$this->pool->setAdminServiceIds(['sonata.news.admin.post']); |
200
|
|
|
|
201
|
|
|
$this->assertInstanceOf(AdminInterface::class, $this->pool->getAdminByAdminCode('sonata.news.admin.post')); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
public function testGetAdminByAdminCodeForChildClass(): void |
205
|
|
|
{ |
206
|
|
|
$adminMock = $this->getMockBuilder(AdminInterface::class) |
207
|
|
|
->disableOriginalConstructor() |
208
|
|
|
->getMock(); |
209
|
|
|
$adminMock->expects($this->any()) |
210
|
|
|
->method('hasChild') |
211
|
|
|
->willReturn(true); |
212
|
|
|
$adminMock->expects($this->once()) |
213
|
|
|
->method('getChild') |
214
|
|
|
->with($this->equalTo('sonata.news.admin.comment')) |
215
|
|
|
->willReturn('commentAdminClass'); |
216
|
|
|
|
217
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
218
|
|
|
$containerMock->expects($this->any()) |
219
|
|
|
->method('get') |
220
|
|
|
->willReturn($adminMock); |
221
|
|
|
|
222
|
|
|
$this->pool = new Pool($containerMock, 'Sonata', '/path/to/logo.png'); |
223
|
|
|
$this->pool->setAdminServiceIds(['sonata.news.admin.post', 'sonata.news.admin.comment']); |
224
|
|
|
|
225
|
|
|
$this->assertSame('commentAdminClass', $this->pool->getAdminByAdminCode('sonata.news.admin.post|sonata.news.admin.comment')); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
public function testGetAdminByAdminCodeWithInvalidCode(): void |
229
|
|
|
{ |
230
|
|
|
$adminMock = $this->getMockBuilder(AdminInterface::class) |
231
|
|
|
->disableOriginalConstructor() |
232
|
|
|
->getMock(); |
233
|
|
|
$adminMock->expects($this->any()) |
234
|
|
|
->method('hasChild') |
235
|
|
|
->willReturn(false); |
236
|
|
|
|
237
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
238
|
|
|
$containerMock->expects($this->any()) |
239
|
|
|
->method('get') |
240
|
|
|
->willReturn($adminMock); |
241
|
|
|
|
242
|
|
|
$this->pool = new Pool($containerMock, 'Sonata', '/path/to/logo.png'); |
243
|
|
|
$this->pool->setAdminServiceIds(['sonata.news.admin.post']); |
244
|
|
|
|
245
|
|
|
$this->expectException(\InvalidArgumentException::class); |
246
|
|
|
$this->expectExceptionMessage('Argument 1 passed to Sonata\AdminBundle\Admin\Pool::getAdminByAdminCode() must contain a valid admin reference, "sonata.news.admin.valid" found at "sonata.news.admin.post|sonata.news.admin.valid".'); |
247
|
|
|
|
248
|
|
|
$this->pool->getAdminByAdminCode('sonata.news.admin.post|sonata.news.admin.valid'); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
public function testGetAdminByAdminCodeWithCodeNotChild(): void |
252
|
|
|
{ |
253
|
|
|
$adminMock = $this->getMockBuilder(AdminInterface::class) |
254
|
|
|
->disableOriginalConstructor() |
255
|
|
|
->getMock(); |
256
|
|
|
$adminMock->expects($this->any()) |
257
|
|
|
->method('hasChild') |
258
|
|
|
->willReturn(false); |
259
|
|
|
|
260
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
261
|
|
|
$containerMock->expects($this->any()) |
262
|
|
|
->method('get') |
263
|
|
|
->willReturn($adminMock); |
264
|
|
|
|
265
|
|
|
$this->pool = new Pool($containerMock, 'Sonata', '/path/to/logo.png'); |
266
|
|
|
$this->pool->setAdminServiceIds(['sonata.news.admin.post', 'sonata.news.admin.valid']); |
267
|
|
|
|
268
|
|
|
$this->assertFalse($this->pool->getAdminByAdminCode('sonata.news.admin.post|sonata.news.admin.valid')); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* @dataProvider getEmptyRootAdminServiceNames |
273
|
|
|
*/ |
274
|
|
|
public function testGetAdminByAdminCodeWithInvalidRootCode(string $adminId): void |
275
|
|
|
{ |
276
|
|
|
$adminMock = $this->createMock(AdminInterface::class); |
277
|
|
|
$adminMock->expects($this->never()) |
278
|
|
|
->method('hasChild'); |
279
|
|
|
|
280
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
281
|
|
|
$containerMock->expects($this->never()) |
282
|
|
|
->method('get'); |
283
|
|
|
|
284
|
|
|
$poolMock = $this->getMockBuilder(Pool::class) |
285
|
|
|
->setConstructorArgs([$containerMock, 'Sonata', '/path/to/logo.png']) |
286
|
|
|
->disableOriginalClone() |
287
|
|
|
->setMethodsExcept(['getAdminByAdminCode']) |
288
|
|
|
->getMock(); |
289
|
|
|
$poolMock->expects($this->never()) |
290
|
|
|
->method('getInstance'); |
291
|
|
|
|
292
|
|
|
$this->expectException(\InvalidArgumentException::class); |
293
|
|
|
$this->expectExceptionMessage('Root admin code must contain a valid admin reference, empty string given.'); |
294
|
|
|
$poolMock->getAdminByAdminCode($adminId); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
public function getEmptyRootAdminServiceNames() |
298
|
|
|
{ |
299
|
|
|
return [ |
300
|
|
|
[''], |
301
|
|
|
[' '], |
302
|
|
|
['|sonata.news.admin.child_of_empty_code'], |
303
|
|
|
]; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* @dataProvider getInvalidChildAdminServiceNames |
308
|
|
|
*/ |
309
|
|
|
public function testGetAdminByAdminCodeWithInvalidChildCode(string $adminId): void |
310
|
|
|
{ |
311
|
|
|
$adminMock = $this->createMock(AdminInterface::class); |
312
|
|
|
$adminMock->expects($this->any()) |
313
|
|
|
->method('hasChild') |
314
|
|
|
->willReturn(false); |
315
|
|
|
$adminMock->expects($this->never()) |
316
|
|
|
->method('getChild'); |
317
|
|
|
|
318
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
319
|
|
|
$containerMock->expects($this->never()) |
320
|
|
|
->method('get'); |
321
|
|
|
|
322
|
|
|
$poolMock = $this->getMockBuilder(Pool::class) |
323
|
|
|
->setConstructorArgs([$containerMock, 'Sonata', '/path/to/logo.png']) |
324
|
|
|
->disableOriginalClone() |
325
|
|
|
->setMethodsExcept(['getAdminByAdminCode']) |
326
|
|
|
->getMock(); |
327
|
|
|
$poolMock->expects($this->any()) |
328
|
|
|
->method('getInstance') |
329
|
|
|
->willReturn($adminMock); |
330
|
|
|
|
331
|
|
|
$this->expectExceptionMessageRegExp(sprintf( |
332
|
|
|
'{^Argument 1 passed to Sonata\\\AdminBundle\\\Admin\\\Pool::getAdminByAdminCode\(\) must contain a valid admin reference, "[^"]+" found at "%s"\.$}', |
333
|
|
|
$adminId |
334
|
|
|
)); |
335
|
|
|
|
336
|
|
|
$poolMock->getAdminByAdminCode($adminId); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
public function getInvalidChildAdminServiceNames() |
340
|
|
|
{ |
341
|
|
|
return [ |
342
|
|
|
['admin1|'], |
343
|
|
|
['admin1|nonexistent_code'], |
344
|
|
|
['admin1||admin3'], |
345
|
|
|
]; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
public function testGetAdminClasses(): void |
349
|
|
|
{ |
350
|
|
|
$this->pool->setAdminClasses(['someclass' => 'sonata.user.admin.group1']); |
351
|
|
|
$this->assertSame(['someclass' => 'sonata.user.admin.group1'], $this->pool->getAdminClasses()); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
public function testGetAdminGroups(): void |
355
|
|
|
{ |
356
|
|
|
$this->pool->setAdminGroups(['adminGroup1' => 'sonata.user.admin.group1']); |
357
|
|
|
$this->assertSame(['adminGroup1' => 'sonata.user.admin.group1'], $this->pool->getAdminGroups()); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
public function testGetAdminServiceIds(): void |
361
|
|
|
{ |
362
|
|
|
$this->pool->setAdminServiceIds(['sonata.user.admin.group1', 'sonata.user.admin.group2', 'sonata.user.admin.group3']); |
363
|
|
|
$this->assertSame(['sonata.user.admin.group1', 'sonata.user.admin.group2', 'sonata.user.admin.group3'], $this->pool->getAdminServiceIds()); |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
public function testGetContainer(): void |
367
|
|
|
{ |
368
|
|
|
$this->assertInstanceOf(ContainerInterface::class, $this->pool->getContainer()); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* @group legacy |
373
|
|
|
*/ |
374
|
|
|
public function testTemplate(): void |
375
|
|
|
{ |
376
|
|
|
$templateRegistry = $this->prophesize(MutableTemplateRegistryInterface::class); |
377
|
|
|
$templateRegistry->getTemplate('ajax') |
378
|
|
|
->shouldBeCalledTimes(1) |
379
|
|
|
->willReturn('Foo.html.twig'); |
380
|
|
|
|
381
|
|
|
$this->pool->setTemplateRegistry($templateRegistry->reveal()); |
382
|
|
|
|
383
|
|
|
$this->assertSame('Foo.html.twig', $this->pool->getTemplate('ajax')); |
|
|
|
|
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* @group legacy |
388
|
|
|
*/ |
389
|
|
|
public function testSetGetTemplates(): void |
390
|
|
|
{ |
391
|
|
|
$templates = [ |
392
|
|
|
'ajax' => 'Foo.html.twig', |
393
|
|
|
'layout' => 'Bar.html.twig', |
394
|
|
|
]; |
395
|
|
|
|
396
|
|
|
$templateRegistry = $this->prophesize(MutableTemplateRegistryInterface::class); |
397
|
|
|
$templateRegistry->setTemplates($templates) |
398
|
|
|
->shouldBeCalledTimes(1); |
399
|
|
|
$templateRegistry->getTemplates() |
400
|
|
|
->shouldBeCalledTimes(1) |
401
|
|
|
->willReturn($templates); |
402
|
|
|
|
403
|
|
|
$this->pool->setTemplateRegistry($templateRegistry->reveal()); |
404
|
|
|
|
405
|
|
|
$this->pool->setTemplates($templates); |
|
|
|
|
406
|
|
|
|
407
|
|
|
$this->assertSame($templates, $this->pool->getTemplates()); |
|
|
|
|
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
public function testGetTitleLogo(): void |
411
|
|
|
{ |
412
|
|
|
$this->assertSame('/path/to/pic.png', $this->pool->getTitleLogo()); |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
public function testGetTitle(): void |
416
|
|
|
{ |
417
|
|
|
$this->assertSame('Sonata Admin', $this->pool->getTitle()); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
public function testGetOption(): void |
421
|
|
|
{ |
422
|
|
|
$this->assertSame('bar', $this->pool->getOption('foo')); |
423
|
|
|
|
424
|
|
|
$this->assertNull($this->pool->getOption('non_existent_option')); |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
public function testOptionDefault(): void |
428
|
|
|
{ |
429
|
|
|
$this->assertSame([], $this->pool->getOption('nonexistantarray', [])); |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
private function getContainer(): ContainerInterface |
433
|
|
|
{ |
434
|
|
|
$containerMock = $this->createMock(ContainerInterface::class); |
435
|
|
|
$containerMock->expects($this->any()) |
436
|
|
|
->method('get') |
437
|
|
|
->willReturnCallback(function () { |
438
|
|
|
return $this->createMock(AdminInterface::class); |
439
|
|
|
}); |
440
|
|
|
|
441
|
|
|
return $containerMock; |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
private function getItemArray($serviceId): array |
445
|
|
|
{ |
446
|
|
|
return [ |
447
|
|
|
'admin' => $serviceId, |
448
|
|
|
'label' => '', |
449
|
|
|
'route' => '', |
450
|
|
|
'route_params' => [], |
451
|
|
|
]; |
452
|
|
|
} |
453
|
|
|
} |
454
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.