Completed
Pull Request — master (#4714)
by Grégoire
03:52
created

CRUDController::editAction()   D

Complexity

Conditions 13
Paths 49

Size

Total Lines 102
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 102
rs 4.9922
c 0
b 0
f 0
cc 13
eloc 65
nc 49
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Sonata Project package.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sonata\AdminBundle\Controller;
13
14
use Doctrine\Common\Inflector\Inflector;
15
use Psr\Log\LoggerInterface;
16
use Psr\Log\NullLogger;
17
use Sonata\AdminBundle\Admin\AdminInterface;
18
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
19
use Sonata\AdminBundle\Exception\LockException;
20
use Sonata\AdminBundle\Exception\ModelManagerException;
21
use Sonata\AdminBundle\Util\AdminObjectAclData;
22
use Sonata\AdminBundle\Util\AdminObjectAclManipulator;
23
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
24
use Symfony\Component\DependencyInjection\ContainerInterface;
25
use Symfony\Component\Form\FormView;
26
use Symfony\Component\HttpFoundation\JsonResponse;
27
use Symfony\Component\HttpFoundation\RedirectResponse;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\HttpFoundation\Response;
30
use Symfony\Component\HttpKernel\Exception\HttpException;
31
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
32
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
33
use Symfony\Component\Security\Csrf\CsrfToken;
34
35
/**
36
 * @author Thomas Rabaix <[email protected]>
37
 */
38
class CRUDController extends Controller
39
{
40
    /**
41
     * The related Admin class.
42
     *
43
     * @var AdminInterface
44
     */
45
    protected $admin;
46
47
    /**
48
     * Sets the Container associated with this Controller.
49
     *
50
     * @param ContainerInterface $container A ContainerInterface instance
51
     */
52
    public function setContainer(ContainerInterface $container = null)
53
    {
54
        $this->container = $container;
55
56
        $this->configure();
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function render($view, array $parameters = [], Response $response = null)
63
    {
64
        if (!$this->isXmlHttpRequest()) {
65
            $parameters['breadcrumbs_builder'] = $this->get('sonata.admin.breadcrumbs_builder');
66
        }
67
        $parameters['admin'] = isset($parameters['admin']) ?
68
            $parameters['admin'] :
69
            $this->admin;
70
71
        $parameters['base_template'] = isset($parameters['base_template']) ?
72
            $parameters['base_template'] :
73
            $this->getBaseTemplate();
74
75
        $parameters['admin_pool'] = $this->get('sonata.admin.pool');
76
77
        return parent::render($view, $parameters, $response);
78
    }
79
80
    /**
81
     * List action.
82
     *
83
     * @return Response
84
     *
85
     * @throws AccessDeniedException If access is not granted
86
     */
87
    public function listAction()
88
    {
89
        $request = $this->getRequest();
90
91
        $this->admin->checkAccess('list');
92
93
        $preResponse = $this->preList($request);
94
        if ($preResponse !== null) {
95
            return $preResponse;
96
        }
97
98
        if ($listMode = $request->get('_list_mode')) {
99
            $this->admin->setListMode($listMode);
100
        }
101
102
        $datagrid = $this->admin->getDatagrid();
103
        $formView = $datagrid->getForm()->createView();
104
105
        // set the theme for the current Admin Form
106
        $this->setFormTheme($formView, $this->admin->getFilterTheme());
0 ignored issues
show
Documentation introduced by
$this->admin->getFilterTheme() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107
108
        return $this->render($this->admin->getTemplate('list'), [
109
            'action' => 'list',
110
            'form' => $formView,
111
            'datagrid' => $datagrid,
112
            'csrf_token' => $this->getCsrfToken('sonata.batch'),
113
            'export_formats' => $this->has('sonata.admin.admin_exporter') ?
114
                $this->get('sonata.admin.admin_exporter')->getAvailableFormats($this->admin) :
115
                $this->admin->getExportFormats(),
116
        ], null);
117
    }
118
119
    /**
120
     * Execute a batch delete.
121
     *
122
     * @param ProxyQueryInterface $query
123
     *
124
     * @return RedirectResponse
125
     *
126
     * @throws AccessDeniedException If access is not granted
127
     */
128
    public function batchActionDelete(ProxyQueryInterface $query)
129
    {
130
        $this->admin->checkAccess('batchDelete');
131
132
        $modelManager = $this->admin->getModelManager();
133
134
        try {
135
            $modelManager->batchDelete($this->admin->getClass(), $query);
136
            $this->addFlash(
137
                'sonata_flash_success',
138
                $this->trans('flash_batch_delete_success', [], 'SonataAdminBundle')
139
            );
140
        } catch (ModelManagerException $e) {
141
            $this->handleModelManagerException($e);
142
            $this->addFlash(
143
                'sonata_flash_error',
144
                $this->trans('flash_batch_delete_error', [], 'SonataAdminBundle')
145
            );
146
        }
147
148
        return new RedirectResponse($this->admin->generateUrl(
149
            'list',
150
            ['filter' => $this->admin->getFilterParameters()]
151
        ));
152
    }
153
154
    /**
155
     * Delete action.
156
     *
157
     * @param int|string|null $id
158
     *
159
     * @return Response|RedirectResponse
160
     *
161
     * @throws NotFoundHttpException If the object does not exist
162
     * @throws AccessDeniedException If access is not granted
163
     */
164
    public function deleteAction($id)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
    {
166
        $request = $this->getRequest();
167
        $id = $request->get($this->admin->getIdParameter());
168
        $object = $this->admin->getObject($id);
169
170
        if (!$object) {
171
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
172
        }
173
174
        $this->admin->checkAccess('delete', $object);
175
176
        $preResponse = $this->preDelete($request, $object);
177
        if ($preResponse !== null) {
178
            return $preResponse;
179
        }
180
181
        if ($this->getRestMethod() == 'DELETE') {
182
            // check the csrf token
183
            $this->validateCsrfToken('sonata.delete');
184
185
            $objectName = $this->admin->toString($object);
186
187
            try {
188
                $this->admin->delete($object);
189
190
                if ($this->isXmlHttpRequest()) {
191
                    return $this->renderJson(['result' => 'ok'], 200, []);
192
                }
193
194
                $this->addFlash(
195
                    'sonata_flash_success',
196
                    $this->trans(
197
                        'flash_delete_success',
198
                        ['%name%' => $this->escapeHtml($objectName)],
199
                        'SonataAdminBundle'
200
                    )
201
                );
202
            } catch (ModelManagerException $e) {
203
                $this->handleModelManagerException($e);
204
205
                if ($this->isXmlHttpRequest()) {
206
                    return $this->renderJson(['result' => 'error'], 200, []);
207
                }
208
209
                $this->addFlash(
210
                    'sonata_flash_error',
211
                    $this->trans(
212
                        'flash_delete_error',
213
                        ['%name%' => $this->escapeHtml($objectName)],
214
                        'SonataAdminBundle'
215
                    )
216
                );
217
            }
218
219
            return $this->redirectTo($object);
220
        }
221
222
        return $this->render($this->admin->getTemplate('delete'), [
223
            'object' => $object,
224
            'action' => 'delete',
225
            'csrf_token' => $this->getCsrfToken('sonata.delete'),
226
        ], null);
227
    }
228
229
    /**
230
     * Edit action.
231
     *
232
     * @param int|string|null $id
233
     *
234
     * @return Response|RedirectResponse
235
     *
236
     * @throws NotFoundHttpException If the object does not exist
237
     * @throws AccessDeniedException If access is not granted
238
     */
239
    public function editAction($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
        $request = $this->getRequest();
242
        // the key used to lookup the template
243
        $templateKey = 'edit';
244
245
        $id = $request->get($this->admin->getIdParameter());
246
        $existingObject = $this->admin->getObject($id);
247
248
        if (!$existingObject) {
249
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
250
        }
251
252
        $this->admin->checkAccess('edit', $existingObject);
253
254
        $preResponse = $this->preEdit($request, $existingObject);
255
        if ($preResponse !== null) {
256
            return $preResponse;
257
        }
258
259
        $this->admin->setSubject($existingObject);
260
        $objectId = $this->admin->getNormalizedIdentifier($existingObject);
261
262
        /** @var $form Form */
263
        $form = $this->admin->getForm();
264
        $form->setData($existingObject);
265
        $form->handleRequest($request);
266
267
        if ($form->isSubmitted()) {
268
            $this->admin->preValidate($existingObject);
269
            $isFormValid = $form->isValid();
270
271
            // persist if the form was valid and if in preview mode the preview was approved
272
            if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) {
273
                $submittedObject = $form->getData();
274
                $this->admin->setSubject($submittedObject);
275
276
                try {
277
                    $existingObject = $this->admin->update($submittedObject);
278
279
                    if ($this->isXmlHttpRequest()) {
280
                        return $this->renderJson([
281
                            'result' => 'ok',
282
                            'objectId' => $objectId,
283
                            'objectName' => $this->escapeHtml($this->admin->toString($existingObject)),
284
                        ], 200, []);
285
                    }
286
287
                    $this->addFlash(
288
                        'sonata_flash_success',
289
                        $this->trans(
290
                            'flash_edit_success',
291
                            ['%name%' => $this->escapeHtml($this->admin->toString($existingObject))],
292
                            'SonataAdminBundle'
293
                        )
294
                    );
295
296
                    // redirect to edit mode
297
                    return $this->redirectTo($existingObject);
298
                } catch (ModelManagerException $e) {
299
                    $this->handleModelManagerException($e);
300
301
                    $isFormValid = false;
302
                } catch (LockException $e) {
303
                    $this->addFlash('sonata_flash_error', $this->trans('flash_lock_error', [
304
                        '%name%' => $this->escapeHtml($this->admin->toString($existingObject)),
305
                        '%link_start%' => '<a href="'.$this->admin->generateObjectUrl('edit', $existingObject).'">',
306
                        '%link_end%' => '</a>',
307
                    ], 'SonataAdminBundle'));
308
                }
309
            }
310
311
            // show an error message if the form failed validation
312
            if (!$isFormValid) {
313
                if (!$this->isXmlHttpRequest()) {
314
                    $this->addFlash(
315
                        'sonata_flash_error',
316
                        $this->trans(
317
                            'flash_edit_error',
318
                            ['%name%' => $this->escapeHtml($this->admin->toString($existingObject))],
319
                            'SonataAdminBundle'
320
                        )
321
                    );
322
                }
323
            } elseif ($this->isPreviewRequested()) {
324
                // enable the preview template if the form was valid and preview was requested
325
                $templateKey = 'preview';
326
                $this->admin->getShow();
327
            }
328
        }
329
330
        $formView = $form->createView();
331
        // set the theme for the current Admin Form
332
        $this->setFormTheme($formView, $this->admin->getFormTheme());
0 ignored issues
show
Documentation introduced by
$this->admin->getFormTheme() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
333
334
        return $this->render($this->admin->getTemplate($templateKey), [
335
            'action' => 'edit',
336
            'form' => $formView,
337
            'object' => $existingObject,
338
            'objectId' => $objectId,
339
        ], null);
340
    }
341
342
    /**
343
     * Batch action.
344
     *
345
     * @return Response|RedirectResponse
346
     *
347
     * @throws NotFoundHttpException If the HTTP method is not POST
348
     * @throws \RuntimeException     If the batch action is not defined
349
     */
350
    public function batchAction()
351
    {
352
        $request = $this->getRequest();
353
        $restMethod = $this->getRestMethod();
354
355
        if ('POST' !== $restMethod) {
356
            throw $this->createNotFoundException(sprintf('Invalid request type "%s", POST expected', $restMethod));
357
        }
358
359
        // check the csrf token
360
        $this->validateCsrfToken('sonata.batch');
361
362
        $confirmation = $request->get('confirmation', false);
363
364
        if ($data = json_decode($request->get('data'), true)) {
365
            $action = $data['action'];
366
            $idx = $data['idx'];
367
            $allElements = $data['all_elements'];
368
            $request->request->replace(array_merge($request->request->all(), $data));
369
        } else {
370
            $request->request->set('idx', $request->get('idx', []));
371
            $request->request->set('all_elements', $request->get('all_elements', false));
372
373
            $action = $request->get('action');
374
            $idx = $request->get('idx');
375
            $allElements = $request->get('all_elements');
376
            $data = $request->request->all();
377
378
            unset($data['_sonata_csrf_token']);
379
        }
380
381
        $batchActions = $this->admin->getBatchActions();
382
        if (!array_key_exists($action, $batchActions)) {
383
            throw new \RuntimeException(sprintf('The `%s` batch action is not defined', $action));
384
        }
385
386
        $camelizedAction = Inflector::classify($action);
387
        $isRelevantAction = sprintf('batchAction%sIsRelevant', ucfirst($camelizedAction));
388
389
        if (method_exists($this, $isRelevantAction)) {
390
            $nonRelevantMessage = call_user_func([$this, $isRelevantAction], $idx, $allElements, $request);
391
        } else {
392
            $nonRelevantMessage = count($idx) != 0 || $allElements; // at least one item is selected
393
        }
394
395
        if (!$nonRelevantMessage) { // default non relevant message (if false of null)
396
            $nonRelevantMessage = 'flash_batch_empty';
397
        }
398
399
        $datagrid = $this->admin->getDatagrid();
400
        $datagrid->buildPager();
401
402
        if (true !== $nonRelevantMessage) {
403
            $this->addFlash(
404
                'sonata_flash_info',
405
                $this->trans($nonRelevantMessage, [], 'SonataAdminBundle')
406
            );
407
408
            return new RedirectResponse(
409
                $this->admin->generateUrl(
410
                    'list',
411
                    ['filter' => $this->admin->getFilterParameters()]
412
                )
413
            );
414
        }
415
416
        $askConfirmation = isset($batchActions[$action]['ask_confirmation']) ?
417
            $batchActions[$action]['ask_confirmation'] :
418
            true;
419
420
        if ($askConfirmation && $confirmation != 'ok') {
421
            $actionLabel = $batchActions[$action]['label'];
422
            $batchTranslationDomain = isset($batchActions[$action]['translation_domain']) ?
423
                $batchActions[$action]['translation_domain'] :
424
                $this->admin->getTranslationDomain();
425
426
            $formView = $datagrid->getForm()->createView();
427
            $this->setFormTheme($formView, $this->admin->getFilterTheme());
0 ignored issues
show
Documentation introduced by
$this->admin->getFilterTheme() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
428
429
            return $this->render($this->admin->getTemplate('batch_confirmation'), [
430
                'action' => 'list',
431
                'action_label' => $actionLabel,
432
                'batch_translation_domain' => $batchTranslationDomain,
433
                'datagrid' => $datagrid,
434
                'form' => $formView,
435
                'data' => $data,
436
                'csrf_token' => $this->getCsrfToken('sonata.batch'),
437
            ], null);
438
        }
439
440
        // execute the action, batchActionXxxxx
441
        $finalAction = sprintf('batchAction%s', $camelizedAction);
442
        if (!is_callable([$this, $finalAction])) {
443
            throw new \RuntimeException(sprintf('A `%s::%s` method must be callable', get_class($this), $finalAction));
444
        }
445
446
        $query = $datagrid->getQuery();
447
448
        $query->setFirstResult(null);
449
        $query->setMaxResults(null);
450
451
        $this->admin->preBatchAction($action, $query, $idx, $allElements);
452
453
        if (count($idx) > 0) {
454
            $this->admin->getModelManager()->addIdentifiersToQuery($this->admin->getClass(), $query, $idx);
455
        } elseif (!$allElements) {
456
            $query = null;
457
        }
458
459
        return call_user_func([$this, $finalAction], $query, $request);
460
    }
461
462
    /**
463
     * Create action.
464
     *
465
     * @return Response
466
     *
467
     * @throws AccessDeniedException If access is not granted
468
     */
469
    public function createAction()
470
    {
471
        $request = $this->getRequest();
472
        // the key used to lookup the template
473
        $templateKey = 'edit';
474
475
        $this->admin->checkAccess('create');
476
477
        $class = new \ReflectionClass($this->admin->hasActiveSubClass() ? $this->admin->getActiveSubClass() : $this->admin->getClass());
478
479
        if ($class->isAbstract()) {
480
            return $this->render(
481
                'SonataAdminBundle:CRUD:select_subclass.html.twig',
482
                [
483
                    'base_template' => $this->getBaseTemplate(),
484
                    'admin' => $this->admin,
485
                    'action' => 'create',
486
                ],
487
                null,
488
                $request
0 ignored issues
show
Unused Code introduced by
The call to CRUDController::render() has too many arguments starting with $request.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
489
            );
490
        }
491
492
        $newObject = $this->admin->getNewInstance();
493
494
        $preResponse = $this->preCreate($request, $newObject);
495
        if ($preResponse !== null) {
496
            return $preResponse;
497
        }
498
499
        $this->admin->setSubject($newObject);
500
501
        /** @var $form \Symfony\Component\Form\Form */
502
        $form = $this->admin->getForm();
503
        $form->setData($newObject);
504
        $form->handleRequest($request);
505
506
        if ($form->isSubmitted()) {
507
            $this->admin->preValidate($newObject);
508
            $isFormValid = $form->isValid();
509
510
            // persist if the form was valid and if in preview mode the preview was approved
511
            if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) {
512
                $submittedObject = $form->getData();
513
                $this->admin->setSubject($submittedObject);
514
                $this->admin->checkAccess('create', $submittedObject);
515
516
                try {
517
                    $newObject = $this->admin->create($submittedObject);
518
519
                    if ($this->isXmlHttpRequest()) {
520
                        return $this->renderJson([
521
                            'result' => 'ok',
522
                            'objectId' => $this->admin->getNormalizedIdentifier($newObject),
523
                        ], 200, []);
524
                    }
525
526
                    $this->addFlash(
527
                        'sonata_flash_success',
528
                        $this->trans(
529
                            'flash_create_success',
530
                            ['%name%' => $this->escapeHtml($this->admin->toString($newObject))],
531
                            'SonataAdminBundle'
532
                        )
533
                    );
534
535
                    // redirect to edit mode
536
                    return $this->redirectTo($newObject);
537
                } catch (ModelManagerException $e) {
538
                    $this->handleModelManagerException($e);
539
540
                    $isFormValid = false;
541
                }
542
            }
543
544
            // show an error message if the form failed validation
545
            if (!$isFormValid) {
546
                if (!$this->isXmlHttpRequest()) {
547
                    $this->addFlash(
548
                        'sonata_flash_error',
549
                        $this->trans(
550
                            'flash_create_error',
551
                            ['%name%' => $this->escapeHtml($this->admin->toString($newObject))],
552
                            'SonataAdminBundle'
553
                        )
554
                    );
555
                }
556
            } elseif ($this->isPreviewRequested()) {
557
                // pick the preview template if the form was valid and preview was requested
558
                $templateKey = 'preview';
559
                $this->admin->getShow();
560
            }
561
        }
562
563
        $formView = $form->createView();
564
        // set the theme for the current Admin Form
565
        $this->setFormTheme($formView, $this->admin->getFormTheme());
0 ignored issues
show
Documentation introduced by
$this->admin->getFormTheme() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
566
567
        return $this->render($this->admin->getTemplate($templateKey), [
568
            'action' => 'create',
569
            'form' => $formView,
570
            'object' => $newObject,
571
            'objectId' => null,
572
        ], null);
573
    }
574
575
    /**
576
     * Show action.
577
     *
578
     * @param int|string|null $id
579
     *
580
     * @return Response
581
     *
582
     * @throws NotFoundHttpException If the object does not exist
583
     * @throws AccessDeniedException If access is not granted
584
     */
585
    public function showAction($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
586
    {
587
        $request = $this->getRequest();
588
        $id = $request->get($this->admin->getIdParameter());
589
590
        $object = $this->admin->getObject($id);
591
592
        if (!$object) {
593
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
594
        }
595
596
        $this->admin->checkAccess('show', $object);
597
598
        $preResponse = $this->preShow($request, $object);
599
        if ($preResponse !== null) {
600
            return $preResponse;
601
        }
602
603
        $this->admin->setSubject($object);
604
605
        return $this->render($this->admin->getTemplate('show'), [
606
            'action' => 'show',
607
            'object' => $object,
608
            'elements' => $this->admin->getShow(),
609
        ], null);
610
    }
611
612
    /**
613
     * Show history revisions for object.
614
     *
615
     * @param int|string|null $id
616
     *
617
     * @return Response
618
     *
619
     * @throws AccessDeniedException If access is not granted
620
     * @throws NotFoundHttpException If the object does not exist or the audit reader is not available
621
     */
622
    public function historyAction($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
623
    {
624
        $request = $this->getRequest();
625
        $id = $request->get($this->admin->getIdParameter());
626
627
        $object = $this->admin->getObject($id);
628
629
        if (!$object) {
630
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
631
        }
632
633
        $this->admin->checkAccess('history', $object);
634
635
        $manager = $this->get('sonata.admin.audit.manager');
636
637
        if (!$manager->hasReader($this->admin->getClass())) {
638
            throw $this->createNotFoundException(
639
                sprintf(
640
                    'unable to find the audit reader for class : %s',
641
                    $this->admin->getClass()
642
                )
643
            );
644
        }
645
646
        $reader = $manager->getReader($this->admin->getClass());
647
648
        $revisions = $reader->findRevisions($this->admin->getClass(), $id);
649
650
        return $this->render($this->admin->getTemplate('history'), [
651
            'action' => 'history',
652
            'object' => $object,
653
            'revisions' => $revisions,
654
            'currentRevision' => $revisions ? current($revisions) : false,
655
        ], null);
656
    }
657
658
    /**
659
     * View history revision of object.
660
     *
661
     * @param int|string|null $id
662
     * @param string|null     $revision
663
     *
664
     * @return Response
665
     *
666
     * @throws AccessDeniedException If access is not granted
667
     * @throws NotFoundHttpException If the object or revision does not exist or the audit reader is not available
668
     */
669
    public function historyViewRevisionAction($id = null, $revision = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
670
    {
671
        $request = $this->getRequest();
672
        $id = $request->get($this->admin->getIdParameter());
673
674
        $object = $this->admin->getObject($id);
675
676
        if (!$object) {
677
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
678
        }
679
680
        $this->admin->checkAccess('historyViewRevision', $object);
681
682
        $manager = $this->get('sonata.admin.audit.manager');
683
684
        if (!$manager->hasReader($this->admin->getClass())) {
685
            throw $this->createNotFoundException(
686
                sprintf(
687
                    'unable to find the audit reader for class : %s',
688
                    $this->admin->getClass()
689
                )
690
            );
691
        }
692
693
        $reader = $manager->getReader($this->admin->getClass());
694
695
        // retrieve the revisioned object
696
        $object = $reader->find($this->admin->getClass(), $id, $revision);
697
698
        if (!$object) {
699
            throw $this->createNotFoundException(
700
                sprintf(
701
                    'unable to find the targeted object `%s` from the revision `%s` with classname : `%s`',
702
                    $id,
703
                    $revision,
704
                    $this->admin->getClass()
705
                )
706
            );
707
        }
708
709
        $this->admin->setSubject($object);
710
711
        return $this->render($this->admin->getTemplate('show'), [
712
            'action' => 'show',
713
            'object' => $object,
714
            'elements' => $this->admin->getShow(),
715
        ], null);
716
    }
717
718
    /**
719
     * Compare history revisions of object.
720
     *
721
     * @param int|string|null $id
722
     * @param int|string|null $base_revision
723
     * @param int|string|null $compare_revision
724
     *
725
     * @return Response
726
     *
727
     * @throws AccessDeniedException If access is not granted
728
     * @throws NotFoundHttpException If the object or revision does not exist or the audit reader is not available
729
     */
730
    public function historyCompareRevisionsAction($id = null, $base_revision = null, $compare_revision = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
731
    {
732
        $request = $this->getRequest();
733
734
        $this->admin->checkAccess('historyCompareRevisions');
735
736
        $id = $request->get($this->admin->getIdParameter());
737
738
        $object = $this->admin->getObject($id);
739
740
        if (!$object) {
741
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
742
        }
743
744
        $manager = $this->get('sonata.admin.audit.manager');
745
746
        if (!$manager->hasReader($this->admin->getClass())) {
747
            throw $this->createNotFoundException(
748
                sprintf(
749
                    'unable to find the audit reader for class : %s',
750
                    $this->admin->getClass()
751
                )
752
            );
753
        }
754
755
        $reader = $manager->getReader($this->admin->getClass());
756
757
        // retrieve the base revision
758
        $base_object = $reader->find($this->admin->getClass(), $id, $base_revision);
759
        if (!$base_object) {
760
            throw $this->createNotFoundException(
761
                sprintf(
762
                    'unable to find the targeted object `%s` from the revision `%s` with classname : `%s`',
763
                    $id,
764
                    $base_revision,
765
                    $this->admin->getClass()
766
                )
767
            );
768
        }
769
770
        // retrieve the compare revision
771
        $compare_object = $reader->find($this->admin->getClass(), $id, $compare_revision);
772
        if (!$compare_object) {
773
            throw $this->createNotFoundException(
774
                sprintf(
775
                    'unable to find the targeted object `%s` from the revision `%s` with classname : `%s`',
776
                    $id,
777
                    $compare_revision,
778
                    $this->admin->getClass()
779
                )
780
            );
781
        }
782
783
        $this->admin->setSubject($base_object);
784
785
        return $this->render($this->admin->getTemplate('show_compare'), [
786
            'action' => 'show',
787
            'object' => $base_object,
788
            'object_compare' => $compare_object,
789
            'elements' => $this->admin->getShow(),
790
        ], null);
791
    }
792
793
    /**
794
     * Export data to specified format.
795
     *
796
     * @param Request $request
797
     *
798
     * @return Response
799
     *
800
     * @throws AccessDeniedException If access is not granted
801
     * @throws \RuntimeException     If the export format is invalid
802
     */
803
    public function exportAction(Request $request)
804
    {
805
        $this->admin->checkAccess('export');
806
807
        $format = $request->get('format');
808
809
        // NEXT_MAJOR: remove the check
810
        if (!$this->has('sonata.admin.admin_exporter')) {
811
            @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
812
                'Not registering the exporter bundle is deprecated since version 3.14.'
813
                .' You must register it to be able to use the export action in 4.0.',
814
                E_USER_DEPRECATED
815
            );
816
            $allowedExportFormats = (array) $this->admin->getExportFormats();
817
818
            $class = $this->admin->getClass();
819
            $filename = sprintf(
820
                'export_%s_%s.%s',
821
                strtolower(substr($class, strripos($class, '\\') + 1)),
822
                date('Y_m_d_H_i_s', strtotime('now')),
823
                $format
824
            );
825
            $exporter = $this->get('sonata.admin.exporter');
826
        } else {
827
            $adminExporter = $this->get('sonata.admin.admin_exporter');
828
            $allowedExportFormats = $adminExporter->getAvailableFormats($this->admin);
829
            $filename = $adminExporter->getExportFilename($this->admin, $format);
830
            $exporter = $this->get('sonata.exporter.exporter');
831
        }
832
833
        if (!in_array($format, $allowedExportFormats)) {
834
            throw new \RuntimeException(
835
                sprintf(
836
                    'Export in format `%s` is not allowed for class: `%s`. Allowed formats are: `%s`',
837
                    $format,
838
                    $this->admin->getClass(),
839
                    implode(', ', $allowedExportFormats)
840
                )
841
            );
842
        }
843
844
        return $exporter->getResponse(
845
            $format,
846
            $filename,
847
            $this->admin->getDataSourceIterator()
848
        );
849
    }
850
851
    /**
852
     * Returns the Response object associated to the acl action.
853
     *
854
     * @param int|string|null $id
855
     *
856
     * @return Response|RedirectResponse
857
     *
858
     * @throws AccessDeniedException If access is not granted
859
     * @throws NotFoundHttpException If the object does not exist or the ACL is not enabled
860
     */
861
    public function aclAction($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
862
    {
863
        $request = $this->getRequest();
864
865
        if (!$this->admin->isAclEnabled()) {
866
            throw $this->createNotFoundException('ACL are not enabled for this admin');
867
        }
868
869
        $id = $request->get($this->admin->getIdParameter());
870
871
        $object = $this->admin->getObject($id);
872
873
        if (!$object) {
874
            throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
875
        }
876
877
        $this->admin->checkAccess('acl', $object);
878
879
        $this->admin->setSubject($object);
880
        $aclUsers = $this->getAclUsers();
881
        $aclRoles = $this->getAclRoles();
882
883
        $adminObjectAclManipulator = $this->get('sonata.admin.object.manipulator.acl.admin');
884
        $adminObjectAclData = new AdminObjectAclData(
885
            $this->admin,
886
            $object,
887
            $aclUsers,
888
            $adminObjectAclManipulator->getMaskBuilderClass(),
889
            $aclRoles
890
        );
891
892
        $aclUsersForm = $adminObjectAclManipulator->createAclUsersForm($adminObjectAclData);
893
        $aclRolesForm = $adminObjectAclManipulator->createAclRolesForm($adminObjectAclData);
894
895
        if ($request->getMethod() === 'POST') {
896
            if ($request->request->has(AdminObjectAclManipulator::ACL_USERS_FORM_NAME)) {
897
                $form = $aclUsersForm;
898
                $updateMethod = 'updateAclUsers';
899
            } elseif ($request->request->has(AdminObjectAclManipulator::ACL_ROLES_FORM_NAME)) {
900
                $form = $aclRolesForm;
901
                $updateMethod = 'updateAclRoles';
902
            }
903
904
            if (isset($form)) {
905
                $form->handleRequest($request);
906
907
                if ($form->isValid()) {
908
                    $adminObjectAclManipulator->$updateMethod($adminObjectAclData);
0 ignored issues
show
Bug introduced by
The variable $updateMethod does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
909
                    $this->addFlash(
910
                        'sonata_flash_success',
911
                        $this->trans('flash_acl_edit_success', [], 'SonataAdminBundle')
912
                    );
913
914
                    return new RedirectResponse($this->admin->generateObjectUrl('acl', $object));
915
                }
916
            }
917
        }
918
919
        return $this->render($this->admin->getTemplate('acl'), [
920
            'action' => 'acl',
921
            'permissions' => $adminObjectAclData->getUserPermissions(),
922
            'object' => $object,
923
            'users' => $aclUsers,
924
            'roles' => $aclRoles,
925
            'aclUsersForm' => $aclUsersForm->createView(),
926
            'aclRolesForm' => $aclRolesForm->createView(),
927
        ], null);
928
    }
929
930
    /**
931
     * @return Request
932
     */
933
    public function getRequest()
934
    {
935
        if ($this->container->has('request_stack')) {
936
            return $this->container->get('request_stack')->getCurrentRequest();
937
        }
938
939
        return $this->container->get('request');
940
    }
941
942
    /**
943
     * Render JSON.
944
     *
945
     * @param mixed $data
946
     * @param int   $status
947
     * @param array $headers
948
     *
949
     * @return Response with json encoded data
950
     */
951
    protected function renderJson($data, $status = 200, $headers = [])
952
    {
953
        return new JsonResponse($data, $status, $headers);
954
    }
955
956
    /**
957
     * Returns true if the request is a XMLHttpRequest.
958
     *
959
     * @return bool True if the request is an XMLHttpRequest, false otherwise
960
     */
961
    protected function isXmlHttpRequest()
962
    {
963
        $request = $this->getRequest();
964
965
        return $request->isXmlHttpRequest() || $request->get('_xml_http_request');
966
    }
967
968
    /**
969
     * Returns the correct RESTful verb, given either by the request itself or
970
     * via the "_method" parameter.
971
     *
972
     * @return string HTTP method, either
973
     */
974
    protected function getRestMethod()
975
    {
976
        $request = $this->getRequest();
977
978
        if (Request::getHttpMethodParameterOverride() || !$request->request->has('_method')) {
979
            return $request->getMethod();
980
        }
981
982
        return $request->request->get('_method');
983
    }
984
985
    /**
986
     * Contextualize the admin class depends on the current request.
987
     *
988
     * @throws \RuntimeException
989
     */
990
    protected function configure()
991
    {
992
        $request = $this->getRequest();
993
994
        $adminCode = $request->get('_sonata_admin');
995
996
        if (!$adminCode) {
997
            throw new \RuntimeException(sprintf(
998
                'There is no `_sonata_admin` defined for the controller `%s` and the current route `%s`',
999
                get_class($this),
1000
                $request->get('_route')
1001
            ));
1002
        }
1003
1004
        $this->admin = $this->container->get('sonata.admin.pool')->getAdminByAdminCode($adminCode);
1005
1006
        if (!$this->admin) {
1007
            throw new \RuntimeException(sprintf(
1008
                'Unable to find the admin class related to the current controller (%s)',
1009
                get_class($this)
1010
            ));
1011
        }
1012
1013
        $rootAdmin = $this->admin;
1014
1015
        while ($rootAdmin->isChild()) {
1016
            $rootAdmin->setCurrentChild(true);
1017
            $rootAdmin = $rootAdmin->getParent();
1018
        }
1019
1020
        $rootAdmin->setRequest($request);
1021
1022
        if ($request->get('uniqid')) {
1023
            $this->admin->setUniqid($request->get('uniqid'));
1024
        }
1025
    }
1026
1027
    /**
1028
     * Proxy for the logger service of the container.
1029
     * If no such service is found, a NullLogger is returned.
1030
     *
1031
     * @return LoggerInterface
1032
     */
1033
    protected function getLogger()
1034
    {
1035
        if ($this->container->has('logger')) {
1036
            return $this->container->get('logger');
1037
        }
1038
1039
        return new NullLogger();
1040
    }
1041
1042
    /**
1043
     * Returns the base template name.
1044
     *
1045
     * @return string The template name
1046
     */
1047
    protected function getBaseTemplate()
1048
    {
1049
        if ($this->isXmlHttpRequest()) {
1050
            return $this->admin->getTemplate('ajax');
1051
        }
1052
1053
        return $this->admin->getTemplate('layout');
1054
    }
1055
1056
    /**
1057
     * @param \Exception $e
1058
     *
1059
     * @throws \Exception
1060
     */
1061
    protected function handleModelManagerException(\Exception $e)
1062
    {
1063
        if ($this->get('kernel')->isDebug()) {
1064
            throw $e;
1065
        }
1066
1067
        $context = ['exception' => $e];
1068
        if ($e->getPrevious()) {
1069
            $context['previous_exception_message'] = $e->getPrevious()->getMessage();
1070
        }
1071
        $this->getLogger()->error($e->getMessage(), $context);
1072
    }
1073
1074
    /**
1075
     * Redirect the user depend on this choice.
1076
     *
1077
     * @param object $object
1078
     *
1079
     * @return RedirectResponse
1080
     */
1081
    protected function redirectTo($object)
1082
    {
1083
        $request = $this->getRequest();
1084
1085
        $url = false;
1086
1087
        if (null !== $request->get('btn_update_and_list')) {
1088
            $url = $this->admin->generateUrl('list');
1089
        }
1090
        if (null !== $request->get('btn_create_and_list')) {
1091
            $url = $this->admin->generateUrl('list');
1092
        }
1093
1094
        if (null !== $request->get('btn_create_and_create')) {
1095
            $params = [];
1096
            if ($this->admin->hasActiveSubClass()) {
1097
                $params['subclass'] = $request->get('subclass');
1098
            }
1099
            $url = $this->admin->generateUrl('create', $params);
1100
        }
1101
1102
        if ($this->getRestMethod() === 'DELETE') {
1103
            $url = $this->admin->generateUrl('list');
1104
        }
1105
1106
        if (!$url) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1107
            foreach (['edit', 'show'] as $route) {
1108
                if ($this->admin->hasRoute($route) && $this->admin->hasAccess($route, $object)) {
1109
                    $url = $this->admin->generateObjectUrl($route, $object);
1110
1111
                    break;
1112
                }
1113
            }
1114
        }
1115
1116
        if (!$url) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1117
            $url = $this->admin->generateUrl('list');
1118
        }
1119
1120
        return new RedirectResponse($url);
1121
    }
1122
1123
    /**
1124
     * Returns true if the preview is requested to be shown.
1125
     *
1126
     * @return bool
1127
     */
1128
    protected function isPreviewRequested()
1129
    {
1130
        $request = $this->getRequest();
1131
1132
        return $request->get('btn_preview') !== null;
1133
    }
1134
1135
    /**
1136
     * Returns true if the preview has been approved.
1137
     *
1138
     * @return bool
1139
     */
1140
    protected function isPreviewApproved()
1141
    {
1142
        $request = $this->getRequest();
1143
1144
        return $request->get('btn_preview_approve') !== null;
1145
    }
1146
1147
    /**
1148
     * Returns true if the request is in the preview workflow.
1149
     *
1150
     * That means either a preview is requested or the preview has already been shown
1151
     * and it got approved/declined.
1152
     *
1153
     * @return bool
1154
     */
1155
    protected function isInPreviewMode()
1156
    {
1157
        return $this->admin->supportsPreviewMode()
1158
        && ($this->isPreviewRequested()
1159
            || $this->isPreviewApproved()
1160
            || $this->isPreviewDeclined());
1161
    }
1162
1163
    /**
1164
     * Returns true if the preview has been declined.
1165
     *
1166
     * @return bool
1167
     */
1168
    protected function isPreviewDeclined()
1169
    {
1170
        $request = $this->getRequest();
1171
1172
        return $request->get('btn_preview_decline') !== null;
1173
    }
1174
1175
    /**
1176
     * Gets ACL users.
1177
     *
1178
     * @return \Traversable
1179
     */
1180
    protected function getAclUsers()
1181
    {
1182
        $aclUsers = [];
1183
1184
        $userManagerServiceName = $this->container->getParameter('sonata.admin.security.acl_user_manager');
1185
        if ($userManagerServiceName !== null && $this->has($userManagerServiceName)) {
1186
            $userManager = $this->get($userManagerServiceName);
1187
1188
            if (method_exists($userManager, 'findUsers')) {
1189
                $aclUsers = $userManager->findUsers();
1190
            }
1191
        }
1192
1193
        return is_array($aclUsers) ? new \ArrayIterator($aclUsers) : $aclUsers;
1194
    }
1195
1196
    /**
1197
     * Gets ACL roles.
1198
     *
1199
     * @return \Traversable
1200
     */
1201
    protected function getAclRoles()
1202
    {
1203
        $aclRoles = [];
1204
        $roleHierarchy = $this->container->getParameter('security.role_hierarchy.roles');
1205
        $pool = $this->container->get('sonata.admin.pool');
1206
1207
        foreach ($pool->getAdminServiceIds() as $id) {
1208
            try {
1209
                $admin = $pool->getInstance($id);
1210
            } catch (\Exception $e) {
1211
                continue;
1212
            }
1213
1214
            $baseRole = $admin->getSecurityHandler()->getBaseRole($admin);
1215
            foreach ($admin->getSecurityInformation() as $role => $permissions) {
1216
                $role = sprintf($baseRole, $role);
1217
                $aclRoles[] = $role;
1218
            }
1219
        }
1220
1221
        foreach ($roleHierarchy as $name => $roles) {
1222
            $aclRoles[] = $name;
1223
            $aclRoles = array_merge($aclRoles, $roles);
1224
        }
1225
1226
        $aclRoles = array_unique($aclRoles);
1227
1228
        return is_array($aclRoles) ? new \ArrayIterator($aclRoles) : $aclRoles;
1229
    }
1230
1231
    /**
1232
     * Adds a flash message for type.
1233
     *
1234
     * @param string $type
1235
     * @param string $message
1236
     *
1237
     * @TODO Remove this method when bumping requirements to Symfony >= 2.6
1238
     */
1239
    protected function addFlash($type, $message)
1240
    {
1241
        if (method_exists('Symfony\Bundle\FrameworkBundle\Controller\Controller', 'addFlash')) {
1242
            parent::addFlash($type, $message);
1243
        } else {
1244
            $this->get('session')
1245
                ->getFlashBag()
1246
                ->add($type, $message);
1247
        }
1248
    }
1249
1250
    /**
1251
     * Validate CSRF token for action without form.
1252
     *
1253
     * @param string $intention
1254
     *
1255
     * @throws HttpException
1256
     */
1257
    protected function validateCsrfToken($intention)
1258
    {
1259
        $request = $this->getRequest();
1260
        $token = $request->request->get('_sonata_csrf_token', false);
1261
1262
        if ($this->container->has('security.csrf.token_manager')) { // SF3.0
1263
            $valid = $this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($intention, $token));
1264
        } elseif ($this->container->has('form.csrf_provider')) { // < SF3.0
1265
            $valid = $this->container->get('form.csrf_provider')->isCsrfTokenValid($intention, $token);
1266
        } else {
1267
            return;
1268
        }
1269
1270
        if (!$valid) {
1271
            throw new HttpException(400, 'The csrf token is not valid, CSRF attack?');
1272
        }
1273
    }
1274
1275
    /**
1276
     * Escape string for html output.
1277
     *
1278
     * @param string $s
1279
     *
1280
     * @return string
1281
     */
1282
    protected function escapeHtml($s)
1283
    {
1284
        return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
1285
    }
1286
1287
    /**
1288
     * Get CSRF token.
1289
     *
1290
     * @param string $intention
1291
     *
1292
     * @return string|false
1293
     */
1294
    protected function getCsrfToken($intention)
1295
    {
1296
        if ($this->container->has('security.csrf.token_manager')) {
1297
            return $this->container->get('security.csrf.token_manager')->getToken($intention)->getValue();
1298
        }
1299
1300
        // TODO: Remove it when bumping requirements to SF 2.4+
1301
        if ($this->container->has('form.csrf_provider')) {
1302
            return $this->container->get('form.csrf_provider')->generateCsrfToken($intention);
1303
        }
1304
1305
        return false;
1306
    }
1307
1308
    /**
1309
     * This method can be overloaded in your custom CRUD controller.
1310
     * It's called from createAction.
1311
     *
1312
     * @param Request $request
1313
     * @param mixed   $object
1314
     *
1315
     * @return Response|null
1316
     */
1317
    protected function preCreate(Request $request, $object)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1318
    {
1319
    }
1320
1321
    /**
1322
     * This method can be overloaded in your custom CRUD controller.
1323
     * It's called from editAction.
1324
     *
1325
     * @param Request $request
1326
     * @param mixed   $object
1327
     *
1328
     * @return Response|null
1329
     */
1330
    protected function preEdit(Request $request, $object)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1331
    {
1332
    }
1333
1334
    /**
1335
     * This method can be overloaded in your custom CRUD controller.
1336
     * It's called from deleteAction.
1337
     *
1338
     * @param Request $request
1339
     * @param mixed   $object
1340
     *
1341
     * @return Response|null
1342
     */
1343
    protected function preDelete(Request $request, $object)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1344
    {
1345
    }
1346
1347
    /**
1348
     * This method can be overloaded in your custom CRUD controller.
1349
     * It's called from showAction.
1350
     *
1351
     * @param Request $request
1352
     * @param mixed   $object
1353
     *
1354
     * @return Response|null
1355
     */
1356
    protected function preShow(Request $request, $object)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1357
    {
1358
    }
1359
1360
    /**
1361
     * This method can be overloaded in your custom CRUD controller.
1362
     * It's called from listAction.
1363
     *
1364
     * @param Request $request
1365
     *
1366
     * @return Response|null
1367
     */
1368
    protected function preList(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1369
    {
1370
    }
1371
1372
    /**
1373
     * Translate a message id.
1374
     *
1375
     * @param string $id
1376
     * @param array  $parameters
1377
     * @param string $domain
1378
     * @param string $locale
1379
     *
1380
     * @return string translated string
1381
     */
1382
    final protected function trans($id, array $parameters = [], $domain = null, $locale = null)
1383
    {
1384
        $domain = $domain ?: $this->admin->getTranslationDomain();
1385
1386
        return $this->get('translator')->trans($id, $parameters, $domain, $locale);
1387
    }
1388
1389
    /**
1390
     * Sets the admin form theme to form view. Used for compatibility between Symfony versions.
1391
     *
1392
     * @param FormView $formView
1393
     * @param string   $theme
1394
     */
1395
    private function setFormTheme(FormView $formView, $theme)
1396
    {
1397
        $twig = $this->get('twig');
1398
1399
        try {
1400
            $twig
1401
                ->getRuntime('Symfony\Bridge\Twig\Form\TwigRenderer')
1402
                ->setTheme($formView, $theme);
1403
        } catch (\Twig_Error_Runtime $e) {
1404
            // BC for Symfony < 3.2 where this runtime not exists
1405
            $twig
1406
                ->getExtension('Symfony\Bridge\Twig\Extension\FormExtension')
1407
                ->renderer
1408
                ->setTheme($formView, $theme);
1409
        }
1410
    }
1411
}
1412