ArrayField   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
dl 0
loc 155
c 0
b 0
f 0
wmc 14
lcom 1
cbo 8
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A handles() 0 3 1
A inflate() 0 12 2
B render() 0 47 4
A makeInputGroup() 0 19 1
A headElements() 0 15 2
A itemHeadElements() 0 5 1
A numberOfNewItems() 0 3 1
A makeInnerParameter() 0 5 1
1
<?php
2
namespace rtens\domin\delivery\web\fields;
3
4
use rtens\domin\delivery\FieldRegistry;
5
use rtens\domin\delivery\web\MobileDetector;
6
use rtens\domin\Parameter;
7
use rtens\domin\delivery\web\Element;
8
use rtens\domin\delivery\web\HeadElements;
9
use rtens\domin\delivery\web\WebField;
10
use watoki\reflect\type\ArrayType;
11
12
class ArrayField implements WebField {
13
14
    const EMPTY_LIST_VALUE = '_____EMPTY_LIST_____';
15
16
    /** @var FieldRegistry */
17
    private $fields;
18
19
    /** @var MobileDetector */
20
    private $mobile;
21
22
    public function __construct(FieldRegistry $fields, MobileDetector $mobile) {
23
        $this->fields = $fields;
24
        $this->mobile = $mobile;
25
    }
26
27
    /**
28
     * @param Parameter $parameter
29
     * @return bool
30
     */
31
    public function handles(Parameter $parameter) {
32
        return $parameter->getType() instanceof ArrayType;
33
    }
34
35
    /**
36
     * @param Parameter $parameter
37
     * @param array $serialized
38
     * @return array
39
     */
40
    public function inflate(Parameter $parameter, $serialized) {
41
        $itemParameter = $this->makeInnerParameter($parameter);
42
43
        $serialized = array_values($serialized);
44
        if ($serialized[0] == self::EMPTY_LIST_VALUE) {
45
            $serialized = array_values(array_slice($serialized, 1));
46
        }
47
        $serialized = array_map(function ($item) use ($itemParameter) {
48
            return $this->fields->getField($itemParameter)->inflate($itemParameter, $item);
49
        }, $serialized);
50
        return $serialized;
51
    }
52
53
    /**
54
     * @param Parameter $parameter
55
     * @param mixed $value
56
     * @return string
57
     */
58
    public function render(Parameter $parameter, $value) {
59
        if (!$value) {
60
            $value = [];
61
        }
62
63
        $id = str_replace(['[', ']'], '-', $parameter->getName());
64
65
        /** @var WebField $innerField */
66
        $innerField = $this->fields->getField($this->makeInnerParameter($parameter));
67
68
        $items = [
69
            new Element('input', [
70
                'type' => 'hidden',
71
                'name' => $parameter->getName() . '[0]',
72
                'value' => self::EMPTY_LIST_VALUE
73
            ])
74
        ];
75
76
        $index = 1;
77
        foreach ($value as $item) {
78
            $items[] = $this->makeInputGroup($innerField, $this->makeInnerParameter($parameter, '[' . $index++ . ']'), $id, $item);
79
        }
80
81
        $newItems = [];
82
        for ($i = 0; $i < $this->numberOfNewItems(); $i++) {
83
            $newItems[] = $this->makeInputGroup($innerField, $this->makeInnerParameter($parameter, '[' . $index++ . ']'), $id);
84
        }
85
86
        return (string)new Element('div', [], [
87
            new Element('div', [], [
88
                new Element('div', [
89
                    'id' => "$id-items",
90
                    'class' => 'array-items'
91
                ], $items),
92
93
                new Element('button', [
94
                    'class' => 'btn btn-success',
95
                    'onclick' => "$('#$id-new-items').children().first().appendTo('#$id-items'); return false;"
96
                ], ['Add']),
97
98
                new Element('div', [
99
                    'id' => "$id-new-items",
100
                    'class' => 'array-new-items hidden'
101
                ], $newItems)
102
            ])
103
        ]);
104
    }
105
106
    private function makeInputGroup(WebField $field, Parameter $parameter, $id, $value = null) {
107
        return new Element('div', [
108
            'class' => 'array-item form-group input-group',
109
            'style' => 'width: 100%'
110
        ], [
111
            new Element('span', ['class' => 'sortable-handle input-group-addon'], [
112
                new Element('span', ['class' => 'glyphicon glyphicon-sort'])
113
            ]),
114
            $field->render($parameter, $value),
115
            new Element('span', [
116
                'class' => 'input-group-btn'
117
            ], [
118
                new Element('button', [
119
                    'class' => 'btn btn-danger',
120
                    'onclick' => "$(this).closest('.array-item').prependTo('#$id-new-items'); return false;"
121
                ], ['X'])
122
            ])
123
        ]);
124
    }
125
126
    /**
127
     * @param Parameter $parameter
128
     * @return array|Element[]
129
     */
130
    public function headElements(Parameter $parameter) {
131
        return array_merge([
132
            HeadElements::jquery(),
133
            HeadElements::jqueryUi(),
134
            new Element('script', [], [
135
                "$(function () {
136
                    $('.array-new-items').appendTo('body');
137
                    $('.array-items').sortable({handle:'.sortable-handle'});
138
                    $('.array-items .sortable-handle').disableSelection();
139
                });"
140
            ])
141
        ], $this->mobile->isMobile() ? [
142
            HeadElements::script('//cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js'),
143
        ] : [], $this->itemHeadElements($this->makeInnerParameter($parameter)));
144
    }
145
146
    private function itemHeadElements(Parameter $itemParameter) {
147
        /** @var WebField $field */
148
        $field = $this->fields->getField($itemParameter);
149
        return $field->headElements($itemParameter);
150
    }
151
152
    protected function numberOfNewItems() {
153
        return 10;
154
    }
155
156
    /**
157
     * @param Parameter $parameter
158
     * @param string $suffix
159
     * @return Parameter
160
     */
161
    private function makeInnerParameter(Parameter $parameter, $suffix = '') {
162
        /** @var ArrayType $type */
163
        $type = $parameter->getType();
164
        return new Parameter($parameter->getName() . $suffix, $type->getItemType());
165
    }
166
}