Completed
Branch feature/job-plans (e266db)
by Adam
05:31
created

JobForm   B

Complexity

Total Complexity 19

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 16

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 333
rs 8.4614
wmc 19
lcom 2
cbo 16

5 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 84 9
B buildForm() 0 154 1
A setupDefaultValues() 0 11 4
A setupPlanFields() 0 20 2
A geocode() 0 20 3
1
<?php
2
3
namespace Coyote\Http\Forms\Job;
4
5
use Coyote\Country;
6
use Coyote\Currency;
7
use Coyote\Job;
8
use Coyote\Repositories\Contracts\FeatureRepositoryInterface as FeatureRepository;
9
use Coyote\Services\FormBuilder\Form;
10
use Coyote\Services\FormBuilder\FormEvents;
11
use Coyote\Services\Geocoder\GeocoderInterface;
12
use Coyote\Services\Parser\Helpers\City;
13
use Coyote\Tag;
14
use Illuminate\Validation\Rule;
15
16
class JobForm extends Form
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $theme = self::THEME_INLINE;
22
23
    /**
24
     * @var Job
25
     */
26
    protected $data;
27
28
    /**
29
     * It's public so we can use use attr from twig
30
     *
31
     * @var array
32
     */
33
    public $attr = [
34
        'method' => self::POST,
35
    ];
36
37
    /**
38
     * @var GeocoderInterface
39
     */
40
    private $geocoder;
41
42
    /**
43
     * @var FeatureRepository
44
     */
45
    private $feature;
46
47
    /**
48
     * @param GeocoderInterface $geocoder
49
     * @param FeatureRepository $feature
50
     */
51
    public function __construct(GeocoderInterface $geocoder, FeatureRepository $feature)
52
    {
53
        parent::__construct();
54
55
        $this->geocoder = $geocoder;
56
        $this->feature = $feature;
57
58
        $this->addEventListener(FormEvents::POST_SUBMIT, function (JobForm $form) {
59
            // call macro and flush collection items
60
            $this->data->tags->flush();
61
            $this->data->locations->flush();
0 ignored issues
show
Bug introduced by
The method flush cannot be called on $this->data->locations (of type array<integer,object<Coyote\Job\Location>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
62
            $this->data->features->flush();
0 ignored issues
show
Bug introduced by
The method flush cannot be called on $this->data->features (of type array<integer,object<Coyote\Feature>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
63
64
            foreach ($form->get('tags')->getChildrenValues() as $tag) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChildrenValues() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Collection. 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...
65
                $pivot = $this->data->tags()->newPivot(['priority' => $tag['priority']]);
66
                $model = (new Tag($tag))->setRelation('pivot', $pivot);
67
68
                $this->data->tags->add($model);
0 ignored issues
show
Bug introduced by
The method add cannot be called on $this->data->tags (of type array<integer,object<Coyote\Tag>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
69
            }
70
71
            foreach ($form->get('features')->getChildrenValues() as $feature) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChildrenValues() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Collection. 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...
72
                $checked = (int) $feature['checked'];
73
74
                $pivot = $this->data->features()->newPivot([
75
                    'checked'       => $checked,
76
                    'value'         => $checked ? ($feature['value'] ?? null) : null
77
                ]);
78
79
                $model = $this->feature->find($feature['id'])->setRelation('pivot', $pivot);
80
81
                $this->data->features->add($model);
0 ignored issues
show
Bug introduced by
The method add cannot be called on $this->data->features (of type array<integer,object<Coyote\Feature>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
82
            }
83
84
            $cities = (new City())->grab($form->get('city')->getValue());
85
86
            foreach ($cities as $city) {
87
                $this->data->locations->add(new Job\Location($this->geocode($city)));
88
            }
89
90
            $this->data->country()->associate((new Country())->find($form->get('country_id')->getValue()));
1 ignored issue
show
Security Code Execution introduced by
$form->get('country_id')->getValue() can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

9 paths for user data to reach this point

  1. Path: Read from $_SERVER in src/Illuminate/Foundation/Bootstrap/SetRequestForConsole.php on line 19
  1. Read from $_SERVER
    in vendor/src/Illuminate/Foundation/Bootstrap/SetRequestForConsole.php on line 19
  2. Data is passed through array_replace()
    in vendor/Request.php on line 360
  3. Data is passed through call_user_func()
    in vendor/Request.php on line 2003
  4. \Illuminate\Http\Request::create($app->make('config')->get('app.url', 'http://localhost'), 'GET', array(), array(), array(), $_SERVER) is passed to Container::instance()
    in vendor/src/Illuminate/Foundation/Bootstrap/SetRequestForConsole.php on line 18
  5. Container::$instances is assigned
    in vendor/src/Illuminate/Container/Container.php on line 371
  6. Tainted property Container::$instances is read
    in vendor/src/Illuminate/Container/Container.php on line 597
  7. Container::resolve() returns tainted data
    in vendor/src/Illuminate/Container/Container.php on line 575
  8. Container::make() returns tainted data
    in vendor/src/Illuminate/Foundation/helpers.php on line 107
  9. app() returns tainted data, and $factory is assigned
    in vendor/src/Illuminate/Foundation/helpers.php on line 915
  10. view() returns tainted data, and view('job.partials.application', compact('job')) is passed to Field::setValue()
    in app/Http/Controllers/Job/ApplicationController.php on line 60
  11. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  12. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  13. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  2. Path: $this->parameters['HTTP_AUTHORIZATION'] seems to return tainted data, and $authorizationHeader is assigned in ServerBag.php on line 62
  1. $this->parameters['HTTP_AUTHORIZATION'] seems to return tainted data, and $authorizationHeader is assigned
    in vendor/ServerBag.php on line 62
  2. ParameterBag::$parameters is assigned
    in vendor/ServerBag.php on line 77
  3. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  4. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  5. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  6. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  7. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  8. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  9. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  10. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  11. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  12. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  13. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  14. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  15. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  16. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  3. Path: Read from $_POST, and $_POST is passed to Request::createRequestFromFactory() in Request.php on line 317
  1. Read from $_POST, and $_POST is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  2. $request is passed to Request::__construct()
    in vendor/Request.php on line 2012
  3. $request is passed to Request::initialize()
    in vendor/Request.php on line 258
  4. $request is passed to ParameterBag::__construct()
    in vendor/Request.php on line 276
  5. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  6. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  7. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  8. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  9. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  10. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  11. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  12. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  13. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  14. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  15. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  16. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  17. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  18. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  19. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  4. Path: Read from $_SERVER, and $server is assigned in Request.php on line 307
  1. Read from $_SERVER, and $server is assigned
    in vendor/Request.php on line 307
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2012
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  8. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  9. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  10. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  11. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  12. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  13. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  14. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  15. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  16. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  17. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  18. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  19. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  20. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  5. Path: Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned in Request.php on line 310
  1. Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned
    in vendor/Request.php on line 310
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2012
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  8. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  9. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  10. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  11. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  12. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  13. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  14. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  15. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  16. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  17. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  18. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  19. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  20. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  6. Path: Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned in Request.php on line 313
  1. Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned
    in vendor/Request.php on line 313
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2012
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  8. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  9. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  10. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  11. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  12. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  13. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  14. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  15. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  16. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  17. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  18. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  19. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  20. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  7. Path: $server['HTTP_HOST'] seems to return tainted data, and $server is assigned in Request.php on line 383
  1. $server['HTTP_HOST'] seems to return tainted data, and $server is assigned
    in vendor/Request.php on line 383
  2. $server is assigned
    in vendor/Request.php on line 431
  3. $server is assigned
    in vendor/Request.php on line 432
  4. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 434
  5. $server is passed to Request::__construct()
    in vendor/Request.php on line 2012
  6. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  7. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  8. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  9. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  10. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  11. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  12. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  13. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  14. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  15. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  16. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  17. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  18. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  19. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  20. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  21. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  22. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  8. Path: $this->parameters['PHP_AUTH_USER'] seems to return tainted data, and $headers is assigned in ServerBag.php on line 43
  1. $this->parameters['PHP_AUTH_USER'] seems to return tainted data, and $headers is assigned
    in vendor/ServerBag.php on line 43
  2. $headers is assigned
    in vendor/ServerBag.php on line 44
  3. ServerBag::getHeaders() returns tainted data, and $this->server->getHeaders() is passed to HeaderBag::__construct()
    in vendor/Request.php on line 282
  4. $values is assigned
    in vendor/HeaderBag.php on line 31
  5. $values is passed to HeaderBag::set()
    in vendor/HeaderBag.php on line 32
  6. (array) $values is passed through array_values(), and $values is assigned
    in vendor/HeaderBag.php on line 143
  7. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  8. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  9. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  10. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1782
  11. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1813
  12. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  13. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  14. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  15. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  16. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  17. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  18. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  19. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  20. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  21. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  22. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  23. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  24. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  25. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  26. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90
  9. Path: $this->parameters['PHP_AUTH_PW'] seems to return tainted data, and $headers is assigned in ServerBag.php on line 44
  1. $this->parameters['PHP_AUTH_PW'] seems to return tainted data, and $headers is assigned
    in vendor/ServerBag.php on line 44
  2. ServerBag::getHeaders() returns tainted data, and $this->server->getHeaders() is passed to HeaderBag::__construct()
    in vendor/Request.php on line 282
  3. $values is assigned
    in vendor/HeaderBag.php on line 31
  4. $values is passed to HeaderBag::set()
    in vendor/HeaderBag.php on line 32
  5. (array) $values is passed through array_values(), and $values is assigned
    in vendor/HeaderBag.php on line 143
  6. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  7. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  8. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  9. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1782
  10. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1813
  11. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  12. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 45
  13. ParameterBag::all() returns tainted data, and $bag->all() is passed to TransformsRequest::cleanArray()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 58
  14. $data is passed to collect()
    in vendor/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php on line 69
  15. $value is passed to Collection::__construct()
    in vendor/src/Illuminate/Support/helpers.php on line 379
  16. Collection::$items is assigned
    in vendor/src/Illuminate/Support/Collection.php on line 47
  17. Tainted property Collection::$items is read
    in vendor/src/Illuminate/Support/Collection.php on line 88
  18. Collection::all() returns tainted data, and $values is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 52
  19. $values is passed through array_merge(), and $results is assigned
    in vendor/src/Illuminate/Support/Arr.php on line 57
  20. Arr::collapse() returns tainted data
    in vendor/src/Illuminate/Support/helpers.php on line 425
  21. data_get() returns tainted data
    in vendor/src/Illuminate/Http/Concerns/InteractsWithInput.php on line 133
  22. InteractsWithInput::input() returns tainted data, and $request->input('parentId') is passed to Field::setValue()
    in app/Http/Controllers/Wiki/SubmitController.php on line 26
  23. Field::$value is assigned
    in app/Services/FormBuilder/Fields/Field.php on line 142
  24. Tainted property Field::$value is read
    in app/Services/FormBuilder/Fields/Field.php on line 132
  25. Field::getValue() returns tainted data
    in app/Http/Forms/Job/JobForm.php on line 90

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
91
        });
92
93
        $this->addEventListener(FormEvents::PRE_RENDER, function (JobForm $form) {
94
            $session = $form->getRequest()->session();
95
96
            if ($session->hasOldInput('tags')) {
0 ignored issues
show
Bug introduced by
The method hasOldInput() does not seem to exist on object<Symfony\Component...ssion\SessionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
97
                $assoc = [];
98
99
                foreach ($form->get('tags')->getChildrenValues() as $tag) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChildrenValues() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Collection. 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...
100
                    $assoc[] = [
101
                        'name' => $tag['name'],
102
                        'pivot' => [
103
                            'priority' => $tag['priority']
104
                        ]
105
                    ];
106
                }
107
108
                $form->get('tags')->setValue($assoc);
109
            }
110
111
            if ($session->hasOldInput('features')) {
0 ignored issues
show
Bug introduced by
The method hasOldInput() does not seem to exist on object<Symfony\Component...ssion\SessionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
112
                $assoc = [];
113
114
                foreach ($form->get('features')->getChildrenValues() as $feature) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChildrenValues() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Collection. 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...
115
                    $assoc[] = [
116
                        'id' => $feature['id'],
117
                        'name' => $feature['name'],
118
                        'default' => $feature['default'],
119
                        'pivot' => [
120
                            'checked' => (int) $feature['checked'],
121
                            'value' => $feature['value'] ?? ''
122
                        ]
123
                    ];
124
                }
125
126
                $form->get('features')->setValue($assoc);
127
            }
128
129
            // tags as json (for vue.js)
130
            $form->get('tags')->setValue(collect($form->get('tags')->getChildrenValues())->toJson());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChildrenValues() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Collection. 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...
131
            // features as json (for vue.js)
132
            $form->get('features')->setValue(collect($form->get('features')->getChildrenValues())->toJson());
133
        });
134
    }
135
136
    public function buildForm()
137
    {
138
        $this
139
            ->setAttr(['class' => 'submit-form', 'v-cloak' => 'v-cloak'])
140
            ->setUrl(route('job.submit'))
141
            ->add('id', 'hidden')
142
            ->add('slug', 'hidden')
143
            ->add('firm_id', 'hidden')
144
            ->add('title', 'text', [
145
                'rules' => 'min:2|max:60',
146
                'label' => 'Tytuł oferty',
147
                'required' => true,
148
                'help' => 'Pozostało <strong>${ charCounter(\'job.title\', 60) }</strong> znaków',
149
                'attr' => [
150
                    'placeholder' => 'Np. Senior Java Developer',
151
                    'maxlength' => 60,
152
                    'v-model' => 'job.title'
153
                ],
154
                'row_attr' => [
155
                    'class' => 'col-sm-9'
156
                ]
157
            ])
158
            ->add('seniority_id', 'select', [
159
                'rules' => 'integer',
160
                'label' => 'Staż pracy',
161
                'choices' => Job::getSeniorityList(),
162
                'empty_value' => '--',
163
                'row_attr' => [
164
                    'class' => 'col-sm-2'
165
                ]
166
            ])
167
            ->add('country_id', 'select', [
168
                'rules' => 'required|integer',
169
                'choices' => Country::getCountriesList()
170
            ])
171
            ->add('city', 'text', [
172
                'rules' => 'string|city',
173
                'attr' => [
174
                    'placeholder' => 'Np. Wrocław, Warszawa'
175
                ]
176
            ])
177
            ->add('is_remote', 'checkbox', [
178
                'label' => 'Możliwa praca zdalna w zakresie',
179
                'rules' => 'bool',
180
                'attr' => [
181
                    'id' => 'remote'
182
                ],
183
                'label_attr' => [
184
                    'for' => 'remote'
185
                ]
186
            ])
187
            ->add('remote_range', 'select', [
188
                'rules' => 'integer|min:10|max:100',
189
                'choices' => Job::getRemoteRangeList(),
190
                'attr' => [
191
                    'placeholder' => '--',
192
                    'class' => 'input-sm input-inline',
193
                    'style' => 'width: 100px'
194
                ]
195
            ])
196
            ->add('salary_from', 'text', [
197
                'rules' => 'integer',
198
                'help' => 'Podanie tych informacji nie jest obowiązkowe, ale dzięki temu Twoja oferta zainteresuje więcej osób. Obiecujemy!',
199
                'attr' => [
200
                    'class' => 'input-inline'
201
                ]
202
            ])
203
            ->add('salary_to', 'text', [
204
                'rules' => 'integer',
205
                'attr' => [
206
                    'class' => 'input-inline'
207
                ]
208
            ])
209
            ->add('is_gross', 'select', [
210
                'rules' => 'required|boolean',
211
                'choices' => Job::getTaxList(),
212
                'attr' => [
213
                    'class' => 'input-inline'
214
                ]
215
            ])
216
            ->add('currency_id', 'select', [
217
                'rules' => 'required|integer',
218
                'choices' => Currency::getCurrenciesList(),
219
                'attr' => [
220
                    'class' => 'input-inline'
221
                ]
222
            ])
223
            ->add('rate_id', 'select', [
224
                'rules' => 'required|integer',
225
                'choices' => Job::getRatesList(),
226
                'attr' => [
227
                    'class' => 'input-inline'
228
                ]
229
            ])
230
            ->add('employment_id', 'select', [
231
                'rules' => 'required|integer',
232
                'choices' => Job::getEmploymentList(),
233
                'attr' => [
234
                    'class' => 'input-inline'
235
                ]
236
            ])
237
            ->add('deadline', 'number', [
238
                'label' => 'Data ważnosci oferty',
239
                'rules' => 'integer|min:1|max:365',
240
                'help' => 'Oferta będzie widoczna na stronie do dnia <strong>${ deadlineDate }</strong>',
241
                'attr' => [
242
                    'min' => 1,
243
                    'max' => 365,
244
                    'class' => 'input-inline',
245
                    'v-model' => 'job.deadline'
246
                ]
247
            ])
248
            ->add('tags', 'collection', [
249
                'child_attr' => [
250
                    'type' => 'child_form',
251
                    'class' => TagsForm::class
252
                ]
253
            ])
254
            ->add('features', 'collection', [
255
                'label' => 'Narzędzia oraz metodologia pracy',
256
                'help' => 'Zaznaczenie tych pól nie jest obowiązkowe, jednak wpływaja one na pozycję oferty na liście wyszukiwania.',
257
                'child_attr' => [
258
                    'type' => 'child_form',
259
                    'class' => FeaturesForm::class
260
                ]
261
            ])
262
            ->add('description', 'textarea', [
263
                'label' => 'Opis oferty (opcjonalnie)',
264
                'help' => 'Miejsce na szczegółowy opis oferty. Pole to jednak nie jest wymagane.',
265
                'style' => 'height: 140px',
266
                'row_attr' => [
267
                    'class' => 'form-group-border'
268
                ]
269
            ])
270
            ->add('enable_apply', 'choice', [
271
                'multiple' => false,
272
                'choices' => [
273
274
                    true => 'Zezwól na wysyłanie CV poprzez serwis 4programmers.net',
275
                    false => '...lub podaj informacje w jaki sposób kandydaci mogą aplikować na to stanowisko',
276
                ]
277
            ])
278
            ->add('recruitment', 'textarea', [
279
                'rules' => 'required_if:enable_apply,0|string',
280
                'style' => 'height: 40px'
281
            ])
282
            ->add('email', 'email', [
283
                'rules' => 'sometimes|required|email',
284
                'help' => 'Podaj adres e-mail na jaki wyślemy Ci informacje o kandydatach. Adres e-mail nie będzie widoczny dla osób postronnych.'
285
            ]);
286
287
        $this->setupPlanFields();
288
        $this->setupDefaultValues();
289
    }
290
291
    protected function setupDefaultValues()
292
    {
293
        // default attributes only if model does not exist and wasn't filled before.
294
        if (!$this->data->exists && !$this->data->isDirty(['title']) && !$this->isSubmitted()) {
295
            $this->get('email')->setValue($this->request->user()->email);
296
297
            // @todo Uzyc mechanizmu geolokalizacji
298
            $this->get('country_id')->setValue(array_search('Polska', $this->get('country_id')->getChoices()));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Coyote\Services\FormBuilder\Fields\Field as the method getChoices() does only exist in the following sub-classes of Coyote\Services\FormBuilder\Fields\Field: Coyote\Services\FormBuilder\Fields\Choice, Coyote\Services\FormBuilder\Fields\Select. 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...
299
            $this->get('remote_range')->setValue(100);
300
        }
301
    }
302
303
    protected function setupPlanFields()
304
    {
305
        // can't show that fields if plan is enabled
306
        if ($this->data->isPlanOngoing()) {
307
            return;
308
        }
309
310
        $this
311
            ->add('plan_id', 'hidden', [
312
                'rules' => [
313
                    'required',
314
                    'int',
315
                    Rule::exists('plans', 'id')->where('is_active', 1)
316
                ],
317
                'attr' => [
318
                    'id' => 'plan_id',
319
                    'v-model' => 'job.plan_id'
320
                ]
321
            ]);
322
    }
323
324
    /**
325
     * @param string $city
326
     * @return array
327
     */
328
    private function geocode($city)
329
    {
330
        $location = [
331
            'city'          => $city
332
        ];
333
334
        try {
335
            $location = $this->geocoder->geocode($city);
336
337
            if (!$location->city) {
338
                $location->city = $city;
339
            }
340
341
            $location = $location->toArray();
342
        } catch (\Exception $e) {
343
            logger()->error($e->getMessage());
344
        }
345
346
        return $location;
347
    }
348
}
349