Completed
Push — develop ( f2612d...39673b )
by
unknown
07:43
created

ManageController   F

Complexity

Total Complexity 65

Size/Duplication

Total Lines 580
Duplicated Lines 8.1 %

Coupling/Cohesion

Components 1
Dependencies 23

Importance

Changes 4
Bugs 0 Features 1
Metric Value
wmc 65
c 4
b 0
f 1
lcom 1
cbo 23
dl 47
loc 580
rs 1.5492

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A attachDefaultListeners() 12 12 1
A preDispatch() 0 16 3
A newAction() 0 14 1
A editAction() 0 10 2
A saveAction() 0 4 1
F save() 21 184 30
A checkApplyIdAction() 0 12 2
A getFormular() 0 17 2
C getJob() 0 30 7
A getViewModel() 0 12 1
B completionAction() 0 30 2
B approvalAction() 14 74 6
A deactivateAction() 0 13 2
A templateAction() 0 13 2
A getErrorViewModel() 0 9 1
A historyAction() 0 10 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ManageController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ManageController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * YAWIK
5
 *
6
 * @filesource
7
 * @copyright (c) 2013-2015 Cross Solution (http://cross-solution.de)
8
 * @license   MIT
9
 */
10
11
/** ActionController of Core */
12
namespace Jobs\Controller;
13
14
use Jobs\Entity\Status;
15
use Core\Repository\RepositoryService;
16
use Zend\Mvc\Controller\AbstractActionController;
17
use Zend\View\Model\ViewModel;
18
use Zend\View\Model\JsonModel;
19
use Core\Form\SummaryForm;
20
use Zend\Mvc\MvcEvent;
21
use Jobs\Listener\Events\JobEvent;
22
use Core\Form\SummaryFormInterface;
23
use Zend\Stdlib\ArrayUtils;
24
use Auth\AuthenticationService;
25
use Zend\Mvc\I18n\Translator;
26
27
/**
28
 * This Controller handles management actions for jobs.
29
 *
30
 * @author Mathias Gelhausen <[email protected]>
31
 */
32
class ManageController extends AbstractActionController
33
{
34
    /**
35
     * @var AuthenticationService
36
     */
37
    protected $auth;
38
39
    /**
40
     * @var RepositoryService
41
     */
42
    protected $repositoryService;
43
44
    /**
45
     * @var Translator
46
     */
47
    protected $translator;
48
49
    /**
50
     * @param AuthenticationService $auth
51
     * @param RepositoryService     $repositoryService
52
     * @param                       $translator
53
     */
54
    public function __construct(AuthenticationService $auth, RepositoryService $repositoryService, Translator $translator) {
55
        $this->auth = $auth;
56
        $this->repositoryService = $repositoryService;
57
        $this->translator = $translator;
58
    }
59
60
    /**
61
     * @return $this|void
62
     */
63 View Code Duplication
    public function attachDefaultListeners()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
64
    {
65
        parent::attachDefaultListeners();
66
        $events = $this->getEventManager();
67
        $events->attach(MvcEvent::EVENT_DISPATCH, array($this, 'preDispatch'), 10);
68
        $serviceLocator = $this->getServiceLocator();
69
        $defaultServices = $serviceLocator->get('DefaultListeners');
70
        $events = $this->getEventManager();
71
        $events->attach($defaultServices);
0 ignored issues
show
Documentation introduced by
$defaultServices is of type object|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...
72
73
        return $this;
74
    }
75
76
    /**
77
     * Dispatch listener callback.
78
     *
79
     * Attaches the MailSender aggregate listener to the job event manager.
80
     *
81
     * @param MvcEvent $e
82
     * @since 0.19
83
     */
84
    public function preDispatch(MvcEvent $e)
85
    {
86
        if ('calculate' == $this->params()->fromQuery('do')) {
87
            return;
88
        }
89
        $routeMatch = $e->getRouteMatch();
90
        $action = $routeMatch->getParam('action');
91
92
        if (in_array($action, array('edit', 'approval', 'completion'))) {
93
            $services = $this->getServiceLocator();
94
            $jobEvents = $services->get('Jobs/Events');
95
            $mailSender = $services->get('Jobs/Listener/MailSender');
96
97
            $mailSender->attach($jobEvents);
98
        }
99
    }
100
101
    /**
102
     * Action called, when a new job should be created.
103
     *
104
     */
105
    public function newAction()
106
    {
107
        $job = $this->getJob(/* create */ true);
108
        $this->acl($job, 'new');
0 ignored issues
show
Documentation Bug introduced by
The method acl does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
109
        $user = $this->auth->getUser();
110
        $job->setContactEmail($user->getInfo()->getEmail());
111
        $job->setApplyId(
112
            uniqid(substr(md5($user->getLogin()), 0, 3))
113
        );
114
        $form  = $this->getFormular($job);
115
        $model = $this->getViewModel($form);
116
        
117
        return $model;
118
    }
119
120
    /**
121
     * @TODO edit-Action and save-Action are doing the same, one of them has to quit
122
     *
123
     * @return null|ViewModel
124
     */
125
    public function editAction()
126
    {
127
        if ('calculate' == $this->params()->fromQuery('do')) {
128
            $calc = $this->getServiceLocator()->get('filtermanager')->get('Jobs/ChannelPrices');
129
            $sum = $calc->filter($this->params()->fromPost('channels'));
130
131
            return new JsonModel(['sum' => $sum]);
132
        }
133
        return $this->save();
134
    }
135
136
    /**
137
     * @return null|ViewModel
138
     */
139
    public function saveAction()
140
    {
141
        return $this->save();
142
    }
143
144
    /**
145
     * save a Job-Post either by a regular request or by an async post (AJAX)
146
     * a mandatory parameter is the ID of the Job
147
     * in case of a regular Request you can
148
     *
149
     * parameter are arbitrary elements for defaults or programming flow
150
     *
151
     * @param array $parameter
152
     * @return null|ViewModel
153
     * @throws \RuntimeException
154
     */
155
    protected function save($parameter = array())
156
    {
157
        $serviceLocator     = $this->getServiceLocator();
158
        $user               = $this->auth->getUser();
159
        if (empty($user->info->email)) {
0 ignored issues
show
Documentation introduced by
The property $info is declared protected in Auth\Entity\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
Accessing email on the interface Auth\Entity\InfoInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
160
            return $this->getErrorViewModel('no-parent', array('cause' => 'noEmail'));
161
        }
162
        $userOrg            = $user->getOrganization();
163
        if (!$userOrg->hasAssociation()) {
164
            return $this->getErrorViewModel('no-parent', array('cause' => 'noCompany'));
165
        }
166
167
        /** @var \Zend\Http\Request $request */
168
        $request            = $this->getRequest();
169
        $isAjax             = $request->isXmlHttpRequest();
170
        $pageToForm         = array(0 => array('locationForm', 'nameForm', 'portalForm'),
171
                                    1 => array('descriptionForm'),
172
                                    2 => array('previewForm'));
173
174
        $params             = $this->params();
175
        $formIdentifier     = $params->fromQuery('form');
176
        $pageIdentifier     = (int) $params->fromQuery('page', array_key_exists('page', $parameter)?$parameter['page']:0);
177
        $jobEntity          = $this->getJob();
178
        $viewModel          = null;
0 ignored issues
show
Unused Code introduced by
$viewModel 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...
179
        $this->acl($jobEntity, 'edit');
0 ignored issues
show
Documentation Bug introduced by
The method acl does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
180
        $form               = $this->getFormular($jobEntity);
181
182
        $valid              = true;
183
        $instanceForm       = null;
184
        $formErrorMessages = array();
185
186
        if (isset($formIdentifier) &&  $request->isPost()) {
187
            // at this point the form get instantiated and immediately accumulated
188
            $instanceForm = $form->getForm($formIdentifier);
189
            if (!isset($instanceForm)) {
190
                throw new \RuntimeException('No form found for "' . $formIdentifier . '"');
191
            }
192
            // the id may be part of the postData, but it never should be altered
193
            $postData = $request->getPost();
194
            if (isset($postData['id'])) {
195
                unset($postData['id']);
196
            }
197
            unset($postData['applyId']);
198
            $instanceForm->setData($postData);
199
            $valid = $instanceForm->isValid();
200
            $formErrorMessages = ArrayUtils::merge($formErrorMessages, $instanceForm->getMessages());
201
            if ($valid) {
202
                /*
203
                 * @todo This is a workaround for GeoJSON data insertion
204
                 * until we figured out, what we really want it to be.
205
                 */
206
                if ('locationForm' == $formIdentifier) {
207
                    $locElem = $instanceForm->getBaseFieldset()->get('location');
208
                    if ($locElem instanceOf \Geo\Form\GeoText) {
209
                        $loc = $locElem->getValue('entity');
210
                        $locations = $jobEntity->getLocations();
211
                        if (count($locations)) { $locations->clear(); }
212
                        $locations->add($loc);
213
                        $jobEntity->setLocation($locElem->getValue());
214
                    }
215
                }
216
217
                $title = $jobEntity->getTitle();
218
                $templateTitle = $jobEntity->getTemplateValues()->getTitle();
219
220
                if (empty($templateTitle)) {
221
                    $jobEntity->getTemplateValues()->setTitle($title);
222
                }
223
                $this->repositoryService->persist($jobEntity);
0 ignored issues
show
Documentation Bug introduced by
The method persist does not exist on object<Core\Repository\RepositoryService>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
224
            }
225
        }
226
227
        // validation
228
        $jobValid = true;
229
        $errorMessage = array();
230
        if (empty($jobEntity->getTitle())) {
231
            $jobValid = false;
232
            $errorMessage[] = $this->translator->translate('No Title');
233
        }
234
        if (empty($jobEntity->getLocation())) {
235
            $jobValid = false;
236
            $errorMessage[] = $this->translator->translate('No Location');
237
        }
238
        if (empty($jobEntity->getTermsAccepted())) {
239
            $jobValid = false;
240
            $errorMessage[] = $this->translator->translate('Accept the Terms');
241
        }
242
243
        $errorMessage = '<br />' . implode('<br />', $errorMessage);
244
        if ($isAjax) {
245
            if ($instanceForm instanceof SummaryForm) {
246
                $instanceForm->setRenderMode(SummaryForm::RENDER_SUMMARY);
247
                $viewHelper = 'summaryform';
248
            } else {
249
                $viewHelper = 'form';
250
            }
251
            $viewHelperManager  = $serviceLocator->get('ViewHelperManager');
252
            $content = $viewHelperManager->get($viewHelper)->__invoke($instanceForm);
253
            $viewModel = new JsonModel(
254
                array(
255
                'content' => $content,
256
                'valid' => $valid,
257
                'jobvalid' => $jobValid,
258
                'errors' => $formErrorMessages,
259
                'errorMessage' => $errorMessage)
260
            );
261
        } else {
262
            if (isset($pageIdentifier)) {
263
                $form->disableForm();
264
                if (array_key_exists($pageIdentifier, $pageToForm)) {
265
                    foreach ($pageToForm[$pageIdentifier] as $actualFormIdentifier) {
266
                        $form->enableForm($actualFormIdentifier);
267
                        if ($jobEntity->isDraft()) {
268
                            $actualForm = $form->get($actualFormIdentifier);
269
                            if ('nameForm' != $actualFormIdentifier && $actualForm instanceof SummaryFormInterface) {
270
                                $form->get($actualFormIdentifier)->setDisplayMode(SummaryFormInterface::DISPLAY_FORM);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Form\ElementInterface as the method setDisplayMode() does only exist in the following implementations of said interface: Applications\Form\Base, Applications\Form\Facts, Auth\Form\UserBase, Auth\Form\UserInfo, Core\Form\SummaryForm, Jobs\Form\AtsMode, Jobs\Form\Base, Jobs\Form\CompanyName, Jobs\Form\Multipost, Organizations\Form\Employees, Organizations\Form\OrganizationsContactForm, Organizations\Form\OrganizationsDescriptionForm, Organizations\Form\OrganizationsNameForm.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
271
                            }
272
                            if ('locationForm' == $actualFormIdentifier) {
273
                                $locElem = $actualForm->getBaseFieldset()->get('location');
274
                                if ($locElem instanceOf \Geo\Form\GeoText) {
275
                                    $loc = $jobEntity->getLocations();
276
                                    if (count($loc)) {
277
                                        $locElem->setValue($loc->first());
278
                                    }
279
                                }
280
                            }
281
                        }
282
                    }
283
                    if (!$jobEntity->isDraft()) {
284
                        // Job is deployed, some changes are now disabled
285
                        $form->enableAll();
286
                    }
287
                } else {
288
                    throw new \RuntimeException('No form found for page ' . $pageIdentifier);
289
                }
290
            }
291
            $pageLinkNext = null;
292
            $pageLinkPrevious = null;
293 View Code Duplication
            if (0 < $pageIdentifier) {
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...
294
                $pageLinkPrevious = $this->url()->fromRoute(
295
                    'lang/jobs/manage',
296
                    [],
297
                    ['query' => [
298
                        'id' => $jobEntity->getId(),
299
                        'page' => $pageIdentifier - 1]
300
                    ]
301
                );
302
            }
303 View Code Duplication
            if ($pageIdentifier < count($pageToForm) - 1) {
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...
304
                $pageLinkNext     = $this->url()->fromRoute(
305
                    'lang/jobs/manage',
306
                    [],
307
                    [
308
                        'query' => [
309
                            'id' => $jobEntity->getId(),
310
                            'page' => $pageIdentifier + 1]
311
                    ]
312
                );
313
            }
314
            $completionLink = $this->url()->fromRoute(
315
                'lang/jobs/completion',
316
                [ 'id' => $jobEntity->getId()]
317
            );
318
319
            $viewModel = $this->getViewModel($form);
320
321
            $viewModel->setVariables(
322
                array(
323
                'pageLinkPrevious' => $pageLinkPrevious,
324
                'pageLinkNext' => $pageLinkNext,
325
                'completionLink' => $completionLink,
326
                'page' => $pageIdentifier,
327
                'title' => $jobEntity->title,
0 ignored issues
show
Documentation introduced by
The property $title is declared protected in Jobs\Entity\Job. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
328
                'job' => $jobEntity,
329
                'summary' => 'this is what we charge you for your offer...',
330
                'valid' => $valid,
331
                'jobvalid' => $jobValid,
332
                'errorMessage' => $errorMessage,
333
                'isDraft' => $jobEntity->isDraft()
334
                )
335
            );
336
        }
337
        return $viewModel;
338
    }
339
340
    /**
341
     * @return array
342
     */
343
    public function checkApplyIdAction()
344
    {
345
        $services = $this->getServiceLocator();
346
        $validator = $services->get('validatormanager')->get('Jobs/Form/UniqueApplyId');
347
        if (!$validator->isValid($this->params()->fromQuery('applyId'))) {
348
            return array(
349
                'ok' => false,
350
                'messages' => $validator->getMessages(),
351
            );
352
        }
353
        return array('ok' => true);
354
    }
355
356
    /**
357
     * @param $job
358
     * @return mixed
359
     */
360
    protected function getFormular($job)
361
    {
362
        $services = $this->getServiceLocator();
363
        /* @var $forms \Zend\Form\FormElementManager */
364
        $forms    = $services->get('FormElementManager');
365
        /* @var $container \Jobs\Form\Job */
366
        $container = $forms->get(
367
            'Jobs/Job',
368
            array(
369
            'mode' => $job->id ? 'edit' : 'new'
370
            )
371
        );
372
        $container->setEntity($job);
373
        $container->setParam('job', $job->id);
374
        $container->setParam('applyId', $job->applyId);
375
        return $container;
376
    }
377
378
    /**
379
     * @param bool $allowDraft
380
     * @return \Jobs\Entity\Job
381
     * @throws \RuntimeException
382
     */
383
    protected function getJob($allowDraft = true)
384
    {
385
        /* @var \Jobs\Repository\Job $jobRepository */
386
        $jobRepository     = $this->repositoryService->get('Jobs/Job');
387
        // @TODO three different method to obtain the job-id ?, simplify this
388
        $id_fromRoute   = $this->params('id', 0);
0 ignored issues
show
Coding Style introduced by
$id_fromRoute does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
389
        $id_fromQuery   = $this->params()->fromQuery('id', 0);
0 ignored issues
show
Coding Style introduced by
$id_fromQuery does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
390
        $id_fromSubForm = $this->params()->fromPost('job', 0);
0 ignored issues
show
Coding Style introduced by
$id_fromSubForm does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
391
        $user           = $this->auth->getUser();
392
        $id             = empty($id_fromRoute)? (empty($id_fromQuery)?$id_fromSubForm:$id_fromQuery) : $id_fromRoute;
0 ignored issues
show
Coding Style introduced by
$id_fromRoute does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
393
394
        if (empty($id) && $allowDraft) {
395
            $this->acl('Jobs/Manage', 'new');
0 ignored issues
show
Documentation Bug introduced by
The method acl does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
396
            /** @var \Jobs\Entity\Job $job */
397
            $job = $jobRepository->findDraft($user);
398
            if (empty($job)) {
399
                $job = $jobRepository->create();
400
                $job->setIsDraft(true);
401
                $job->setUser($user);
402
                $this->repositoryService->store($job);
403
            }
404
            return $job;
405
        }
406
407
        $jobEntity      = $jobRepository->find($id);
408
        if (!$jobEntity) {
409
            throw new \RuntimeException('No job found with id "' . $id . '"');
410
        }
411
        return $jobEntity;
412
    }
413
414
    /**
415
     * @param $form
416
     * @param array $params
417
     * @return ViewModel
418
     */
419
    protected function getViewModel($form, array $params = array())
420
    {
421
        $variables = array(
422
            'form' => $form,
423
        );
424
        $viewVars  = array_merge($variables, $params);
425
        
426
        $model = new ViewModel($viewVars);
427
        $model->setTemplate("jobs/manage/form");
428
        
429
        return $model;
430
    }
431
432
    /**
433
     * Job opening is completed.
434
     *
435
     * @return array
436
     */
437
    public function completionAction()
438
    {
439
        $serviceLocator = $this->getServiceLocator();
440
        $job = $this->getJob();
441
442
        $job->setIsDraft(false);
443
444
        $reference = $job->getReference();
445
446
        if (empty($reference)) {
447
            /* @var $repository \Jobs\Repository\Job */
448
            $repository = $this->repositoryService->get('Jobs/Job');
449
            $job->setReference($repository->getUniqueReference());
450
        }
451
        $job->changeStatus(Status::CREATED, "job was created");
452
        $job->setAtsEnabled(true);
453
454
        // sets ATS-Mode on intern
455
        $job->getAtsMode();
456
457
        /*
458
         * make the job opening persist and fire the EVENT_JOB_CREATED
459
         */
460
        $this->repositoryService->store($job);
461
462
        $jobEvents = $serviceLocator->get('Jobs/Events');
463
        $jobEvents->trigger(JobEvent::EVENT_JOB_CREATED, $this, array('job' => $job));
464
465
        return array('job' => $job);
466
    }
467
468
    /**
469
     * all actions around approve or decline jobs-offers
470
     *
471
     * @return array with the viewVariables
472
     */
473
    public function approvalAction()
474
    {
475
476
        $serviceLocator = $this->getServiceLocator();
477
        $user           = $this->auth->getUser();
478
479
        $params         = $this->params('state');
480
        /** @var \Jobs\Entity\Job $jobEntity */
481
        $jobEntity      = $this->getJob();
482
        $jobEvent       = $serviceLocator->get('Jobs/Event');
483
        $jobEvent->setJobEntity($jobEntity);
484
        $jobEvents      = $serviceLocator->get('Jobs/Events');
485
        // array with differences between the last snapshot and the actual entity
486
        // is remains Null if there is no snapshot
487
        // it will be an empty array if the snapshot and the actual entity do not differ
488
        $diff           = null;
489
        // preliminary difference, contain all differences
490
        $prelDiff = $this->entitySnapshot()->diff($jobEntity);
0 ignored issues
show
Documentation Bug introduced by
The method entitySnapshot does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
491
        if (isset($prelDiff)) {
492
            // we want just some Values to be compared
493
            $diff = null;
494
            foreach (array('title', 'organization', 'location',
495
                         'templateValues.qualifications', 'templateValues.requirements', 'templateValues.benefits', 'templateValues.title',
496
                         'templateValues._freeValues.description',
497
                     ) as $prelKey) {
498
                if (array_key_exists($prelKey, $prelDiff)) {
499
                    $diff[$prelKey] = $prelDiff[$prelKey];
500
                }
501
            }
502
        }
503
504 View Code Duplication
        if ($params == 'declined') {
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...
505
            $jobEntity->changeStatus(Status::REJECTED, sprintf(/*@translate*/ "Job opening was rejected by %s", $user->info->displayName));
0 ignored issues
show
Documentation introduced by
The property $info is declared protected in Auth\Entity\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
Accessing displayName on the interface Auth\Entity\InfoInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
506
            $jobEntity->setIsDraft(true);
507
            $this->repositoryService->store($jobEntity);
508
            $jobEvents->trigger(JobEvent::EVENT_JOB_REJECTED, $jobEvent);
509
            $this->notification()->success($this->translator->translate('Job has been rejected'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
510
        }
511
512 View Code Duplication
        if ($params == 'approved') {
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...
513
            $jobEntity->changeStatus(Status::ACTIVE, sprintf(/*@translate*/ "Job opening was activated by %s", $user->info->displayName));
0 ignored issues
show
Documentation introduced by
The property $info is declared protected in Auth\Entity\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
Accessing displayName on the interface Auth\Entity\InfoInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
514
            $this->repositoryService->store($jobEntity);
515
            $jobEvents->trigger(JobEvent::EVENT_JOB_ACCEPTED, $jobEvent);
516
            $this->entitySnapshot($jobEntity);
0 ignored issues
show
Documentation Bug introduced by
The method entitySnapshot does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
517
            $this->notification()->success($this->translator->translate('Job has been approved'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
518
        }
519
520
        $viewLink = $this->url()->fromRoute(
521
            'lang/jobs/view',
522
            array(),
523
            array('query' =>
524
                      array( 'id' => $jobEntity->getId()))
525
        );
526
527
        $approvalLink = $this->url()->fromRoute(
528
            'lang/jobs/approval',
529
            array('state' => 'approved'),
530
            array('query' =>
531
                      array( 'id' => $jobEntity->getId()))
532
        );
533
534
        $declineLink = $this->url()->fromRoute(
535
            'lang/jobs/approval',
536
            array('state' => 'declined'),
537
            array('query' =>
538
                      array( 'id' => $jobEntity->getId()))
539
        );
540
541
        return array('job' => $jobEntity,
542
                     'diffSnapshot' => $diff,
543
                     'viewLink' => $viewLink,
544
                     'approvalLink' => $approvalLink,
545
                     'declineLink' => $declineLink);
546
    }
547
548
    /**
549
     * Deactivate a job posting
550
     *
551
     * @return null|ViewModel
552
     */
553
    public function deactivateAction()
554
    {
555
        $user           = $this->auth->getUser();
556
        $jobEntity      = $this->getJob();
557
558
        try {
559
            $jobEntity->changeStatus(Status::INACTIVE, sprintf(/*@translate*/ "Job was deactivated by %s", $user->getInfo()->getDisplayName()));
560
            $this->notification()->success($this->translator->translate('Job has been deactivated'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
561
        } catch (\Exception $e) {
562
            $this->notification()->danger($this->translator->translate('Job could not be deactivated'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
563
        }
564
        return $this->save(array('page' => 2));
565
    }
566
567
    /**
568
     * Assign a template to a job posting
569
     *
570
     * @return JsonModel
571
     */
572
    public function templateAction()
573
    {
574
        try {
575
            $jobEntity           = $this->getJob();
576
            $jobEntity->setTemplate($this->params('template', 'default'));
577
            $this->repositoryService->store($jobEntity);
578
            $this->notification()->success($this->translator->translate('Template changed'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
579
        } catch (\Exception $e) {
580
            $this->notification()->danger($this->translator->translate('Template not changed'));
0 ignored issues
show
Documentation Bug introduced by
The method notification does not exist on object<Jobs\Controller\ManageController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
581
        }
582
583
        return new JsonModel(array());
584
    }
585
586
    /**
587
     * @param $script
588
     * @param array $parameter
589
     * @return ViewModel
590
     */
591
    protected function getErrorViewModel($script, $parameter = array())
592
    {
593
        $this->getResponse()->setStatusCode(500);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Stdlib\ResponseInterface as the method setStatusCode() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Response, Zend\Http\Response, Zend\Http\Response\Stream.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
594
595
        $model = new ViewModel($parameter);
596
        $model->setTemplate("jobs/error/$script");
597
598
        return $model;
599
    }
600
601
    public function historyAction()
602
    {
603
        $jobEntity      = $this->getJob();
604
        $title          = $jobEntity->title;
0 ignored issues
show
Documentation introduced by
The property $title is declared protected in Jobs\Entity\Job. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
605
        $historyEntity  = $jobEntity->history;
0 ignored issues
show
Documentation introduced by
The property $history is declared protected in Jobs\Entity\Job. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
606
607
        $model = new ViewModel(array('title' => $title, 'history' => $historyEntity));
608
        $model->setTerminal(true);
609
        return $model;
610
    }
611
}