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\Action; |
||
15 | |||
16 | use Sonata\AdminBundle\Admin\AdminInterface; |
||
17 | use Sonata\AdminBundle\Admin\FieldDescriptionInterface; |
||
18 | use Sonata\AdminBundle\Admin\Pool; |
||
19 | use Sonata\AdminBundle\Filter\FilterInterface; |
||
20 | use Symfony\Component\Form\Form; |
||
21 | use Symfony\Component\HttpFoundation\JsonResponse; |
||
22 | use Symfony\Component\HttpFoundation\Request; |
||
23 | use Symfony\Component\HttpFoundation\Response; |
||
24 | use Symfony\Component\Security\Core\Exception\AccessDeniedException; |
||
25 | |||
26 | final class RetrieveAutocompleteItemsAction |
||
27 | { |
||
28 | /** |
||
29 | * @var Pool |
||
30 | */ |
||
31 | private $pool; |
||
32 | |||
33 | public function __construct(Pool $pool) |
||
34 | { |
||
35 | $this->pool = $pool; |
||
36 | } |
||
37 | |||
38 | /** |
||
39 | * Retrieve list of items for autocomplete form field. |
||
40 | * |
||
41 | * @throws \RuntimeException |
||
42 | * @throws AccessDeniedException |
||
43 | */ |
||
44 | public function __invoke(Request $request): JsonResponse |
||
45 | { |
||
46 | $admin = $this->pool->getInstance($request->get('admin_code')); |
||
47 | $admin->setRequest($request); |
||
48 | $context = $request->get('_context', ''); |
||
49 | |||
50 | if ('filter' === $context) { |
||
51 | $admin->checkAccess('list'); |
||
52 | } elseif (!$admin->hasAccess('create') && !$admin->hasAccess('edit')) { |
||
53 | throw new AccessDeniedException(); |
||
54 | } |
||
55 | |||
56 | // subject will be empty to avoid unnecessary database requests and keep autocomplete function fast |
||
57 | $admin->setSubject($admin->getNewInstance()); |
||
58 | |||
59 | if ('filter' === $context) { |
||
60 | // filter |
||
61 | $fieldDescription = $this->retrieveFilterFieldDescription($admin, $request->get('field')); |
||
62 | $filterAutocomplete = $admin->getDatagrid()->getFilter($fieldDescription->getName()); |
||
63 | |||
64 | $property = $filterAutocomplete->getFieldOption('property'); |
||
65 | $callback = $filterAutocomplete->getFieldOption('callback'); |
||
66 | $minimumInputLength = $filterAutocomplete->getFieldOption('minimum_input_length', 3); |
||
67 | $itemsPerPage = $filterAutocomplete->getFieldOption('items_per_page', 10); |
||
68 | $reqParamPageNumber = $filterAutocomplete->getFieldOption('req_param_name_page_number', '_page'); |
||
69 | $toStringCallback = $filterAutocomplete->getFieldOption('to_string_callback'); |
||
70 | $targetAdminAccessAction = $filterAutocomplete->getFieldOption('target_admin_access_action', 'list'); |
||
71 | } else { |
||
72 | // create/edit form |
||
73 | $fieldDescription = $this->retrieveFormFieldDescription($admin, $request->get('field')); |
||
74 | $formAutocomplete = $admin->getForm()->get($fieldDescription->getName()); |
||
75 | |||
76 | $formAutocompleteConfig = $formAutocomplete->getConfig(); |
||
77 | if ($formAutocompleteConfig->getAttribute('disabled')) { |
||
78 | throw new AccessDeniedException( |
||
79 | 'Autocomplete list can`t be retrieved because the form element is disabled or read_only.' |
||
80 | ); |
||
81 | } |
||
82 | |||
83 | $property = $formAutocompleteConfig->getAttribute('property'); |
||
84 | $callback = $formAutocompleteConfig->getAttribute('callback'); |
||
85 | $minimumInputLength = $formAutocompleteConfig->getAttribute('minimum_input_length'); |
||
86 | $itemsPerPage = $formAutocompleteConfig->getAttribute('items_per_page'); |
||
87 | $reqParamPageNumber = $formAutocompleteConfig->getAttribute('req_param_name_page_number'); |
||
88 | $toStringCallback = $formAutocompleteConfig->getAttribute('to_string_callback'); |
||
89 | $targetAdminAccessAction = $formAutocompleteConfig->getAttribute('target_admin_access_action'); |
||
90 | } |
||
91 | |||
92 | $searchText = $request->get('q'); |
||
93 | |||
94 | $targetAdmin = $fieldDescription->getAssociationAdmin(); |
||
95 | |||
96 | // check user permission |
||
97 | $targetAdmin->checkAccess($targetAdminAccessAction); |
||
98 | |||
99 | if (mb_strlen($searchText, 'UTF-8') < $minimumInputLength) { |
||
100 | return new JsonResponse(['status' => 'KO', 'message' => 'Too short search string.'], Response::HTTP_FORBIDDEN); |
||
101 | } |
||
102 | |||
103 | $targetAdmin->setFilterPersister(null); |
||
104 | $datagrid = $targetAdmin->getDatagrid(); |
||
105 | |||
106 | if (null !== $callback) { |
||
107 | if (!\is_callable($callback)) { |
||
108 | throw new \RuntimeException('Callback does not contain callable function.'); |
||
109 | } |
||
110 | |||
111 | $callback($targetAdmin, $property, $searchText); |
||
112 | } else { |
||
113 | if (\is_array($property)) { |
||
114 | // multiple properties |
||
115 | foreach ($property as $prop) { |
||
116 | if (!$datagrid->hasFilter($prop)) { |
||
117 | throw new \RuntimeException(sprintf( |
||
118 | 'To retrieve autocomplete items,' |
||
119 | .' you should add filter "%s" to "%s" in configureDatagridFilters() method.', |
||
120 | $prop, |
||
121 | \get_class($targetAdmin) |
||
122 | )); |
||
123 | } |
||
124 | |||
125 | $filter = $datagrid->getFilter($prop); |
||
126 | $filter->setCondition(FilterInterface::CONDITION_OR); |
||
127 | |||
128 | $datagrid->setValue($filter->getFormName(), null, $searchText); |
||
129 | } |
||
130 | } else { |
||
131 | if (!$datagrid->hasFilter($property)) { |
||
132 | throw new \RuntimeException(sprintf( |
||
133 | 'To retrieve autocomplete items,' |
||
134 | .' you should add filter "%s" to "%s" in configureDatagridFilters() method.', |
||
135 | $property, |
||
136 | \get_class($targetAdmin) |
||
137 | )); |
||
138 | } |
||
139 | |||
140 | $datagrid->setValue($datagrid->getFilter($property)->getFormName(), null, $searchText); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | $datagrid->setValue('_per_page', null, $itemsPerPage); |
||
145 | $datagrid->setValue('_page', null, $request->query->get($reqParamPageNumber, 1)); |
||
146 | $datagrid->buildPager(); |
||
147 | |||
148 | $pager = $datagrid->getPager(); |
||
149 | |||
150 | $items = []; |
||
151 | $results = $pager->getResults(); |
||
152 | |||
153 | foreach ($results as $model) { |
||
154 | if (null !== $toStringCallback) { |
||
155 | if (!\is_callable($toStringCallback)) { |
||
156 | throw new \RuntimeException('Option "to_string_callback" does not contain callable function.'); |
||
157 | } |
||
158 | |||
159 | $label = $toStringCallback($model, $property); |
||
160 | } else { |
||
161 | $resultMetadata = $targetAdmin->getObjectMetadata($model); |
||
162 | $label = $resultMetadata->getTitle(); |
||
163 | } |
||
164 | |||
165 | $items[] = [ |
||
166 | 'id' => $admin->id($model), |
||
167 | 'label' => $label, |
||
168 | ]; |
||
169 | } |
||
170 | |||
171 | return new JsonResponse([ |
||
172 | 'status' => 'OK', |
||
173 | 'more' => !$pager->isLastPage(), |
||
174 | 'items' => $items, |
||
175 | ]); |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Retrieve the filter field description given by field name. |
||
180 | * |
||
181 | * @throws \RuntimeException |
||
182 | */ |
||
183 | private function retrieveFilterFieldDescription( |
||
184 | AdminInterface $admin, |
||
185 | string $field |
||
186 | ): FieldDescriptionInterface { |
||
187 | $fieldDescription = $admin->getFilterFieldDescription($field); |
||
188 | |||
189 | if (!$fieldDescription) { |
||
190 | throw new \RuntimeException(sprintf('The field "%s" does not exist.', $field)); |
||
191 | } |
||
192 | |||
193 | if (null === $fieldDescription->getTargetEntity()) { |
||
0 ignored issues
–
show
|
|||
194 | throw new \RuntimeException(sprintf('No associated entity with field "%s".', $field)); |
||
195 | } |
||
196 | |||
197 | return $fieldDescription; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Retrieve the form field description given by field name. |
||
202 | * |
||
203 | * @throws \RuntimeException |
||
204 | */ |
||
205 | private function retrieveFormFieldDescription( |
||
206 | AdminInterface $admin, |
||
207 | string $field |
||
208 | ): FieldDescriptionInterface { |
||
209 | $fieldDescription = $admin->getFormFieldDescription($field); |
||
210 | |||
211 | if (!$fieldDescription) { |
||
212 | throw new \RuntimeException(sprintf('The field "%s" does not exist.', $field)); |
||
213 | } |
||
214 | |||
215 | if (null === $fieldDescription->getTargetEntity()) { |
||
0 ignored issues
–
show
The method
Sonata\AdminBundle\Admin...face::getTargetEntity() has been deprecated with message: since sonata-project/admin-bundle 3.69. Use `getTargetModel()` instead.
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.
Loading history...
|
|||
216 | throw new \RuntimeException(sprintf('No associated entity with field "%s".', $field)); |
||
217 | } |
||
218 | |||
219 | return $fieldDescription; |
||
220 | } |
||
221 | } |
||
222 |
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.