Completed
Push — master ( e25986...ffddd1 )
by Craig
07:06
created

AbstractEditHandler::setLockingApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Routes.
4
 *
5
 * @copyright Zikula contributors (Zikula)
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 * @author Zikula contributors <[email protected]>.
8
 * @link http://www.zikula.org
9
 * @link http://zikula.org
10
 * @version Generated by ModuleStudio 0.7.4 (http://modulestudio.de).
11
 */
12
13
namespace Zikula\RoutesModule\Form\Handler\Common\Base;
14
15
use Psr\Log\LoggerInterface;
16
use RuntimeException;
17
use Symfony\Component\Form\AbstractType;
18
use Symfony\Component\Form\FormFactoryInterface;
19
use Symfony\Component\HttpFoundation\RedirectResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\HttpFoundation\RequestStack;
22
use Symfony\Component\Routing\RouterInterface;
23
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
24
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
25
use Zikula\Common\Translator\TranslatorInterface;
26
use Zikula\Common\Translator\TranslatorTrait;
27
use Zikula\Core\Doctrine\EntityAccess;
28
use Zikula\PageLockModule\Api\LockingApi;
29
use Zikula\PermissionsModule\Api\ApiInterface\PermissionApiInterface;
30
use Zikula\UsersModule\Api\CurrentUserApi;
31
use Zikula\RoutesModule\Entity\Factory\RoutesFactory;
32
use Zikula\RoutesModule\Helper\ControllerHelper;
33
use Zikula\RoutesModule\Helper\ModelHelper;
34
use Zikula\RoutesModule\Helper\SelectionHelper;
35
use Zikula\RoutesModule\Helper\WorkflowHelper;
36
37
/**
38
 * This handler class handles the page events of editing forms.
39
 * It collects common functionality required by different object types.
40
 */
41
abstract class AbstractEditHandler
42
{
43
    use TranslatorTrait;
44
45
    /**
46
     * Name of treated object type.
47
     *
48
     * @var string
49
     */
50
    protected $objectType;
51
52
    /**
53
     * Name of treated object type starting with upper case.
54
     *
55
     * @var string
56
     */
57
    protected $objectTypeCapital;
58
59
    /**
60
     * Lower case version.
61
     *
62
     * @var string
63
     */
64
    protected $objectTypeLower;
65
66
    /**
67
     * Permission component based on object type.
68
     *
69
     * @var string
70
     */
71
    protected $permissionComponent;
72
73
    /**
74
     * Reference to treated entity instance.
75
     *
76
     * @var EntityAccess
77
     */
78
    protected $entityRef = null;
79
80
    /**
81
     * List of identifier names.
82
     *
83
     * @var array
84
     */
85
    protected $idFields = [];
86
87
    /**
88
     * List of identifiers of treated entity.
89
     *
90
     * @var array
91
     */
92
    protected $idValues = [];
93
94
    /**
95
     * Code defining the redirect goal after command handling.
96
     *
97
     * @var string
98
     */
99
    protected $returnTo = null;
100
101
    /**
102
     * Whether a create action is going to be repeated or not.
103
     *
104
     * @var boolean
105
     */
106
    protected $repeatCreateAction = false;
107
108
    /**
109
     * Url of current form with all parameters for multiple creations.
110
     *
111
     * @var string
112
     */
113
    protected $repeatReturnUrl = null;
114
115
    /**
116
     * Whether an existing item is used as template for a new one.
117
     *
118
     * @var boolean
119
     */
120
    protected $hasTemplateId = false;
121
122
    /**
123
     * Whether the PageLock extension is used for this entity type or not.
124
     *
125
     * @var boolean
126
     */
127
    protected $hasPageLockSupport = false;
128
129
    /**
130
     * @var ZikulaHttpKernelInterface
131
     */
132
    protected $kernel;
133
134
    /**
135
     * @var FormFactoryInterface
136
     */
137
    protected $formFactory;
138
139
    /**
140
     * The current request.
141
     *
142
     * @var Request
143
     */
144
    protected $request;
145
146
    /**
147
     * The router.
148
     *
149
     * @var RouterInterface
150
     */
151
    protected $router;
152
153
    /**
154
     * @var LoggerInterface
155
     */
156
    protected $logger;
157
158
    /**
159
     * @var PermissionApiInterface
160
     */
161
    protected $permissionApi;
162
163
    /**
164
     * @var CurrentUserApi
165
     */
166
    protected $currentUserApi;
167
168
    /**
169
     * @var RoutesFactory
170
     */
171
    protected $entityFactory;
172
173
    /**
174
     * @var ControllerHelper
175
     */
176
    protected $controllerHelper;
177
178
    /**
179
     * @var ModelHelper
180
     */
181
    protected $modelHelper;
182
183
    /**
184
     * @var SelectionHelper
185
     */
186
    protected $selectionHelper;
187
188
    /**
189
     * @var WorkflowHelper
190
     */
191
    protected $workflowHelper;
192
193
    /**
194
     * Reference to optional locking api.
195
     *
196
     * @var LockingApi
197
     */
198
    protected $lockingApi = null;
199
200
    /**
201
     * The handled form type.
202
     *
203
     * @var AbstractType
204
     */
205
    protected $form;
206
207
    /**
208
     * Template parameters.
209
     *
210
     * @var array
211
     */
212
    protected $templateParameters = [];
213
214
    /**
215
     * EditHandler constructor.
216
     *
217
     * @param ZikulaHttpKernelInterface $kernel           Kernel service instance
218
     * @param TranslatorInterface       $translator       Translator service instance
219
     * @param FormFactoryInterface      $formFactory      FormFactory service instance
220
     * @param RequestStack              $requestStack     RequestStack service instance
221
     * @param RouterInterface           $router           Router service instance
222
     * @param LoggerInterface           $logger           Logger service instance
223
     * @param PermissionApiInterface             $permissionApi    PermissionApi service instance
224
     * @param CurrentUserApi            $currentUserApi   CurrentUserApi service instance
225
     * @param RoutesFactory $entityFactory RoutesFactory service instance
226
     * @param ControllerHelper          $controllerHelper ControllerHelper service instance
227
     * @param ModelHelper               $modelHelper      ModelHelper service instance
228
     * @param SelectionHelper           $selectionHelper  SelectionHelper service instance
229
     * @param WorkflowHelper            $workflowHelper   WorkflowHelper service instance
230
     */
231
    public function __construct(
232
        ZikulaHttpKernelInterface $kernel,
233
        TranslatorInterface $translator,
234
        FormFactoryInterface $formFactory,
235
        RequestStack $requestStack,
236
        RouterInterface $router,
237
        LoggerInterface $logger,
238
        PermissionApiInterface $permissionApi,
239
        CurrentUserApi $currentUserApi,
240
        RoutesFactory $entityFactory,
241
        ControllerHelper $controllerHelper,
242
        ModelHelper $modelHelper,
243
        SelectionHelper $selectionHelper,
244
        WorkflowHelper $workflowHelper)
245
    {
246
        $this->kernel = $kernel;
247
        $this->setTranslator($translator);
248
        $this->formFactory = $formFactory;
249
        $this->request = $requestStack->getCurrentRequest();
250
        $this->router = $router;
251
        $this->logger = $logger;
252
        $this->permissionApi = $permissionApi;
253
        $this->currentUserApi = $currentUserApi;
254
        $this->entityFactory = $entityFactory;
255
        $this->controllerHelper = $controllerHelper;
256
        $this->modelHelper = $modelHelper;
257
        $this->selectionHelper = $selectionHelper;
258
        $this->workflowHelper = $workflowHelper;
259
    }
260
261
    /**
262
     * Sets the translator.
263
     *
264
     * @param TranslatorInterface $translator Translator service instance
265
     */
266
    public function setTranslator(/*TranslatorInterface */$translator)
267
    {
268
        $this->translator = $translator;
269
    }
270
271
    /**
272
     * Initialise form handler.
273
     *
274
     * This method takes care of all necessary initialisation of our data and form states.
275
     *
276
     * @param array $templateParameters List of preassigned template variables
277
     *
278
     * @return boolean False in case of initialisation errors, otherwise true
279
     *
280
     * @throws RuntimeException Thrown if the workflow actions can not be determined
281
     */
282
    public function processForm(array $templateParameters)
283
    {
284
        $this->templateParameters = $templateParameters;
285
    
286
        // initialise redirect goal
287
        $this->returnTo = $this->request->query->get('returnTo', null);
288
        if (null === $this->returnTo) {
289
            // default to referer
290
            if ($this->request->getSession()->has('zikularoutesmoduleReferer')) {
291
                $this->returnTo = $this->request->getSession()->get('zikularoutesmoduleReferer');
292
            } elseif ($this->request->headers->has('zikularoutesmoduleReferer')) {
293
                $this->returnTo = $this->request->headers->get('zikularoutesmoduleReferer');
294
                $this->request->getSession()->set('zikularoutesmoduleReferer', $this->returnTo);
295
            } elseif ($this->request->server->has('HTTP_REFERER')) {
296
                $this->returnTo = $this->request->server->get('HTTP_REFERER');
297
                $this->request->getSession()->set('zikularoutesmoduleReferer', $this->returnTo);
298
            }
299
        }
300
        // store current uri for repeated creations
301
        $this->repeatReturnUrl = $this->request->getSchemeAndHttpHost() . $this->request->getBasePath() . $this->request->getPathInfo();
302
    
303
        $this->permissionComponent = 'ZikulaRoutesModule:' . $this->objectTypeCapital . ':';
304
    
305
        $this->idFields = $this->selectionHelper->getIdFields($this->objectType);
306
    
307
        // retrieve identifier of the object we wish to view
308
        $this->idValues = $this->controllerHelper->retrieveIdentifier($this->request, [], $this->objectType, $this->idFields);
309
        $hasIdentifier = $this->controllerHelper->isValidIdentifier($this->idValues);
310
    
311
        $entity = null;
0 ignored issues
show
Unused Code introduced by
$entity is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
312
        $this->templateParameters['mode'] = $hasIdentifier ? 'edit' : 'create';
313
    
314
        if ($this->templateParameters['mode'] == 'edit') {
315
            if (!$this->permissionApi->hasPermission($this->permissionComponent, $this->createCompositeIdentifier() . '::', ACCESS_EDIT)) {
316
                throw new AccessDeniedException();
317
            }
318
    
319
            $entity = $this->initEntityForEditing();
320
            if (null !== $entity) {
321
                if (true === $this->hasPageLockSupport && $this->kernel->isBundle('ZikulaPageLockModule') && null !== $this->lockingApi) {
322
                    // try to guarantee that only one person at a time can be editing this entity
323
                    $lockName = 'ZikulaRoutesModule' . $this->objectTypeCapital . $this->createCompositeIdentifier();
324
                    $this->lockingApi->addLock($lockName, $this->getRedirectUrl(null));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\RoutesModule\Form...ase\AbstractEditHandler as the method getRedirectUrl() does only exist in the following sub-classes of Zikula\RoutesModule\Form...ase\AbstractEditHandler: Zikula\RoutesModule\Form...ase\AbstractEditHandler, Zikula\RoutesModule\Form\Handler\Route\EditHandler. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
325
                }
326
            }
327
        } else {
328
            if (!$this->permissionApi->hasPermission($this->permissionComponent, '::', ACCESS_EDIT)) {
329
                throw new AccessDeniedException();
330
            }
331
    
332
            $entity = $this->initEntityForCreation();
333
    
334
            // set default values from request parameters
335
            foreach ($this->request->query->all() as $key => $value) {
336
                if (strlen($key) < 5 || substr($key, 0, 4) != 'set_') {
337
                    continue;
338
                }
339
                $fieldName = str_replace('set_', '', $key);
340
                $setterName = 'set' . ucfirst($fieldName);
341
                if (!method_exists($entity, $setterName)) {
342
                    continue;
343
                }
344
                $entity[$fieldName] = $value;
345
            }
346
        }
347
    
348
        if (null === $entity) {
349
            $this->request->getSession()->getFlashBag()->add('error', $this->__('No such item found.'));
350
    
351
            return new RedirectResponse($this->getRedirectUrl(['commandName' => 'cancel']), 302);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\RoutesModule\Form...ase\AbstractEditHandler as the method getRedirectUrl() does only exist in the following sub-classes of Zikula\RoutesModule\Form...ase\AbstractEditHandler: Zikula\RoutesModule\Form...ase\AbstractEditHandler, Zikula\RoutesModule\Form\Handler\Route\EditHandler. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
352
        }
353
    
354
        // save entity reference for later reuse
355
        $this->entityRef = $entity;
356
    
357
    
358
        $actions = $this->workflowHelper->getActionsForObject($entity);
359
        if (false === $actions || !is_array($actions)) {
360
            $this->request->getSession()->getFlashBag()->add('error', $this->__('Error! Could not determine workflow actions.'));
361
            $logArgs = ['app' => 'ZikulaRoutesModule', 'user' => $this->currentUserApi->get('uname'), 'entity' => $this->objectType, 'id' => $entity->createCompositeIdentifier()];
362
            $this->logger->error('{app}: User {user} tried to edit the {entity} with id {id}, but failed to determine available workflow actions.', $logArgs);
363
            throw new \RuntimeException($this->__('Error! Could not determine workflow actions.'));
364
        }
365
    
366
        $this->templateParameters['actions'] = $actions;
367
    
368
        $this->form = $this->createForm();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->form is correct as $this->createForm() (which targets Zikula\RoutesModule\Form...itHandler::createForm()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
369
        if (!is_object($this->form)) {
370
            return false;
371
        }
372
    
373
        // handle form request and check validity constraints of edited entity
374
        if ($this->form->handleRequest($this->request) && $this->form->isSubmitted()) {
375
            if ($this->form->isValid()) {
376
                $result = $this->handleCommand();
377
                if (false === $result) {
378
                    $this->templateParameters['form'] = $this->form->createView();
379
                }
380
    
381
                return $result;
382
            }
383
            if ($this->form->get('cancel')->isClicked()) {
384
                return new RedirectResponse($this->getRedirectUrl(['commandName' => 'cancel']), 302);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\RoutesModule\Form...ase\AbstractEditHandler as the method getRedirectUrl() does only exist in the following sub-classes of Zikula\RoutesModule\Form...ase\AbstractEditHandler: Zikula\RoutesModule\Form...ase\AbstractEditHandler, Zikula\RoutesModule\Form\Handler\Route\EditHandler. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
385
            }
386
        }
387
    
388
        $this->templateParameters['form'] = $this->form->createView();
389
    
390
        // everything okay, no initialisation errors occured
391
        return true;
392
    }
393
    
394
    /**
395
     * Creates the form type.
396
     */
397
    protected function createForm()
398
    {
399
        // to be customised in sub classes
400
        return null;
401
    }
402
    
403
    /**
404
     * Returns the template parameters.
405
     *
406
     * @return array
407
     */
408
    public function getTemplateParameters()
409
    {
410
        return $this->templateParameters;
411
    }
412
    
413
    /**
414
     * Create concatenated identifier string (for composite keys).
415
     *
416
     * @return String concatenated identifiers
417
     */
418
    protected function createCompositeIdentifier()
419
    {
420
        $itemId = '';
421
        foreach ($this->idFields as $idField) {
422
            if (!empty($itemId)) {
423
                $itemId .= '_';
424
            }
425
            $itemId .= $this->idValues[$idField];
426
        }
427
    
428
        return $itemId;
429
    }
430
    
431
    /**
432
     * Initialise existing entity for editing.
433
     *
434
     * @return EntityAccess|null Desired entity instance or null
435
     */
436
    protected function initEntityForEditing()
437
    {
438
        $entity = $this->selectionHelper->getEntity($this->objectType, $this->idValues);
439
        if (null === $entity) {
440
            return null;
441
        }
442
    
443
        $entity->initWorkflow();
444
    
445
        return $entity;
446
    }
447
    
448
    /**
449
     * Initialise new entity for creation.
450
     *
451
     * @return EntityAccess|null Desired entity instance or null
452
     */
453
    protected function initEntityForCreation()
454
    {
455
        $this->hasTemplateId = false;
456
        $templateId = $this->request->query->get('astemplate', '');
457
        $entity = null;
458
    
459
        if (!empty($templateId)) {
460
            $templateIdValueParts = explode('_', $templateId);
461
            $this->hasTemplateId = count($templateIdValueParts) == count($this->idFields);
462
    
463
            if (true === $this->hasTemplateId) {
464
                $templateIdValues = [];
465
                $i = 0;
466
                foreach ($this->idFields as $idField) {
467
                    $templateIdValues[$idField] = $templateIdValueParts[$i];
468
                    $i++;
469
                }
470
                // reuse existing entity
471
                $entityT = $this->selectionHelper->getEntity($this->objectType, $templateIdValues);
472
                if (null === $entityT) {
473
                    return null;
474
                }
475
                $entity = clone $entityT;
476
            }
477
        }
478
    
479
        if (null === $entity) {
480
            $createMethod = 'create' . ucfirst($this->objectType);
481
            $entity = $this->entityFactory->$createMethod();
482
        }
483
    
484
        return $entity;
485
    }
486
487
    /**
488
     * Get list of allowed redirect codes.
489
     *
490
     * @return array list of possible redirect codes
491
     */
492
    protected function getRedirectCodes()
493
    {
494
        $codes = [];
495
    
496
        // to be filled by subclasses
497
    
498
        return $codes;
499
    }
500
501
    /**
502
     * Command event handler.
503
     *
504
     * @param array $args List of arguments
505
     *
506
     * @return mixed Redirect or false on errors
507
     */
508
    public function handleCommand($args = [])
509
    {
510
        // build $args for BC (e.g. used by redirect handling)
511 View Code Duplication
        foreach ($this->templateParameters['actions'] as $action) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
512
            if ($this->form->get($action['id'])->isClicked()) {
513
                $args['commandName'] = $action['id'];
514
            }
515
        }
516
        if ($this->form->get('cancel')->isClicked()) {
517
            $args['commandName'] = 'cancel';
518
        }
519
    
520
        $action = $args['commandName'];
521
        $isRegularAction = !in_array($action, ['delete', 'cancel']);
522
    
523
        if ($isRegularAction || $action == 'delete') {
524
            $this->fetchInputData($args);
525
        }
526
    
527
        // get treated entity reference from persisted member var
528
        $entity = $this->entityRef;
0 ignored issues
show
Unused Code introduced by
$entity is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
529
    
530
        if ($isRegularAction || $action == 'delete') {
531
            $success = $this->applyAction($args);
532
            if (!$success) {
533
                // the workflow operation failed
534
                return false;
535
            }
536
        }
537
    
538
        if (true === $this->hasPageLockSupport && $this->templateParameters['mode'] == 'edit' && $this->kernel->isBundle('ZikulaPageLockModule') && null !== $this->lockingApi) {
539
            $lockName = 'ZikulaRoutesModule' . $this->objectTypeCapital . $this->createCompositeIdentifier();
540
            $this->lockingApi->releaseLock($lockName);
541
        }
542
    
543
        return new RedirectResponse($this->getRedirectUrl($args), 302);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\RoutesModule\Form...ase\AbstractEditHandler as the method getRedirectUrl() does only exist in the following sub-classes of Zikula\RoutesModule\Form...ase\AbstractEditHandler: Zikula\RoutesModule\Form...ase\AbstractEditHandler, Zikula\RoutesModule\Form\Handler\Route\EditHandler. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
544
    }
545
    
546
    /**
547
     * Get success or error message for default operations.
548
     *
549
     * @param array   $args    arguments from handleCommand method
550
     * @param Boolean $success true if this is a success, false for default error
551
     *
552
     * @return String desired status or error message
553
     */
554
    protected function getDefaultMessage($args, $success = false)
555
    {
556
        $message = '';
557
        switch ($args['commandName']) {
558 View Code Duplication
            case 'create':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
559
                if (true === $success) {
560
                    $message = $this->__('Done! Item created.');
561
                } else {
562
                    $message = $this->__('Error! Creation attempt failed.');
563
                }
564
                break;
565 View Code Duplication
            case 'update':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
566
                if (true === $success) {
567
                    $message = $this->__('Done! Item updated.');
568
                } else {
569
                    $message = $this->__('Error! Update attempt failed.');
570
                }
571
                break;
572 View Code Duplication
            case 'delete':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
573
                if (true === $success) {
574
                    $message = $this->__('Done! Item deleted.');
575
                } else {
576
                    $message = $this->__('Error! Deletion attempt failed.');
577
                }
578
                break;
579
        }
580
    
581
        return $message;
582
    }
583
    
584
    /**
585
     * Add success or error message to session.
586
     *
587
     * @param array   $args    arguments from handleCommand method
588
     * @param Boolean $success true if this is a success, false for default error
589
     *
590
     * @throws RuntimeException Thrown if executing the workflow action fails
591
     */
592
    protected function addDefaultMessage($args, $success = false)
593
    {
594
        $message = $this->getDefaultMessage($args, $success);
595
        if (empty($message)) {
596
            return;
597
        }
598
    
599
        $flashType = true === $success ? 'status' : 'error';
600
        $this->request->getSession()->getFlashBag()->add($flashType, $message);
601
        $logArgs = ['app' => 'ZikulaRoutesModule', 'user' => $this->currentUserApi->get('uname'), 'entity' => $this->objectType, 'id' => $this->entityRef->createCompositeIdentifier()];
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\Core\Doctrine\EntityAccess as the method createCompositeIdentifier() does only exist in the following sub-classes of Zikula\Core\Doctrine\EntityAccess: Zikula\RoutesModule\Enti...ase\AbstractRouteEntity, Zikula\RoutesModule\Entity\RouteEntity. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
602
        if (true === $success) {
603
            $this->logger->notice('{app}: User {user} updated the {entity} with id {id}.', $logArgs);
604
        } else {
605
            $this->logger->error('{app}: User {user} tried to update the {entity} with id {id}, but failed.', $logArgs);
606
        }
607
    }
608
609
    /**
610
     * Input data processing called by handleCommand method.
611
     *
612
     * @param array $args Additional arguments
613
     */
614
    public function fetchInputData($args)
0 ignored issues
show
Unused Code introduced by
The parameter $args 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...
615
    {
616
        // fetch posted data input values as an associative array
617
        $formData = $this->form->getData();
618
    
619
        if ($this->templateParameters['mode'] == 'create' && isset($this->form['repeatCreation']) && $this->form['repeatCreation']->getData() == 1) {
620
            $this->repeatCreateAction = true;
621
        }
622
    
623
        if (method_exists($this->entityRef, 'getCreatedBy')) {
624 View Code Duplication
            if (isset($this->form['moderationSpecificCreator']) && null !== $this->form['moderationSpecificCreator']->getData()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
625
                $this->entityRef->setCreatedBy($this->form['moderationSpecificCreator']->getData());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\Core\Doctrine\EntityAccess as the method setCreatedBy() does only exist in the following sub-classes of Zikula\Core\Doctrine\EntityAccess: Zikula\RoutesModule\Enti...ase\AbstractRouteEntity, Zikula\RoutesModule\Entity\RouteEntity. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
626
            }
627 View Code Duplication
            if (isset($this->form['moderationSpecificCreationDate']) && $this->form['moderationSpecificCreationDate']->getData() != '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
628
                $this->entityRef->setCreatedDate($this->form['moderationSpecificCreationDate']->getData());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Zikula\Core\Doctrine\EntityAccess as the method setCreatedDate() does only exist in the following sub-classes of Zikula\Core\Doctrine\EntityAccess: Zikula\RoutesModule\Enti...ase\AbstractRouteEntity, Zikula\RoutesModule\Entity\RouteEntity. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
629
            }
630
        }
631
    
632
        if (isset($this->form['additionalNotificationRemarks']) && $this->form['additionalNotificationRemarks']->getData() != '') {
633
            $this->request->getSession()->set('ZikulaRoutesModuleAdditionalNotificationRemarks', $this->form['additionalNotificationRemarks']->getData());
634
        }
635
    
636
        // return remaining form data
637
        return $formData;
638
    }
639
640
    /**
641
     * This method executes a certain workflow action.
642
     *
643
     * @param array $args Arguments from handleCommand method
644
     *
645
     * @return bool Whether everything worked well or not
646
     */
647
    public function applyAction(array $args = [])
648
    {
649
        // stub for subclasses
650
        return false;
651
    }
652
653
    /**
654
     * Sets optional locking api reference.
655
     *
656
     * @param LockingApi $lockingApi
657
     */
658
    public function setLockingApi(LockingApi $lockingApi)
659
    {
660
        $this->lockingApi = $lockingApi;
661
    }
662
}
663