Completed
Push — 3.x ( e95e95...638cd1 )
by Oskar
05:54
created

Action/RetrieveAutocompleteItemsActionTest.php (16 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Action;
15
16
use PHPUnit\Framework\TestCase;
17
use Prophecy\Argument;
18
use Prophecy\Prophecy\ObjectProphecy;
19
use Sonata\AdminBundle\Action\GetShortObjectDescriptionAction;
20
use Sonata\AdminBundle\Action\RetrieveAutocompleteItemsAction;
21
use Sonata\AdminBundle\Admin\AbstractAdmin;
22
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
23
use Sonata\AdminBundle\Admin\Pool;
24
use Sonata\AdminBundle\Datagrid\Pager;
25
use Sonata\AdminBundle\Object\MetadataInterface;
26
use Sonata\AdminBundle\Tests\Fixtures\Filter\FooFilter;
27
use Sonata\DatagridBundle\Datagrid\DatagridInterface;
28
use Symfony\Component\Form\Form;
29
use Symfony\Component\Form\FormConfigInterface;
30
use Symfony\Component\HttpFoundation\Request;
31
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
32
33
final class RetrieveAutocompleteItemsActionTest extends TestCase
34
{
35
    /**
36
     * @var Pool
37
     */
38
    private $pool;
39
40
    /**
41
     * @var GetShortObjectDescriptionAction
42
     */
43
    private $action;
44
45
    /**
46
     * @var AbstractAdmin
47
     */
48
    private $admin;
49
50
    protected function setUp(): void
51
    {
52
        $this->admin = $this->prophesize(AbstractAdmin::class);
53
        $this->admin->setRequest(Argument::type(Request::class))->shouldBeCalled();
54
        $this->pool = $this->prophesize(Pool::class);
55
        $this->pool->getInstance(Argument::any())->willReturn($this->admin->reveal());
56
        $this->action = new RetrieveAutocompleteItemsAction(
57
            $this->pool->reveal()
58
        );
59
    }
60
61
    public function testRetrieveAutocompleteItemsActionNotGranted(): void
62
    {
63
        $this->expectException(AccessDeniedException::class);
64
65
        $request = new Request([
66
            'admin_code' => 'foo.admin',
67
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
68
69
        $this->admin->hasAccess('create')->willReturn(false);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->hasAccess('create') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
70
        $this->admin->hasAccess('edit')->willReturn(false);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->hasAccess('edit') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
71
72
        $action = $this->action;
73
        $action($request);
74
    }
75
76
    public function testRetrieveAutocompleteItemsActionDisabledFormelememt(): void
77
    {
78
        $this->expectException(AccessDeniedException::class);
79
        $this->expectExceptionMessage('Autocomplete list can`t be retrieved because the form element is disabled or read_only.');
80
81
        $object = new \stdClass();
82
        $request = new Request([
83
            'admin_code' => 'foo.admin',
84
            'field' => 'barField',
85
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
86
87
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
88
89
        $this->configureFormConfig('barField', true);
90
91
        $this->admin->getNewInstance()->willReturn($object);
92
        $this->admin->setSubject($object)->shouldBeCalled();
0 ignored issues
show
The method shouldBeCalled cannot be called on $this->admin->setSubject($object) (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
93
        $this->admin->hasAccess('create')->willReturn(true);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->hasAccess('create') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
94
        $this->admin->getFormFieldDescriptions()->willReturn(null);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->getFormFieldDescriptions() (of type array<integer,object<Son...dDescriptionInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
95
        $this->admin->getFormFieldDescription('barField')->willReturn($fieldDescription->reveal());
0 ignored issues
show
The method willReturn() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
96
97
        $fieldDescription->getTargetEntity()->willReturn(Foo::class);
98
        $fieldDescription->getName()->willReturn('barField');
99
100
        $action = $this->action;
101
        $action($request);
102
    }
103
104
    public function testRetrieveAutocompleteItemsTooShortSearchString(): void
105
    {
106
        $object = new \stdClass();
107
        $request = new Request([
108
            'admin_code' => 'foo.admin',
109
            'field' => 'barField',
110
            'q' => 'so',
111
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
112
113
        $targetAdmin = $this->prophesize(AbstractAdmin::class);
114
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
115
116
        $this->configureFormConfig('barField');
117
118
        $this->admin->getNewInstance()->willReturn($object);
119
        $this->admin->setSubject($object)->shouldBeCalled();
0 ignored issues
show
The method shouldBeCalled cannot be called on $this->admin->setSubject($object) (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
120
        $this->admin->hasAccess('create')->willReturn(true);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->hasAccess('create') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
121
        $this->admin->getFormFieldDescription('barField')->willReturn($fieldDescription->reveal());
0 ignored issues
show
The method willReturn() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
122
        $this->admin->getFormFieldDescriptions()->willReturn(null);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->getFormFieldDescriptions() (of type array<integer,object<Son...dDescriptionInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
123
        $targetAdmin->checkAccess('list')->willReturn(null);
124
        $fieldDescription->getTargetEntity()->willReturn(Foo::class);
125
        $fieldDescription->getName()->willReturn('barField');
126
        $fieldDescription->getAssociationAdmin()->willReturn($targetAdmin->reveal());
127
128
        $action = $this->action;
129
        $response = $action($request);
130
131
        $this->isInstanceOf(Response::class, $response);
132
        $this->assertSame('application/json', $response->headers->get('Content-Type'));
133
        $this->assertSame('{"status":"KO","message":"Too short search string."}', $response->getContent());
134
    }
135
136
    public function testRetrieveAutocompleteItems(): void
137
    {
138
        $entity = new \stdClass();
139
        $request = new Request([
140
            'admin_code' => 'foo.admin',
141
            'field' => 'barField',
142
            'q' => 'sonata',
143
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
144
145
        $targetAdmin = $this->prophesize(AbstractAdmin::class);
146
        $datagrid = $this->prophesize(DatagridInterface::class);
147
        $metadata = $this->prophesize(MetadataInterface::class);
148
        $pager = $this->prophesize(Pager::class);
149
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
150
151
        $this->configureFormConfig('barField');
152
153
        $datagrid = $this->configureAutocompleteItemsDatagrid();
154
        $filter = new FooFilter();
155
        $filter->initialize('foo');
156
157
        $datagrid->hasFilter('foo')->willReturn(true);
158
        $datagrid->getFilter('foo')->willReturn($filter);
159
        $datagrid->setValue('foo', null, 'sonata')->shouldBeCalled();
160
161
        $action = $this->action;
162
        $response = $action($request);
163
164
        $this->isInstanceOf(Response::class, $response);
165
        $this->assertSame('application/json', $response->headers->get('Content-Type'));
166
        $this->assertSame('{"status":"OK","more":false,"items":[{"id":123,"label":"FOO"}]}', $response->getContent());
167
    }
168
169
    public function testRetrieveAutocompleteItemsComplexPropertyArray(): void
170
    {
171
        $request = new Request([
172
            'admin_code' => 'foo.admin',
173
            'field' => 'barField',
174
            'q' => 'sonata',
175
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
176
177
        $this->configureFormConfigComplexPropertyArray('barField');
178
        $datagrid = $this->configureAutocompleteItemsDatagrid();
179
180
        $filter = new FooFilter();
181
        $filter->initialize('entity.property');
182
183
        $datagrid->hasFilter('entity.property')->willReturn(true);
184
        $datagrid->getFilter('entity.property')->willReturn($filter);
185
        $filter2 = new FooFilter();
186
        $filter2->initialize('entity2.property2');
187
188
        $datagrid->hasFilter('entity2.property2')->willReturn(true);
189
        $datagrid->getFilter('entity2.property2')->willReturn($filter2);
190
191
        $datagrid->setValue('entity__property', null, 'sonata')->shouldBeCalled();
192
        $datagrid->setValue('entity2__property2', null, 'sonata')->shouldBeCalled();
193
194
        $action = $this->action;
195
        $response = $action($request);
196
197
        $this->isInstanceOf(Response::class, $response);
198
        $this->assertSame('application/json', $response->headers->get('Content-Type'));
199
        $this->assertSame('{"status":"OK","more":false,"items":[{"id":123,"label":"FOO"}]}', $response->getContent());
200
    }
201
202
    public function testRetrieveAutocompleteItemsComplexProperty(): void
203
    {
204
        $request = new Request([
205
            'admin_code' => 'foo.admin',
206
            'field' => 'barField',
207
            'q' => 'sonata',
208
        ], [], [], [], [], ['REQUEST_METHOD' => 'GET', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
209
210
        $this->configureFormConfigComplexProperty('barField');
211
        $datagrid = $this->configureAutocompleteItemsDatagrid();
212
213
        $filter = new FooFilter();
214
        $filter->initialize('entity.property');
215
216
        $datagrid->hasFilter('entity.property')->willReturn(true);
217
        $datagrid->getFilter('entity.property')->willReturn($filter);
218
        $datagrid->setValue('entity__property', null, 'sonata')->shouldBeCalled();
219
220
        $action = $this->action;
221
        $response = $action($request);
222
223
        $this->isInstanceOf(Response::class, $response);
224
        $this->assertSame('application/json', $response->headers->get('Content-Type'));
225
        $this->assertSame('{"status":"OK","more":false,"items":[{"id":123,"label":"FOO"}]}', $response->getContent());
226
    }
227
228
    private function configureAutocompleteItemsDatagrid(): ObjectProphecy
229
    {
230
        $entity = new \stdClass();
231
232
        $targetAdmin = $this->prophesize(AbstractAdmin::class);
233
        $datagrid = $this->prophesize(DatagridInterface::class);
234
        $metadata = $this->prophesize(MetadataInterface::class);
235
        $pager = $this->prophesize(Pager::class);
236
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
237
238
        $this->admin->getNewInstance()->willReturn($entity);
239
        $this->admin->setSubject($entity)->shouldBeCalled();
0 ignored issues
show
The method shouldBeCalled cannot be called on $this->admin->setSubject($entity) (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
240
        $this->admin->hasAccess('create')->willReturn(true);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->hasAccess('create') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
241
        $this->admin->getFormFieldDescription('barField')->willReturn($fieldDescription->reveal());
0 ignored issues
show
The method willReturn() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
242
        $this->admin->getFormFieldDescriptions()->willReturn(null);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->getFormFieldDescriptions() (of type array<integer,object<Son...dDescriptionInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
243
        $this->admin->id($entity)->willReturn(123);
0 ignored issues
show
The method willReturn cannot be called on $this->admin->id($entity) (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
244
        $targetAdmin->checkAccess('list')->shouldBeCalled();
245
        $targetAdmin->setFilterPersister(null)->shouldBeCalled();
246
        $targetAdmin->getDatagrid()->willReturn($datagrid->reveal());
247
        $targetAdmin->getObjectMetadata($entity)->willReturn($metadata->reveal());
248
        $metadata->getTitle()->willReturn('FOO');
249
250
        $datagrid->setValue('_per_page', null, 10)->shouldBeCalled();
251
        $datagrid->setValue('_page', null, 1)->shouldBeCalled();
252
        $datagrid->buildPager()->willReturn(null);
253
        $datagrid->getPager()->willReturn($pager->reveal());
254
        $pager->getResults()->willReturn([$entity]);
255
        $pager->isLastPage()->willReturn(true);
256
        $fieldDescription->getTargetEntity()->willReturn(Foo::class);
257
        $fieldDescription->getName()->willReturn('barField');
258
        $fieldDescription->getAssociationAdmin()->willReturn($targetAdmin->reveal());
259
260
        return $datagrid;
261
    }
262
263
    private function configureFormConfig(string $field, bool $disabled = false): void
264
    {
265
        $form = $this->prophesize(Form::class);
266
        $formType = $this->prophesize(Form::class);
267
        $formConfig = $this->prophesize(FormConfigInterface::class);
268
269
        $this->admin->getForm()->willReturn($form->reveal());
0 ignored issues
show
The method willReturn() does not seem to exist on object<Symfony\Component\Form\Form>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
270
        $form->get($field)->willReturn($formType->reveal());
271
        $formType->getConfig()->willReturn($formConfig->reveal());
272
        $formConfig->getAttribute('disabled')->willReturn($disabled);
273
        $formConfig->getAttribute('property')->willReturn('foo');
274
        $formConfig->getAttribute('callback')->willReturn(null);
275
        $formConfig->getAttribute('minimum_input_length')->willReturn(3);
276
        $formConfig->getAttribute('items_per_page')->willReturn(10);
277
        $formConfig->getAttribute('req_param_name_page_number')->willReturn('_page');
278
        $formConfig->getAttribute('to_string_callback')->willReturn(null);
279
        $formConfig->getAttribute('target_admin_access_action')->willReturn('list');
280
    }
281
282
    private function configureFormConfigComplexProperty(string $field): void
283
    {
284
        $form = $this->prophesize(Form::class);
285
        $formType = $this->prophesize(Form::class);
286
        $formConfig = $this->prophesize(FormConfigInterface::class);
287
288
        $this->admin->getForm()->willReturn($form->reveal());
289
        $form->get($field)->willReturn($formType->reveal());
290
        $formType->getConfig()->willReturn($formConfig->reveal());
291
        $formConfig->getAttribute('disabled')->willReturn(false);
292
        $formConfig->getAttribute('property')->willReturn('entity.property');
293
        $formConfig->getAttribute('callback')->willReturn(null);
294
        $formConfig->getAttribute('minimum_input_length')->willReturn(3);
295
        $formConfig->getAttribute('items_per_page')->willReturn(10);
296
        $formConfig->getAttribute('req_param_name_page_number')->willReturn('_page');
297
        $formConfig->getAttribute('to_string_callback')->willReturn(null);
298
        $formConfig->getAttribute('target_admin_access_action')->willReturn('list');
299
    }
300
301
    private function configureFormConfigComplexPropertyArray($field): void
302
    {
303
        $form = $this->prophesize(Form::class);
304
        $formType = $this->prophesize(Form::class);
305
        $formConfig = $this->prophesize(FormConfigInterface::class);
306
307
        $this->admin->getForm()->willReturn($form->reveal());
308
        $form->get($field)->willReturn($formType->reveal());
309
        $formType->getConfig()->willReturn($formConfig->reveal());
310
        $formConfig->getAttribute('disabled')->willReturn(false);
311
        $formConfig->getAttribute('property')->willReturn(['entity.property', 'entity2.property2']);
312
        $formConfig->getAttribute('callback')->willReturn(null);
313
        $formConfig->getAttribute('minimum_input_length')->willReturn(3);
314
        $formConfig->getAttribute('items_per_page')->willReturn(10);
315
        $formConfig->getAttribute('req_param_name_page_number')->willReturn('_page');
316
        $formConfig->getAttribute('to_string_callback')->willReturn(null);
317
        $formConfig->getAttribute('target_admin_access_action')->willReturn('list');
318
    }
319
}
320