Completed
Pull Request — master (#81)
by Klochok
15:21
created

InternalObjectCombo::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace hipanel\widgets\combo;
4
5
use hiqdev\combo\Combo;
6
use ReflectionClass;
7
use yii\base\InvalidConfigException;
8
use yii\bootstrap\Html;
9
use yii\web\View;
10
11
/**
12
 * Class InternalObjectCombo
13
 */
14
class InternalObjectCombo extends Combo
15
{
16
    /** {@inheritdoc} */
17
    public $type = 'hipanel/object';
18
19
    /** {@inheritdoc} */
20
    public $name;
21
22
    /** {@inheritdoc} */
23
    public $url;
24
25
    /** {@inheritdoc} */
26
    public $_return;
27
28
    /** {@inheritdoc} */
29
    public $_rename;
30
31
    /** {@inheritdoc} */
32
    public $_primaryFilter;
33
34
    /**
35
     * @uses ObjectCombo::getClasses()
36
     *
37
     * @var array
38
     */
39
    public $classes = [];
40
41
    /**
42
     * @var string
43
     */
44
    public $class_attribute;
45
46
    /**
47
     * @var string
48
     */
49
    public $class_attribute_name;
50
51
    /**
52
     * @var array
53
     */
54
    private $requiredAttributes = [];
55
56
    /** {@inheritdoc} */
57
    public function init()
58
    {
59
        if (empty($this->classes)) {
60
            throw new InvalidConfigException('Property `classes` is required for class InternalObjectCombo.');
61
        }
62
        $this->inputOptions = ['data-object-selector-field' => true, 'class' => 'object-selector-select'];
63
        $this->registerSpecialAssets();
64
        $this->fillRequiredAttributes();
65
        $this->generateConfigs();
66
        parent::init();
67
        $this->registerChangerScript();
68
        $this->applyDefaultAttributes();
69
    }
70
71
    private function generateConfigs()
72
    {
73
        foreach ($this->classes as $className => $options) {
74
            $this->applyConfigByObjectClassName($className);
75
        }
76
77
    }
78
79
    private function registerChangerScript()
80
    {
81
        $changerId = Html::getInputId($this->model, $this->class_attribute_name);
82
        $inputId = $this->inputOptions['id'];
83
84
        $this->view->registerJs("initObjectSelectorChanger('{$changerId}', '{$inputId}')");
85
    }
86
87
    private function applyConfigByObjectClassName($className)
88
    {
89
        $options = $this->classes[$className];
90
        if ($options['comboOptions']) {
91
            foreach ($this->requiredAttributes as $attribute) {
92
                if (isset($options['comboOptions'][$attribute->name])) {
93
                    $this->{$attribute->name} = $options['comboOptions'][$attribute->name];
94
                }
95
            }
96
        }
97
        $this->registerClientConfig();
98
        $varName = strtolower($this->model->formName()) . '_object_id_' . $className;
99
        $this->view->registerJsVar($varName, $this->configId, View::POS_END);
100
        $this->reset();
101
    }
102
103
    private function fillRequiredAttributes()
104
    {
105
        $this->requiredAttributes = array_filter((new ReflectionClass(get_class($this)))->getProperties(), function ($attr) {
106
            return $attr->class === get_class($this);
107
        });
108
    }
109
110
    private function applyDefaultAttributes()
111
    {
112
        $this->applyConfigByObjectClassName($this->class_attribute ?: 'client');
113
    }
114
115
    private function registerSpecialAssets()
116
    {
117
        // Fix validation styles
118
        $this->view->registerCss("
119
            .form-group.has-error .select2-selection { border-color: #dd4b39; box-shadow: none; }
120
            .form-group.has-success .select2-selection { border-color: #00a65a; box-shadow: none; }
121
            select.object-selector-select:not([data-select2-id]) { display: none; }
122
        ");
123
        $this->view->registerJs(<<<'JS'
124
            (function( $ ){
125
126
                var originalDynamicForm = $.fn.yiiDynamicForm;
127
                
128
                var methods = {
129
                    addItem : function(widgetOptions, e, elem) { 
130
                        originalDynamicForm('addItem', widgetOptions, e, elem);
131
                        var count = elem.closest('.' + widgetOptions.widgetContainer).find(widgetOptions.widgetItem).length;
132
133
                        // Reinit ObjectSelectorChanger after added new item
134
                        if (count < widgetOptions.limit) {
135
                            var objectSelectorInputs = $($newclone).find('[data-object-selector-field]');
136
                            objectSelectorInputs.each(function() {
137
                                var objectInputId = $(this).attr('id');
138
                                var changerInputId = $(this).prev('select').attr('id');
139
                                initObjectSelectorChanger(changerInputId, objectInputId);
140
                                $('#' + objectInputId).find('option').remove().end().val(null).trigger('change');
141
                            });
142
                        } 
143
                    }
144
                };
145
                
146
                $.fn.yiiDynamicForm = function(method) {
147
                    if (method === 'addItem') {
148
                        return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
149
                    }
150
                    originalDynamicForm.apply(this, arguments);
151
                }
152
                
153
            })(window.jQuery);
154
JS
155
        );
156
        $this->view->registerJs(<<<JS
157
            function initObjectSelectorChanger(changerInputId, objectInputId) {
158
                $('#' + changerInputId).change(function(e) {
159
                    var regexID = /^(.+?)([-\d-]{1,})(.+)$/i;
160
                    var matches = objectInputId.match(regexID);
161
                    var combo = $('#' + objectInputId).closest('form').combo();
162
                    if (combo) {
163
                        combo.register('#' + objectInputId, window[matches[1] + '_object_id_' + e.target.value]);
164
                        $('#' + objectInputId).val(null).trigger('change');
165
                    }
166
                });
167
            }
168
JS
169
        );
170
    }
171
172
    /**
173
     * Reset attributes which may remains from the previous combo-object which leads to incorrect JS configuration
174
     */
175
    private function reset(): void
176
    {
177
        $attributes = [
178
            '_primaryFilter' => null,
179
        ];
180
        foreach ($attributes as $attribute => $defaultValue) {
181
            $this->$attribute = $defaultValue;
182
        }
183
    }
184
}
185