YamlParser::setData()   B
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 14

Duplication

Lines 23
Ratio 100 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 0
Metric Value
dl 23
loc 23
ccs 15
cts 15
cp 1
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 14
nc 4
nop 1
crap 4
1
<?php
2
3
/**
4
 * This file is part of slick/form package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Form\Parser;
11
12
use Slick\Form\Exception\InvalidArgumentException;
13
use Slick\Form\Exception\ParserErrorException;
14
use Slick\Form\FormInterface;
15
use Slick\Form\Parser\Worker\AddElements;
16
use Slick\Form\Parser\Worker\FormId;
17
use Symfony\Component\Yaml\Yaml;
18
19
/**
20
 * Form Definitions Parser
21
 *
22
 * This class is used by the FormRegistry when creating forms
23
 * based on YAML definitions.
24
 *
25
 * @package Slick\Form\Parser
26
 * @author  Filipe Silva <[email protected]>
27
 */
28
class YamlParser implements ParserInterface
29
{
30
31
    /** Default form class to create */
32
    const DEFAULT_FORM_CLASS = 'Slick\Form\Form';
33
34
    /**
35
     * @var array The YAML parser data
36
     */
37
    protected $parsedData;
38
39
    /**
40
     * @var WorkerInterface[]
41
     */
42
    protected static $workers = [
43
        'formId' => FormId::class,
44
        'addElements' => AddElements::class
45
    ];
46
47
    /**
48
     * Crates a definition parser
49
     *
50
     * @param string $definitions The full path for definitions file
51
     */
52 28
    public function __construct($definitions)
53
    {
54 28
        $this->setData($definitions);
55 28
    }
56
57
    /**
58
     * Create form using provided definitions
59
     *
60
     * @param string $definitions
61
     *
62
     * @return FormInterface
63
     */
64 16
    public static function create($definitions)
65
    {
66 16
        $parser = new static($definitions);
67 8
        return $parser->getForm();
68
    }
69
70
    /**
71
     * Gets the resulting form object
72
     *
73
     * @return FormInterface
74
     */
75 20
    public function getForm()
76
    {
77 20
        $form = $this->createForm();
78 12
        $this->workout($form);
79 12
        return $form;
80
    }
81
82
    /**
83
     * Updates the form with definitions from parsed data
84
     *
85
     * @param FormInterface $form
86
     */
87 12
    protected function workout(FormInterface $form)
88
    {
89 12
        foreach (self::$workers as $worker) {
90 12
            call_user_func_array(
91 12
                [$worker, 'execute'],
92 12
                [$form, $this->parsedData]
93 12
            );
94 12
        }
95 12
    }
96
97
    /**
98
     * Creates the form class
99
     *
100
     * @return FormInterface
101
     */
102 20
    protected function createForm()
103
    {
104 20
        $class = self::DEFAULT_FORM_CLASS;
105 20
        if (array_key_exists('class', $this->parsedData)) {
106 14
            $class = $this->checkClass($this->parsedData['class']);
107 6
        }
108
109 12
        return new $class;
110
    }
111
112 14
    protected function checkClass($name)
113
    {
114 14
        if (! class_exists($name)) {
115 4
            throw new InvalidArgumentException(
116 4
                "The form class '{$name}' does not exists."
117 4
            );
118
        }
119
120 10
        if (! is_subclass_of($name, FormInterface::class)) {
121 4
            throw new InvalidArgumentException(
122 4
                "The class '{$name}' does not implements the " .
123
                "FormInterface interface"
124 4
            );
125
        }
126 6
        return $name;
127
    }
128
129
    /**
130
     * Sets definition data for form creation
131
     *
132
     * @param mixed $definitions
133
     *
134
     * @return self|$this|ParserInterface
135
     */
136 14 View Code Duplication
    public function setData($definitions)
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...
137
    {
138 14
        if (is_array($definitions)) {
139 4
            $this->parsedData = $definitions;
140 4
            return;
141
        }
142
143 14
        if (!is_file($definitions)) {
144 2
            throw new InvalidArgumentException(
145 2
                "The form definition file '{$definitions}' does not exists."
146 2
            );
147
        }
148
149
        try {
150 14
            $this->parsedData = Yaml::parse(file_get_contents($definitions));
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Yaml\...contents($definitions)) can also be of type string or object<stdClass>. However, the property $parsedData is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
151 14
        } catch (\Exception $caught) {
152 2
            throw new ParserErrorException(
153 2
                'Error parsing form definitions: '.$caught->getMessage(),
154 2
                0,
155
                $caught
156 2
            );
157
        }
158
    }
159
}