ActionField::render()   B
last analyzed

Complexity

Conditions 4
Paths 8

Size

Total Lines 25
Code Lines 15

Duplication

Lines 5
Ratio 20 %

Importance

Changes 0
Metric Value
dl 5
loc 25
c 0
b 0
f 0
rs 8.5806
cc 4
eloc 15
nc 8
nop 2
1
<?php
2
namespace rtens\domin\delivery\web\fields;
3
4
use rtens\domin\Action;
5
use rtens\domin\ActionRegistry;
6
use rtens\domin\delivery\FieldRegistry;
7
use rtens\domin\delivery\web\Element;
8
use rtens\domin\delivery\web\WebField;
9
use rtens\domin\Parameter;
10
use watoki\reflect\type\ClassType;
11
12
class ActionField implements WebField {
13
14
    /** @var FieldRegistry */
15
    private $fields;
16
17
    /** @var ActionRegistry */
18
    private $actions;
19
20
    public function __construct(FieldRegistry $fields, ActionRegistry $actions) {
21
        $this->fields = $fields;
22
        $this->actions = $actions;
23
    }
24
25
    /**
26
     * @param Parameter $parameter
27
     * @return bool
28
     */
29
    public function handles(Parameter $parameter) {
30
        $type = $parameter->getType();
31
        return $type instanceof ClassType && is_subclass_of($type->getClass(), Action::class);
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \rtens\domin\Action::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
32
    }
33
34
    /**
35
     * @param Parameter $parameter
36
     * @param mixed[] $values
37
     * @return string
38
     * @throws \Exception
39
     */
40
    public function render(Parameter $parameter, $values) {
41
        $errors = $values['errors'];
42
        $values = $values['inflated'];
43
44
        $action = $this->actions->getAction($parameter->getName());
45
        $values = $action->fill($values);
46
47
        $body = [];
48
49 View Code Duplication
        if ($action->description()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $action->description() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
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...
50
            $body[] = new Element('div', ['class' => 'well'], [
51
                $action->description()
52
            ]);
53
        }
54
55
        foreach ($action->parameters() as $parameter) {
56
            $value = $this->get($parameter, $values);
57
            $error = $this->get($parameter, $errors);
58
59
            $body[] = new Element('div', ['class' => 'form-group'],
60
                $this->makeFormGroup($parameter, $value, $error));
61
        }
62
63
        return $body ? (string)new Element('div', [], $body) : '';
64
    }
65
66
    private function makeFormGroup(Parameter $parameter, $value, \Exception $error = null) {
67
        $formGroup = [
68
            new Element('label', [], [
69
                $this->makeLabel($parameter) . ($parameter->isRequired() ? '*' : '')
70
            ])
71
        ];
72
73
        if ($parameter->getDescription()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parameter->getDescription() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
74
            $formGroup[] = new Element('a', ['class' => 'description'], [
75
                new Element('span', ['class' => 'glyphicon glyphicon-question-sign'])
76
            ]);
77
            $formGroup[] = new Element('div', ['class' => 'description-content sr-only'], [
78
                $parameter->getDescription()
79
            ]);
80
        }
81
82 View Code Duplication
        if ($error) {
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...
83
            $formGroup[] = new Element('div', ['class' => 'alert alert-danger'], [
84
                $error->getMessage()
85
            ]);
86
        }
87
88
        $field = $this->fields->getField($parameter);
89
90
        if (!($field instanceof WebField)) {
91
            throw new \Exception("[$parameter] is not a WebField");
92
        }
93
94
        $formGroup[] = $field->render($parameter, $value);
95
        return $formGroup;
96
    }
97
98
    /**
99
     * @param $parameter
100
     * @return mixed
101
     */
102
    protected function makeLabel(Parameter $parameter) {
103
        return ucfirst(preg_replace('/(.)([A-Z0-9])/', '$1 $2', $parameter->getName()));
104
    }
105
106
    /**
107
     * @param Parameter $parameter
108
     * @param string $serialized
109
     * @return mixed
110
     */
111
    public function inflate(Parameter $parameter, $serialized) {
112
        return null;
113
    }
114
115
    /**
116
     * @param Parameter $parameter
117
     * @return array|\rtens\domin\delivery\web\Element[]
118
     */
119
    public function headElements(Parameter $parameter) {
120
        $action = $this->actions->getAction($parameter->getName());
121
122
        $headElements = [
123
            self::descriptionCode()
124
        ];
125
126
        foreach ($action->parameters() as $parameter) {
127
            $field = $this->fields->getField($parameter);
128
            if ($field instanceof WebField) {
129
                $headElements = array_merge($headElements, $field->headElements($parameter));
130
            }
131
        }
132
        return $headElements;
133
    }
134
135
    private static function descriptionCode() {
136
        return new Element('script', [], ["
137
                $(function () {
138
                    $('.description').popover({
139
                        trigger: 'hover',
140
                        delay: {show: 100, hide: 1000},
141
                        html: true,
142
                        placement: 'auto top',
143
                        content: function () {
144
                            return $(this).siblings('.description-content').html();
145
                        }
146
                    });
147
                });"
148
        ]);
149
    }
150
151
    private function get(Parameter $parameter, $array) {
152
        if (isset($array[$parameter->getName()])) {
153
            return $array[$parameter->getName()];
154
        }
155
        return null;
156
    }
157
}