1 | <?php |
||
2 | |||
3 | /* |
||
4 | * @copyright 2014 Mautic Contributors. All rights reserved |
||
5 | * @author Mautic |
||
6 | * |
||
7 | * @link http://mautic.org |
||
8 | * |
||
9 | * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html |
||
10 | */ |
||
11 | |||
12 | namespace Mautic\ApiBundle\Controller; |
||
13 | |||
14 | use Doctrine\ORM\Mapping\ClassMetadata; |
||
15 | use Doctrine\ORM\Tools\Pagination\Paginator; |
||
16 | use FOS\RestBundle\Controller\FOSRestController; |
||
17 | use FOS\RestBundle\View\View; |
||
18 | use JMS\Serializer\Exclusion\ExclusionStrategyInterface; |
||
19 | use Mautic\ApiBundle\ApiEvents; |
||
20 | use Mautic\ApiBundle\Event\ApiEntityEvent; |
||
21 | use Mautic\ApiBundle\Serializer\Exclusion\ParentChildrenExclusionStrategy; |
||
22 | use Mautic\ApiBundle\Serializer\Exclusion\PublishDetailsExclusionStrategy; |
||
23 | use Mautic\CategoryBundle\Entity\Category; |
||
24 | use Mautic\CoreBundle\Controller\FormErrorMessagesTrait; |
||
25 | use Mautic\CoreBundle\Controller\MauticController; |
||
26 | use Mautic\CoreBundle\Factory\MauticFactory; |
||
27 | use Mautic\CoreBundle\Form\RequestTrait; |
||
28 | use Mautic\CoreBundle\Helper\CoreParametersHelper; |
||
29 | use Mautic\CoreBundle\Helper\InputHelper; |
||
30 | use Mautic\CoreBundle\Model\AbstractCommonModel; |
||
31 | use Mautic\CoreBundle\Security\Exception\PermissionException; |
||
32 | use Mautic\CoreBundle\Service\FlashBag; |
||
33 | use Mautic\UserBundle\Entity\User; |
||
34 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
35 | use Symfony\Component\Form\Form; |
||
36 | use Symfony\Component\HttpFoundation\RedirectResponse; |
||
37 | use Symfony\Component\HttpFoundation\Request; |
||
38 | use Symfony\Component\HttpFoundation\Response; |
||
39 | use Symfony\Component\HttpKernel\Event\FilterControllerEvent; |
||
40 | use Symfony\Component\Translation\TranslatorInterface; |
||
41 | |||
42 | /** |
||
43 | * Class CommonApiController. |
||
44 | */ |
||
45 | class CommonApiController extends FOSRestController implements MauticController |
||
46 | { |
||
47 | use RequestTrait; |
||
48 | use FormErrorMessagesTrait; |
||
49 | |||
50 | /** |
||
51 | * @var CoreParametersHelper |
||
52 | */ |
||
53 | protected $coreParametersHelper; |
||
54 | |||
55 | /** |
||
56 | * If set to true, serializer will not return null values. |
||
57 | * |
||
58 | * @var bool |
||
59 | */ |
||
60 | protected $customSelectRequested = false; |
||
61 | |||
62 | /** |
||
63 | * @var array |
||
64 | */ |
||
65 | protected $dataInputMasks = []; |
||
66 | |||
67 | /** |
||
68 | * @var EventDispatcherInterface |
||
69 | */ |
||
70 | protected $dispatcher; |
||
71 | |||
72 | /** |
||
73 | * Class for the entity. |
||
74 | * |
||
75 | * @var string |
||
76 | */ |
||
77 | protected $entityClass; |
||
78 | |||
79 | /** |
||
80 | * Key to return for entity lists. |
||
81 | * |
||
82 | * @var string |
||
83 | */ |
||
84 | protected $entityNameMulti; |
||
85 | |||
86 | /** |
||
87 | * Key to return for a single entity. |
||
88 | * |
||
89 | * @var string |
||
90 | */ |
||
91 | protected $entityNameOne; |
||
92 | |||
93 | /** |
||
94 | * Custom JMS strategies to add to the view's context. |
||
95 | * |
||
96 | * @var array |
||
97 | */ |
||
98 | protected $exclusionStrategies = []; |
||
99 | |||
100 | /** |
||
101 | * Pass to the model's getEntities() method. |
||
102 | * |
||
103 | * @var array |
||
104 | */ |
||
105 | protected $extraGetEntitiesArguments = []; |
||
106 | |||
107 | /** |
||
108 | * @var MauticFactory |
||
109 | */ |
||
110 | protected $factory; |
||
111 | |||
112 | /** |
||
113 | * @var bool |
||
114 | */ |
||
115 | protected $inBatchMode = false; |
||
116 | |||
117 | /** |
||
118 | * Used to set default filters for entity lists such as restricting to owning user. |
||
119 | * |
||
120 | * @var array |
||
121 | */ |
||
122 | protected $listFilters = []; |
||
123 | |||
124 | /** |
||
125 | * Model object for processing the entity. |
||
126 | * |
||
127 | * @var \Mautic\CoreBundle\Model\AbstractCommonModel |
||
128 | */ |
||
129 | protected $model; |
||
130 | |||
131 | /** |
||
132 | * The level parent/children should stop loading if applicable. |
||
133 | * |
||
134 | * @var int |
||
135 | */ |
||
136 | protected $parentChildrenLevelDepth = 3; |
||
137 | |||
138 | /** |
||
139 | * Permission base for the entity such as page:pages. |
||
140 | * |
||
141 | * @var string |
||
142 | */ |
||
143 | protected $permissionBase; |
||
144 | |||
145 | /** |
||
146 | * @var Request |
||
147 | */ |
||
148 | protected $request; |
||
149 | |||
150 | /** |
||
151 | * @var array |
||
152 | */ |
||
153 | protected $routeParams = []; |
||
154 | |||
155 | /** |
||
156 | * @var \Mautic\CoreBundle\Security\Permissions\CorePermissions |
||
157 | */ |
||
158 | protected $security; |
||
159 | |||
160 | /** |
||
161 | * @var array |
||
162 | */ |
||
163 | protected $serializerGroups = []; |
||
164 | |||
165 | /** |
||
166 | * @var TranslatorInterface |
||
167 | */ |
||
168 | protected $translator; |
||
169 | |||
170 | /** |
||
171 | * @var User |
||
172 | */ |
||
173 | protected $user; |
||
174 | |||
175 | /** |
||
176 | * @var array |
||
177 | */ |
||
178 | protected $entityRequestParameters = []; |
||
179 | |||
180 | /** |
||
181 | * Delete a batch of entities. |
||
182 | * |
||
183 | * @return array|Response |
||
184 | */ |
||
185 | public function deleteEntitiesAction() |
||
186 | { |
||
187 | $parameters = $this->request->query->all(); |
||
188 | |||
189 | $valid = $this->validateBatchPayload($parameters); |
||
190 | if ($valid instanceof Response) { |
||
191 | return $valid; |
||
192 | } |
||
193 | |||
194 | $errors = []; |
||
195 | $entities = $this->getBatchEntities($parameters, $errors, true); |
||
196 | $this->inBatchMode = true; |
||
197 | |||
198 | // Generate the view before deleting so that the IDs are still populated before Doctrine removes them |
||
199 | $payload = [$this->entityNameMulti => $entities]; |
||
200 | $view = $this->view($payload, Response::HTTP_OK); |
||
201 | $this->setSerializationContext($view); |
||
202 | $response = $this->handleView($view); |
||
203 | |||
204 | foreach ($entities as $key => $entity) { |
||
205 | if (null === $entity || !$entity->getId()) { |
||
206 | $this->setBatchError($key, 'mautic.core.error.notfound', Response::HTTP_NOT_FOUND, $errors, $entities, $entity); |
||
207 | continue; |
||
208 | } |
||
209 | |||
210 | if (!$this->checkEntityAccess($entity, 'delete')) { |
||
211 | $this->setBatchError($key, 'mautic.core.error.accessdenied', Response::HTTP_FORBIDDEN, $errors, $entities, $entity); |
||
212 | continue; |
||
213 | } |
||
214 | |||
215 | $this->model->deleteEntity($entity); |
||
216 | $this->getDoctrine()->getManager()->detach($entity); |
||
217 | } |
||
218 | |||
219 | if (!empty($errors)) { |
||
220 | $content = json_decode($response->getContent(), true); |
||
221 | $content['errors'] = $errors; |
||
222 | $response->setContent(json_encode($content)); |
||
223 | } |
||
224 | |||
225 | return $response; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Deletes an entity. |
||
230 | * |
||
231 | * @param int $id Entity ID |
||
232 | * |
||
233 | * @return Response |
||
234 | */ |
||
235 | public function deleteEntityAction($id) |
||
236 | { |
||
237 | $entity = $this->model->getEntity($id); |
||
238 | if (null !== $entity) { |
||
239 | if (!$this->checkEntityAccess($entity, 'delete')) { |
||
240 | return $this->accessDenied(); |
||
241 | } |
||
242 | |||
243 | $this->model->deleteEntity($entity); |
||
244 | |||
245 | $this->preSerializeEntity($entity); |
||
246 | $view = $this->view([$this->entityNameOne => $entity], Response::HTTP_OK); |
||
247 | $this->setSerializationContext($view); |
||
248 | |||
249 | return $this->handleView($view); |
||
250 | } |
||
251 | |||
252 | return $this->notFound(); |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * Edit a batch of entities. |
||
257 | * |
||
258 | * @return array|Response |
||
259 | */ |
||
260 | public function editEntitiesAction() |
||
261 | { |
||
262 | $parameters = $this->request->request->all(); |
||
263 | |||
264 | $valid = $this->validateBatchPayload($parameters); |
||
265 | if ($valid instanceof Response) { |
||
266 | return $valid; |
||
267 | } |
||
268 | |||
269 | $errors = []; |
||
270 | $statusCodes = []; |
||
271 | $entities = $this->getBatchEntities($parameters, $errors); |
||
272 | |||
273 | foreach ($parameters as $key => $params) { |
||
274 | $method = $this->request->getMethod(); |
||
275 | $entity = (isset($entities[$key])) ? $entities[$key] : null; |
||
276 | |||
277 | $statusCode = Response::HTTP_OK; |
||
278 | if (null === $entity || !$entity->getId()) { |
||
279 | if ('PATCH' === $method) { |
||
280 | //PATCH requires that an entity exists |
||
281 | $this->setBatchError($key, 'mautic.core.error.notfound', Response::HTTP_NOT_FOUND, $errors, $entities, $entity); |
||
282 | $statusCodes[$key] = Response::HTTP_NOT_FOUND; |
||
283 | continue; |
||
284 | } |
||
285 | |||
286 | //PUT can create a new entity if it doesn't exist |
||
287 | $entity = $this->model->getEntity(); |
||
288 | if (!$this->checkEntityAccess($entity, 'create')) { |
||
289 | $this->setBatchError($key, 'mautic.core.error.accessdenied', Response::HTTP_FORBIDDEN, $errors, $entities, $entity); |
||
290 | $statusCodes[$key] = Response::HTTP_FORBIDDEN; |
||
291 | continue; |
||
292 | } |
||
293 | |||
294 | $statusCode = Response::HTTP_CREATED; |
||
295 | } |
||
296 | |||
297 | if (!$this->checkEntityAccess($entity, 'edit')) { |
||
298 | $this->setBatchError($key, 'mautic.core.error.accessdenied', Response::HTTP_FORBIDDEN, $errors, $entities, $entity); |
||
299 | $statusCodes[$key] = Response::HTTP_FORBIDDEN; |
||
300 | continue; |
||
301 | } |
||
302 | |||
303 | $this->processBatchForm($key, $entity, $params, $method, $errors, $entities); |
||
304 | |||
305 | if (isset($errors[$key])) { |
||
306 | $statusCodes[$key] = $errors[$key]['code']; |
||
307 | } else { |
||
308 | $statusCodes[$key] = $statusCode; |
||
309 | } |
||
310 | } |
||
311 | |||
312 | $payload = [ |
||
313 | $this->entityNameMulti => $entities, |
||
314 | 'statusCodes' => $statusCodes, |
||
315 | ]; |
||
316 | |||
317 | if (!empty($errors)) { |
||
318 | $payload['errors'] = $errors; |
||
319 | } |
||
320 | |||
321 | $view = $this->view($payload, Response::HTTP_OK); |
||
322 | $this->setSerializationContext($view); |
||
323 | |||
324 | return $this->handleView($view); |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Edits an existing entity or creates one on PUT if it doesn't exist. |
||
329 | * |
||
330 | * @param int $id Entity ID |
||
331 | * |
||
332 | * @return Response |
||
333 | */ |
||
334 | public function editEntityAction($id) |
||
335 | { |
||
336 | $entity = $this->model->getEntity($id); |
||
337 | $parameters = $this->request->request->all(); |
||
338 | $method = $this->request->getMethod(); |
||
339 | |||
340 | if (null === $entity || !$entity->getId()) { |
||
341 | if ('PATCH' === $method) { |
||
342 | //PATCH requires that an entity exists |
||
343 | return $this->notFound(); |
||
344 | } |
||
345 | |||
346 | //PUT can create a new entity if it doesn't exist |
||
347 | $entity = $this->model->getEntity(); |
||
348 | if (!$this->checkEntityAccess($entity, 'create')) { |
||
349 | return $this->accessDenied(); |
||
350 | } |
||
351 | } |
||
352 | |||
353 | if (!$this->checkEntityAccess($entity, 'edit')) { |
||
354 | return $this->accessDenied(); |
||
355 | } |
||
356 | |||
357 | return $this->processForm($entity, $parameters, $method); |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * Obtains a list of entities as defined by the API URL. |
||
362 | * |
||
363 | * @return Response |
||
364 | */ |
||
365 | public function getEntitiesAction() |
||
366 | { |
||
367 | $repo = $this->model->getRepository(); |
||
368 | $tableAlias = $repo->getTableAlias(); |
||
369 | $publishedOnly = $this->request->get('published', 0); |
||
370 | $minimal = $this->request->get('minimal', 0); |
||
371 | |||
372 | try { |
||
373 | if (!$this->security->isGranted($this->permissionBase.':view')) { |
||
374 | return $this->accessDenied(); |
||
375 | } |
||
376 | } catch (PermissionException $e) { |
||
377 | return $this->accessDenied($e->getMessage()); |
||
378 | } |
||
379 | |||
380 | if ($this->security->checkPermissionExists($this->permissionBase.':viewother') |
||
381 | && !$this->security->isGranted($this->permissionBase.':viewother') |
||
382 | ) { |
||
383 | $this->listFilters[] = [ |
||
384 | 'column' => $tableAlias.'.createdBy', |
||
385 | 'expr' => 'eq', |
||
386 | 'value' => $this->user->getId(), |
||
387 | ]; |
||
388 | } |
||
389 | |||
390 | if ($publishedOnly) { |
||
391 | $this->listFilters[] = [ |
||
392 | 'column' => $tableAlias.'.isPublished', |
||
393 | 'expr' => 'eq', |
||
394 | 'value' => true, |
||
395 | ]; |
||
396 | } |
||
397 | |||
398 | if ($minimal) { |
||
399 | if (isset($this->serializerGroups[0])) { |
||
400 | $this->serializerGroups[0] = str_replace('Details', 'List', $this->serializerGroups[0]); |
||
401 | } |
||
402 | } |
||
403 | |||
404 | $args = array_merge( |
||
405 | [ |
||
406 | 'start' => $this->request->query->get('start', 0), |
||
407 | 'limit' => $this->request->query->get('limit', $this->coreParametersHelper->get('default_pagelimit')), |
||
408 | 'filter' => [ |
||
409 | 'string' => $this->request->query->get('search', ''), |
||
410 | 'force' => $this->listFilters, |
||
411 | ], |
||
412 | 'orderBy' => $this->addAliasIfNotPresent($this->request->query->get('orderBy', ''), $tableAlias), |
||
413 | 'orderByDir' => $this->request->query->get('orderByDir', 'ASC'), |
||
414 | 'withTotalCount' => true, //for repositories that break free of Paginator |
||
415 | ], |
||
416 | $this->extraGetEntitiesArguments |
||
417 | ); |
||
418 | |||
419 | if ($select = InputHelper::cleanArray($this->request->get('select', []))) { |
||
420 | $args['select'] = $select; |
||
421 | $this->customSelectRequested = true; |
||
422 | } |
||
423 | |||
424 | if ($where = $this->getWhereFromRequest()) { |
||
425 | $args['filter']['where'] = $where; |
||
426 | } |
||
427 | |||
428 | if ($order = $this->getOrderFromRequest()) { |
||
429 | $args['filter']['order'] = $order; |
||
430 | } |
||
431 | |||
432 | $results = $this->model->getEntities($args); |
||
433 | |||
434 | [$entities, $totalCount] = $this->prepareEntitiesForView($results); |
||
435 | |||
436 | $view = $this->view( |
||
437 | [ |
||
438 | 'total' => $totalCount, |
||
439 | $this->entityNameMulti => $entities, |
||
440 | ], |
||
441 | Response::HTTP_OK |
||
442 | ); |
||
443 | $this->setSerializationContext($view); |
||
444 | |||
445 | return $this->handleView($view); |
||
446 | } |
||
447 | |||
448 | /** |
||
449 | * Sanitizes and returns an array of where statements from the request. |
||
450 | * |
||
451 | * @return array |
||
452 | */ |
||
453 | protected function getWhereFromRequest() |
||
454 | { |
||
455 | $where = InputHelper::cleanArray($this->request->get('where', [])); |
||
456 | |||
457 | $this->sanitizeWhereClauseArrayFromRequest($where); |
||
458 | |||
459 | return $where; |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Sanitizes and returns an array of ORDER statements from the request. |
||
464 | * |
||
465 | * @return array |
||
466 | */ |
||
467 | protected function getOrderFromRequest() |
||
468 | { |
||
469 | return InputHelper::cleanArray($this->request->get('order', [])); |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * Adds the repository alias to the column name if it doesn't exist. |
||
474 | * |
||
475 | * @return string $column name with alias prefix |
||
476 | */ |
||
477 | protected function addAliasIfNotPresent($columns, $alias) |
||
478 | { |
||
479 | if (!$columns) { |
||
480 | return $columns; |
||
481 | } |
||
482 | |||
483 | $columns = explode(',', trim($columns)); |
||
484 | $prefix = $alias.'.'; |
||
485 | |||
486 | array_walk( |
||
487 | $columns, |
||
488 | function (&$column, $key, $prefix) { |
||
489 | $column = trim($column); |
||
490 | if (1 === count(explode('.', $column))) { |
||
491 | $column = $prefix.$column; |
||
492 | } |
||
493 | }, |
||
494 | $prefix |
||
495 | ); |
||
496 | |||
497 | return implode(',', $columns); |
||
498 | } |
||
499 | |||
500 | /** |
||
501 | * Obtains a specific entity as defined by the API URL. |
||
502 | * |
||
503 | * @param int $id Entity ID |
||
504 | * |
||
505 | * @return Response |
||
506 | */ |
||
507 | public function getEntityAction($id) |
||
508 | { |
||
509 | $args = []; |
||
510 | if ($select = InputHelper::cleanArray($this->request->get('select', []))) { |
||
511 | $args['select'] = $select; |
||
512 | $this->customSelectRequested = true; |
||
513 | } |
||
514 | |||
515 | if (!empty($args)) { |
||
516 | $args['id'] = $id; |
||
517 | $entity = $this->model->getEntity($args); |
||
518 | } else { |
||
519 | $entity = $this->model->getEntity($id); |
||
520 | } |
||
521 | |||
522 | if (!$entity instanceof $this->entityClass) { |
||
523 | return $this->notFound(); |
||
524 | } |
||
525 | |||
526 | if (!$this->checkEntityAccess($entity)) { |
||
527 | return $this->accessDenied(); |
||
528 | } |
||
529 | |||
530 | $this->preSerializeEntity($entity); |
||
531 | $view = $this->view([$this->entityNameOne => $entity], Response::HTTP_OK); |
||
532 | $this->setSerializationContext($view); |
||
533 | |||
534 | return $this->handleView($view); |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * Initialize some variables. |
||
539 | */ |
||
540 | public function initialize(FilterControllerEvent $event) |
||
541 | { |
||
542 | $this->security = $this->get('mautic.security'); |
||
543 | |||
544 | if ($this->model && !$this->permissionBase && method_exists($this->model, 'getPermissionBase')) { |
||
545 | $this->permissionBase = $this->model->getPermissionBase(); |
||
546 | } |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * Creates new entity from provided params. |
||
551 | * |
||
552 | * @return object |
||
553 | */ |
||
554 | public function getNewEntity(array $params) |
||
555 | { |
||
556 | return $this->model->getEntity(); |
||
0 ignored issues
–
show
|
|||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Create a batch of new entities. |
||
561 | * |
||
562 | * @return array|Response |
||
563 | */ |
||
564 | public function newEntitiesAction() |
||
565 | { |
||
566 | $entity = $this->model->getEntity(); |
||
567 | |||
568 | if (!$this->checkEntityAccess($entity, 'create')) { |
||
569 | return $this->accessDenied(); |
||
570 | } |
||
571 | |||
572 | $parameters = $this->request->request->all(); |
||
573 | |||
574 | $valid = $this->validateBatchPayload($parameters); |
||
575 | if ($valid instanceof Response) { |
||
576 | return $valid; |
||
577 | } |
||
578 | |||
579 | $this->inBatchMode = true; |
||
580 | $entities = []; |
||
581 | $errors = []; |
||
582 | $statusCodes = []; |
||
583 | foreach ($parameters as $key => $params) { |
||
584 | // Can be new or an existing on based on params |
||
585 | $entity = $this->getNewEntity($params); |
||
586 | $entityExists = false; |
||
587 | $method = 'POST'; |
||
588 | if ($entity->getId()) { |
||
589 | $entityExists = true; |
||
590 | $method = 'PATCH'; |
||
591 | if (!$this->checkEntityAccess($entity, 'edit')) { |
||
592 | $this->setBatchError($key, 'mautic.core.error.accessdenied', Response::HTTP_FORBIDDEN, $errors, $entities, $entity); |
||
593 | $statusCodes[$key] = Response::HTTP_FORBIDDEN; |
||
594 | continue; |
||
595 | } |
||
596 | } |
||
597 | $this->processBatchForm($key, $entity, $params, $method, $errors, $entities); |
||
598 | |||
599 | if (isset($errors[$key])) { |
||
600 | $statusCodes[$key] = $errors[$key]['code']; |
||
601 | } elseif ($entityExists) { |
||
602 | $statusCodes[$key] = Response::HTTP_OK; |
||
603 | } else { |
||
604 | $statusCodes[$key] = Response::HTTP_CREATED; |
||
605 | } |
||
606 | } |
||
607 | |||
608 | $payload = [ |
||
609 | $this->entityNameMulti => $entities, |
||
610 | 'statusCodes' => $statusCodes, |
||
611 | ]; |
||
612 | |||
613 | if (!empty($errors)) { |
||
614 | $payload['errors'] = $errors; |
||
615 | } |
||
616 | |||
617 | $view = $this->view($payload, Response::HTTP_CREATED); |
||
618 | $this->setSerializationContext($view); |
||
619 | |||
620 | return $this->handleView($view); |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * Creates a new entity. |
||
625 | * |
||
626 | * @return Response |
||
627 | */ |
||
628 | public function newEntityAction() |
||
629 | { |
||
630 | $parameters = $this->request->request->all(); |
||
631 | $entity = $this->getNewEntity($parameters); |
||
632 | |||
633 | if (!$this->checkEntityAccess($entity, 'create')) { |
||
634 | return $this->accessDenied(); |
||
635 | } |
||
636 | |||
637 | return $this->processForm($entity, $parameters, 'POST'); |
||
638 | } |
||
639 | |||
640 | public function setCoreParametersHelper(CoreParametersHelper $coreParametersHelper) |
||
641 | { |
||
642 | $this->coreParametersHelper = $coreParametersHelper; |
||
643 | } |
||
644 | |||
645 | public function setDispatcher(EventDispatcherInterface $dispatcher) |
||
646 | { |
||
647 | $this->dispatcher = $dispatcher; |
||
648 | } |
||
649 | |||
650 | public function setFactory(MauticFactory $factory) |
||
651 | { |
||
652 | $this->factory = $factory; |
||
653 | } |
||
654 | |||
655 | public function setRequest(Request $request) |
||
656 | { |
||
657 | $this->request = $request; |
||
658 | } |
||
659 | |||
660 | public function setTranslator(TranslatorInterface $translator) |
||
661 | { |
||
662 | $this->translator = $translator; |
||
663 | } |
||
664 | |||
665 | public function setFlashBag(FlashBag $flashBag) |
||
666 | { |
||
667 | // @see \Mautic\CoreBundle\EventListener\CoreSubscriber::onKernelController() |
||
668 | } |
||
669 | |||
670 | public function setUser(User $user) |
||
671 | { |
||
672 | $this->user = $user; |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * Alias for notFound method. It's used in the LeadAccessTrait. |
||
677 | * |
||
678 | * @param array $args |
||
679 | * |
||
680 | * @return Response |
||
681 | */ |
||
682 | public function postActionRedirect($args = []) |
||
683 | { |
||
684 | return $this->notFound('mautic.contact.error.notfound'); |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * Returns a 403 Access Denied. |
||
689 | * |
||
690 | * @param string $msg |
||
691 | * |
||
692 | * @return Response |
||
693 | */ |
||
694 | protected function accessDenied($msg = 'mautic.core.error.accessdenied') |
||
695 | { |
||
696 | return $this->returnError($msg, Response::HTTP_FORBIDDEN); |
||
697 | } |
||
698 | |||
699 | protected function addExclusionStrategy(ExclusionStrategyInterface $strategy) |
||
700 | { |
||
701 | $this->exclusionStrategies[] = $strategy; |
||
702 | } |
||
703 | |||
704 | /** |
||
705 | * Returns a 400 Bad Request. |
||
706 | * |
||
707 | * @param string $msg |
||
708 | * |
||
709 | * @return Response |
||
710 | */ |
||
711 | protected function badRequest($msg = 'mautic.core.error.badrequest') |
||
712 | { |
||
713 | return $this->returnError($msg, Response::HTTP_BAD_REQUEST); |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * Checks if user has permission to access retrieved entity. |
||
718 | * |
||
719 | * @param mixed $entity |
||
720 | * @param string $action view|create|edit|publish|delete |
||
721 | * |
||
722 | * @return bool|Response |
||
723 | */ |
||
724 | protected function checkEntityAccess($entity, $action = 'view') |
||
725 | { |
||
726 | if ('create' != $action && method_exists($entity, 'getCreatedBy')) { |
||
727 | $ownPerm = "{$this->permissionBase}:{$action}own"; |
||
728 | $otherPerm = "{$this->permissionBase}:{$action}other"; |
||
729 | |||
730 | $owner = (method_exists($entity, 'getPermissionUser')) ? $entity->getPermissionUser() : $entity->getCreatedBy(); |
||
731 | |||
732 | return $this->security->hasEntityAccess($ownPerm, $otherPerm, $owner); |
||
733 | } |
||
734 | |||
735 | try { |
||
736 | return $this->security->isGranted("{$this->permissionBase}:{$action}"); |
||
737 | } catch (PermissionException $e) { |
||
738 | return $this->accessDenied($e->getMessage()); |
||
739 | } |
||
740 | } |
||
741 | |||
742 | /** |
||
743 | * Creates the form instance. |
||
744 | * |
||
745 | * @param $entity |
||
746 | * |
||
747 | * @return Form |
||
748 | */ |
||
749 | protected function createEntityForm($entity) |
||
750 | { |
||
751 | return $this->model->createForm( |
||
752 | $entity, |
||
753 | $this->get('form.factory'), |
||
754 | null, |
||
755 | array_merge( |
||
756 | [ |
||
757 | 'csrf_protection' => false, |
||
758 | 'allow_extra_fields' => true, |
||
759 | ], |
||
760 | $this->getEntityFormOptions() |
||
761 | ) |
||
762 | ); |
||
763 | } |
||
764 | |||
765 | /** |
||
766 | * @param $parameters |
||
767 | * @param $errors |
||
768 | * @param bool $prepareForSerialization |
||
769 | * @param string $requestIdColumn |
||
770 | * @param null $model |
||
771 | * @param bool $returnWithOriginalKeys |
||
772 | * |
||
773 | * @return array|mixed |
||
774 | */ |
||
775 | protected function getBatchEntities($parameters, &$errors, $prepareForSerialization = false, $requestIdColumn = 'id', $model = null, $returnWithOriginalKeys = true) |
||
776 | { |
||
777 | $ids = []; |
||
778 | if (isset($parameters['ids'])) { |
||
779 | foreach ($parameters['ids'] as $key => $id) { |
||
780 | $ids[(int) $id] = $key; |
||
781 | } |
||
782 | } else { |
||
783 | foreach ($parameters as $key => $params) { |
||
784 | if (is_array($params) && !isset($params[$requestIdColumn])) { |
||
785 | $this->setBatchError($key, 'mautic.api.call.id_missing', Response::HTTP_BAD_REQUEST, $errors); |
||
786 | continue; |
||
787 | } |
||
788 | |||
789 | $id = (is_array($params)) ? (int) $params[$requestIdColumn] : (int) $params; |
||
790 | $ids[$id] = $key; |
||
791 | } |
||
792 | } |
||
793 | $return = []; |
||
794 | if (!empty($ids)) { |
||
795 | $model = ($model) ? $model : $this->model; |
||
796 | $entities = $model->getEntities( |
||
797 | [ |
||
798 | 'filter' => [ |
||
799 | 'force' => [ |
||
800 | [ |
||
801 | 'column' => $model->getRepository()->getTableAlias().'.id', |
||
802 | 'expr' => 'in', |
||
803 | 'value' => array_keys($ids), |
||
804 | ], |
||
805 | ], |
||
806 | ], |
||
807 | 'ignore_paginator' => true, |
||
808 | ] |
||
809 | ); |
||
810 | |||
811 | [$entities, $total] = $prepareForSerialization |
||
812 | ? |
||
813 | $this->prepareEntitiesForView($entities) |
||
814 | : |
||
815 | $this->prepareEntityResultsToArray($entities); |
||
816 | |||
817 | foreach ($entities as $entity) { |
||
818 | if ($returnWithOriginalKeys) { |
||
819 | // Ensure same keys as params |
||
820 | $return[$ids[$entity->getId()]] = $entity; |
||
821 | } else { |
||
822 | $return[$entity->getId()] = $entity; |
||
823 | } |
||
824 | } |
||
825 | } |
||
826 | |||
827 | return $return; |
||
828 | } |
||
829 | |||
830 | /** |
||
831 | * Get the default properties of an entity and parents. |
||
832 | * |
||
833 | * @param $entity |
||
834 | * |
||
835 | * @return array |
||
836 | */ |
||
837 | protected function getEntityDefaultProperties($entity) |
||
838 | { |
||
839 | $class = get_class($entity); |
||
840 | $chain = array_reverse(class_parents($entity), true) + [$class => $class]; |
||
841 | $defaultValues = []; |
||
842 | |||
843 | $classMetdata = new ClassMetadata($class); |
||
844 | foreach ($chain as $class) { |
||
845 | if (method_exists($class, 'loadMetadata')) { |
||
846 | $class::loadMetadata($classMetdata); |
||
847 | } |
||
848 | $defaultValues += (new \ReflectionClass($class))->getDefaultProperties(); |
||
849 | } |
||
850 | |||
851 | // These are the mapped columns |
||
852 | $fields = $classMetdata->getFieldNames(); |
||
853 | |||
854 | // Merge values in with $fields |
||
855 | $properties = []; |
||
856 | foreach ($fields as $field) { |
||
857 | $properties[$field] = $defaultValues[$field]; |
||
858 | } |
||
859 | |||
860 | return $properties; |
||
861 | } |
||
862 | |||
863 | /** |
||
864 | * Append options to the form. |
||
865 | * |
||
866 | * @return array |
||
867 | */ |
||
868 | protected function getEntityFormOptions() |
||
869 | { |
||
870 | return []; |
||
871 | } |
||
872 | |||
873 | /** |
||
874 | * Get a model instance from the service container. |
||
875 | * |
||
876 | * @param $modelNameKey |
||
877 | * |
||
878 | * @return AbstractCommonModel |
||
879 | */ |
||
880 | protected function getModel($modelNameKey) |
||
881 | { |
||
882 | return $this->get('mautic.model.factory')->getModel($modelNameKey); |
||
883 | } |
||
884 | |||
885 | /** |
||
886 | * Returns a 404 Not Found. |
||
887 | * |
||
888 | * @param string $msg |
||
889 | * |
||
890 | * @return Response |
||
891 | */ |
||
892 | protected function notFound($msg = 'mautic.core.error.notfound') |
||
893 | { |
||
894 | return $this->returnError($msg, Response::HTTP_NOT_FOUND); |
||
895 | } |
||
896 | |||
897 | /** |
||
898 | * Gives child controllers opportunity to analyze and do whatever to an entity before populating the form. |
||
899 | * |
||
900 | * @param $entity |
||
901 | * @param $parameters |
||
902 | * @param string $action |
||
903 | * |
||
904 | * @return mixed |
||
905 | */ |
||
906 | protected function prePopulateForm(&$entity, $parameters, $action = 'edit') |
||
907 | { |
||
908 | } |
||
909 | |||
910 | /** |
||
911 | * Give the controller an opportunity to process the entity before persisting. |
||
912 | * |
||
913 | * @param $entity |
||
914 | * @param $form |
||
915 | * @param $parameters |
||
916 | * @param $action |
||
917 | * |
||
918 | * @return mixed |
||
919 | */ |
||
920 | protected function preSaveEntity(&$entity, $form, $parameters, $action = 'edit') |
||
921 | { |
||
922 | } |
||
923 | |||
924 | /** |
||
925 | * Gives child controllers opportunity to analyze and do whatever to an entity before going through serializer. |
||
926 | * |
||
927 | * @param $entity |
||
928 | * @param string $action |
||
929 | * |
||
930 | * @return mixed |
||
931 | */ |
||
932 | protected function preSerializeEntity(&$entity, $action = 'view') |
||
933 | { |
||
934 | } |
||
935 | |||
936 | /** |
||
937 | * Prepares entities returned from repository getEntities(). |
||
938 | * |
||
939 | * @param $results |
||
940 | * |
||
941 | * @return array($entities, $totalCount) |
||
942 | */ |
||
943 | protected function prepareEntitiesForView($results) |
||
944 | { |
||
945 | return $this->prepareEntityResultsToArray( |
||
946 | $results, |
||
947 | function ($entity) { |
||
948 | $this->preSerializeEntity($entity); |
||
949 | } |
||
950 | ); |
||
951 | } |
||
952 | |||
953 | /** |
||
954 | * @param $results |
||
955 | * @param null $callback |
||
956 | * |
||
957 | * @return array($entities, $totalCount) |
||
958 | */ |
||
959 | protected function prepareEntityResultsToArray($results, $callback = null) |
||
960 | { |
||
961 | if ($results instanceof Paginator) { |
||
962 | $totalCount = count($results); |
||
963 | } elseif (isset($results['count'])) { |
||
964 | $totalCount = $results['count']; |
||
965 | $results = $results['results']; |
||
966 | } else { |
||
967 | $totalCount = count($results); |
||
968 | } |
||
969 | |||
970 | //we have to convert them from paginated proxy functions to entities in order for them to be |
||
971 | //returned by the serializer/rest bundle |
||
972 | $entities = []; |
||
973 | foreach ($results as $key => $r) { |
||
974 | if (is_array($r) && isset($r[0])) { |
||
975 | //entity has some extra something something tacked onto the entities |
||
976 | if (is_object($r[0])) { |
||
977 | foreach ($r as $k => $v) { |
||
978 | if (0 === $k) { |
||
979 | continue; |
||
980 | } |
||
981 | |||
982 | $r[0]->$k = $v; |
||
983 | } |
||
984 | $entities[$key] = $r[0]; |
||
985 | } elseif (is_array($r[0])) { |
||
986 | foreach ($r[0] as $k => $v) { |
||
987 | $r[$k] = $v; |
||
988 | } |
||
989 | unset($r[0]); |
||
990 | $entities[$key] = $r; |
||
991 | } |
||
992 | } else { |
||
993 | $entities[$key] = $r; |
||
994 | } |
||
995 | |||
996 | if (is_callable($callback)) { |
||
997 | $callback($entities[$key]); |
||
998 | } |
||
999 | } |
||
1000 | |||
1001 | return [$entities, $totalCount]; |
||
1002 | } |
||
1003 | |||
1004 | /** |
||
1005 | * Convert posted parameters into what the form needs in order to successfully bind. |
||
1006 | * |
||
1007 | * @param $parameters |
||
1008 | * @param $entity |
||
1009 | * @param $action |
||
1010 | * |
||
1011 | * @return mixed |
||
1012 | */ |
||
1013 | protected function prepareParametersForBinding($parameters, $entity, $action) |
||
1014 | { |
||
1015 | return $parameters; |
||
1016 | } |
||
1017 | |||
1018 | /** |
||
1019 | * @param $key |
||
1020 | * @param $entity |
||
1021 | * @param $params |
||
1022 | * @param $method |
||
1023 | * @param $errors |
||
1024 | * @param $entities |
||
1025 | */ |
||
1026 | protected function processBatchForm($key, $entity, $params, $method, &$errors, &$entities) |
||
1027 | { |
||
1028 | $this->inBatchMode = true; |
||
1029 | $formResponse = $this->processForm($entity, $params, $method); |
||
1030 | if ($formResponse instanceof Response) { |
||
1031 | if (!$formResponse instanceof RedirectResponse) { |
||
1032 | // Assume an error |
||
1033 | $this->setBatchError( |
||
1034 | $key, |
||
1035 | InputHelper::string($formResponse->getContent()), |
||
1036 | $formResponse->getStatusCode(), |
||
1037 | $errors, |
||
1038 | $entities, |
||
1039 | $entity |
||
1040 | ); |
||
1041 | } |
||
1042 | } elseif (is_object($formResponse) && get_class($formResponse) === get_class($entity)) { |
||
1043 | // Success |
||
1044 | $entities[$key] = $formResponse; |
||
1045 | } elseif (is_array($formResponse) && isset($formResponse['code'], $formResponse['message'])) { |
||
1046 | // There was an error |
||
1047 | $errors[$key] = $formResponse; |
||
1048 | } |
||
1049 | |||
1050 | $this->getDoctrine()->getManager()->detach($entity); |
||
1051 | |||
1052 | $this->inBatchMode = false; |
||
1053 | } |
||
1054 | |||
1055 | /** |
||
1056 | * Processes API Form. |
||
1057 | * |
||
1058 | * @param $entity |
||
1059 | * @param null $parameters |
||
1060 | * @param string $method |
||
1061 | * |
||
1062 | * @return mixed |
||
1063 | */ |
||
1064 | protected function processForm($entity, $parameters = null, $method = 'PUT') |
||
1065 | { |
||
1066 | $categoryId = null; |
||
1067 | |||
1068 | if (null === $parameters) { |
||
1069 | //get from request |
||
1070 | $parameters = $this->request->request->all(); |
||
1071 | } |
||
1072 | |||
1073 | // Store the original parameters from the request so that callbacks can have access to them as needed |
||
1074 | $this->entityRequestParameters = $parameters; |
||
1075 | |||
1076 | //unset the ID in the parameters if set as this will cause the form to fail |
||
1077 | if (isset($parameters['id'])) { |
||
1078 | unset($parameters['id']); |
||
1079 | } |
||
1080 | |||
1081 | //is an entity being updated or created? |
||
1082 | if ($entity->getId()) { |
||
1083 | $statusCode = Response::HTTP_OK; |
||
1084 | $action = 'edit'; |
||
1085 | } else { |
||
1086 | $statusCode = Response::HTTP_CREATED; |
||
1087 | $action = 'new'; |
||
1088 | |||
1089 | // All the properties have to be defined in order for validation to work |
||
1090 | // Bug reported https://github.com/symfony/symfony/issues/19788 |
||
1091 | $defaultProperties = $this->getEntityDefaultProperties($entity); |
||
1092 | $parameters = array_merge($defaultProperties, $parameters); |
||
1093 | } |
||
1094 | |||
1095 | // Check if user has access to publish |
||
1096 | if ( |
||
1097 | ( |
||
1098 | array_key_exists('isPublished', $parameters) || |
||
1099 | array_key_exists('publishUp', $parameters) || |
||
1100 | array_key_exists('publishDown', $parameters) |
||
1101 | ) && |
||
1102 | $this->security->checkPermissionExists($this->permissionBase.':publish')) { |
||
1103 | if ($this->security->checkPermissionExists($this->permissionBase.':publishown')) { |
||
1104 | if (!$this->checkEntityAccess($entity, 'publish')) { |
||
1105 | if ('new' === $action) { |
||
1106 | $parameters['isPublished'] = 0; |
||
1107 | } else { |
||
1108 | unset($parameters['isPublished'], $parameters['publishUp'], $parameters['publishDown']); |
||
1109 | } |
||
1110 | } |
||
1111 | } |
||
1112 | } |
||
1113 | |||
1114 | $form = $this->createEntityForm($entity); |
||
1115 | $submitParams = $this->prepareParametersForBinding($parameters, $entity, $action); |
||
1116 | |||
1117 | if ($submitParams instanceof Response) { |
||
1118 | return $submitParams; |
||
1119 | } |
||
1120 | |||
1121 | // Remove category from the payload because it will cause form validation error. |
||
1122 | if (isset($submitParams['category'])) { |
||
1123 | $categoryId = (int) $submitParams['category']; |
||
1124 | unset($submitParams['category']); |
||
1125 | } |
||
1126 | |||
1127 | $this->prepareParametersFromRequest($form, $submitParams, $entity, $this->dataInputMasks); |
||
1128 | |||
1129 | $form->submit($submitParams, 'PATCH' !== $method); |
||
1130 | |||
1131 | if ($form->isValid()) { |
||
1132 | $this->setCategory($entity, $categoryId); |
||
1133 | $preSaveError = $this->preSaveEntity($entity, $form, $submitParams, $action); |
||
1134 | |||
1135 | if ($preSaveError instanceof Response) { |
||
1136 | return $preSaveError; |
||
1137 | } |
||
1138 | |||
1139 | try { |
||
1140 | if ($this->dispatcher->hasListeners(ApiEvents::API_ON_ENTITY_PRE_SAVE)) { |
||
1141 | $this->dispatcher->dispatch(ApiEvents::API_ON_ENTITY_PRE_SAVE, new ApiEntityEvent($entity, $this->entityRequestParameters, $this->request)); |
||
1142 | } |
||
1143 | } catch (\Exception $e) { |
||
1144 | return $this->returnError($e->getMessage(), $e->getCode()); |
||
1145 | } |
||
1146 | |||
1147 | $this->model->saveEntity($entity); |
||
1148 | $headers = []; |
||
1149 | //return the newly created entities location if applicable |
||
1150 | if (Response::HTTP_CREATED === $statusCode) { |
||
1151 | $route = (null !== $this->get('router')->getRouteCollection()->get('mautic_api_'.$this->entityNameMulti.'_getone')) |
||
1152 | ? 'mautic_api_'.$this->entityNameMulti.'_getone' : 'mautic_api_get'.$this->entityNameOne; |
||
1153 | $headers['Location'] = $this->generateUrl( |
||
1154 | $route, |
||
1155 | array_merge(['id' => $entity->getId()], $this->routeParams), |
||
1156 | true |
||
1157 | ); |
||
1158 | } |
||
1159 | |||
1160 | try { |
||
1161 | if ($this->dispatcher->hasListeners(ApiEvents::API_ON_ENTITY_POST_SAVE)) { |
||
1162 | $this->dispatcher->dispatch(ApiEvents::API_ON_ENTITY_POST_SAVE, new ApiEntityEvent($entity, $this->entityRequestParameters, $this->request)); |
||
1163 | } |
||
1164 | } catch (\Exception $e) { |
||
1165 | return $this->returnError($e->getMessage(), $e->getCode()); |
||
1166 | } |
||
1167 | |||
1168 | $this->preSerializeEntity($entity, $action); |
||
1169 | |||
1170 | if ($this->inBatchMode) { |
||
1171 | return $entity; |
||
1172 | } else { |
||
1173 | $view = $this->view([$this->entityNameOne => $entity], $statusCode, $headers); |
||
1174 | } |
||
1175 | |||
1176 | $this->setSerializationContext($view); |
||
1177 | } else { |
||
1178 | $formErrors = $this->getFormErrorMessages($form); |
||
1179 | $msg = $this->getFormErrorMessage($formErrors); |
||
1180 | |||
1181 | if (!$msg) { |
||
1182 | $msg = $this->translator->trans('mautic.core.error.badrequest', [], 'flashes'); |
||
1183 | } |
||
1184 | |||
1185 | return $this->returnError($msg, Response::HTTP_BAD_REQUEST, $formErrors); |
||
1186 | } |
||
1187 | |||
1188 | return $this->handleView($view); |
||
1189 | } |
||
1190 | |||
1191 | /** |
||
1192 | * Returns an error. |
||
1193 | * |
||
1194 | * @param string $msg |
||
1195 | * @param int $code |
||
1196 | * @param array $details |
||
1197 | * |
||
1198 | * @return Response|array |
||
1199 | */ |
||
1200 | protected function returnError($msg, $code = Response::HTTP_INTERNAL_SERVER_ERROR, $details = []) |
||
1201 | { |
||
1202 | if ($this->get('translator')->hasId($msg, 'flashes')) { |
||
1203 | $msg = $this->get('translator')->trans($msg, [], 'flashes'); |
||
1204 | } elseif ($this->get('translator')->hasId($msg, 'messages')) { |
||
1205 | $msg = $this->get('translator')->trans($msg, [], 'messages'); |
||
1206 | } |
||
1207 | |||
1208 | $error = [ |
||
1209 | 'code' => $code, |
||
1210 | 'message' => $msg, |
||
1211 | 'details' => $details, |
||
1212 | 'type' => null, |
||
1213 | ]; |
||
1214 | |||
1215 | if ($this->inBatchMode) { |
||
1216 | return $error; |
||
1217 | } |
||
1218 | |||
1219 | $view = $this->view( |
||
1220 | [ |
||
1221 | 'errors' => [ |
||
1222 | $error, |
||
1223 | ], |
||
1224 | ], |
||
1225 | $code |
||
1226 | ); |
||
1227 | |||
1228 | return $this->handleView($view); |
||
1229 | } |
||
1230 | |||
1231 | /** |
||
1232 | * @param $where |
||
1233 | */ |
||
1234 | protected function sanitizeWhereClauseArrayFromRequest(&$where) |
||
1235 | { |
||
1236 | foreach ($where as $key => $statement) { |
||
1237 | if (isset($statement['internal'])) { |
||
1238 | unset($where[$key]); |
||
1239 | } elseif (in_array($statement['expr'], ['andX', 'orX'])) { |
||
1240 | $this->sanitizeWhereClauseArrayFromRequest($statement['val']); |
||
1241 | } |
||
1242 | } |
||
1243 | } |
||
1244 | |||
1245 | /** |
||
1246 | * @param object $entity |
||
1247 | * @param int $categoryId |
||
1248 | * |
||
1249 | * @throws \UnexpectedValueException |
||
1250 | */ |
||
1251 | protected function setCategory($entity, $categoryId) |
||
1252 | { |
||
1253 | if (!empty($categoryId) && method_exists($entity, 'setCategory')) { |
||
1254 | $category = $this->getDoctrine()->getManager()->find(Category::class, $categoryId); |
||
1255 | |||
1256 | if (null === $category) { |
||
1257 | throw new \UnexpectedValueException("Category $categoryId does not exist"); |
||
1258 | } |
||
1259 | |||
1260 | $entity->setCategory($category); |
||
1261 | } |
||
1262 | } |
||
1263 | |||
1264 | /** |
||
1265 | * @param $key |
||
1266 | * @param $msg |
||
1267 | * @param $code |
||
1268 | * @param $errors |
||
1269 | * @param array $entities |
||
1270 | * @param null $entity |
||
1271 | */ |
||
1272 | protected function setBatchError($key, $msg, $code, &$errors, &$entities = [], $entity = null) |
||
1273 | { |
||
1274 | unset($entities[$key]); |
||
1275 | if ($entity) { |
||
1276 | $this->getDoctrine()->getManager()->detach($entity); |
||
1277 | } |
||
1278 | |||
1279 | $errors[$key] = [ |
||
1280 | 'message' => $this->get('translator')->hasId($msg, 'flashes') ? $this->get('translator')->trans($msg, [], 'flashes') : $msg, |
||
1281 | 'code' => $code, |
||
1282 | 'type' => 'api', |
||
1283 | ]; |
||
1284 | } |
||
1285 | |||
1286 | /** |
||
1287 | * Set serialization groups and exclusion strategies. |
||
1288 | * |
||
1289 | * @param View $view |
||
1290 | */ |
||
1291 | protected function setSerializationContext($view) |
||
1292 | { |
||
1293 | $context = $view->getContext(); |
||
1294 | if (!empty($this->serializerGroups)) { |
||
1295 | $context->setGroups($this->serializerGroups); |
||
1296 | } |
||
1297 | |||
1298 | // Only include FormEntity properties for the top level entity and not the associated entities |
||
1299 | $context->addExclusionStrategy( |
||
1300 | new PublishDetailsExclusionStrategy() |
||
1301 | ); |
||
1302 | |||
1303 | // Only include first level of children/parents |
||
1304 | if ($this->parentChildrenLevelDepth) { |
||
1305 | $context->addExclusionStrategy( |
||
1306 | new ParentChildrenExclusionStrategy($this->parentChildrenLevelDepth) |
||
1307 | ); |
||
1308 | } |
||
1309 | |||
1310 | // Add custom exclusion strategies |
||
1311 | foreach ($this->exclusionStrategies as $strategy) { |
||
1312 | $context->addExclusionStrategy($strategy); |
||
1313 | } |
||
1314 | |||
1315 | // Include null values if a custom select has not been given |
||
1316 | if (!$this->customSelectRequested) { |
||
1317 | $context->setSerializeNull(true); |
||
1318 | } |
||
1319 | |||
1320 | $view->setContext($context); |
||
1321 | } |
||
1322 | |||
1323 | /** |
||
1324 | * @param $parameters |
||
1325 | * |
||
1326 | * @return array|bool|Response |
||
1327 | */ |
||
1328 | protected function validateBatchPayload($parameters) |
||
1329 | { |
||
1330 | $batchLimit = (int) $this->get('mautic.config')->getParameter('api_batch_max_limit', 200); |
||
1331 | if (count($parameters) > $batchLimit) { |
||
1332 | return $this->returnError($this->get('translator')->trans('mautic.api.call.batch_exception', ['%limit%' => $batchLimit])); |
||
1333 | } |
||
1334 | |||
1335 | return true; |
||
1336 | } |
||
1337 | |||
1338 | /** |
||
1339 | * {@inheritdoc} |
||
1340 | * |
||
1341 | * @param null $data |
||
1342 | * @param null $statusCode |
||
1343 | */ |
||
1344 | protected function view($data = null, $statusCode = null, array $headers = []) |
||
1345 | { |
||
1346 | if ($data instanceof Paginator) { |
||
1347 | // Get iterator out of Paginator class so that the entities are properly serialized by the serializer |
||
1348 | $data = $data->getIterator()->getArrayCopy(); |
||
1349 | } |
||
1350 | |||
1351 | $headers['Mautic-Version'] = $this->get('kernel')->getVersion(); |
||
1352 | |||
1353 | return parent::view($data, $statusCode, $headers); |
||
1354 | } |
||
1355 | } |
||
1356 |
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.