Completed
Push — master ( 4ca583...a67af2 )
by Song
02:43
created

BelongsToMany::getOtherKey()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 0
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Grid\Displayers;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Grid\Selectable;
7
use Illuminate\Database\Eloquent\Relations\BelongsToMany as Relation;
8
use Illuminate\Support\Arr;
9
10
class BelongsToMany extends AbstractDisplayer
11
{
12
    use BelongsToRelation;
13
14
    /**
15
     * Other key for many-to-many relation.
16
     *
17
     * @var string
18
     */
19
    protected static $otherKey = [];
20
21
    /**
22
     * @return $this
23
     */
24 View Code Duplication
    public function addScript()
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...
25
    {
26
        $script = <<<SCRIPT
27
(function () {
28
    var modal = $('#{$this->modalID}');
29
    var related = null;
30
    var selected = [];
31
32
    var load = function (url) {
33
        $.get(url, function (data) {
34
            modal.find('.modal-body').html(data);
35
            modal.find('.select').iCheck({
36
                radioClass:'iradio_minimal-blue',
37
                checkboxClass:'icheckbox_minimal-blue'
38
            });
39
            modal.find('.box-header:first').hide();
40
41
            modal.find('input.select').each(function (index, el) {
42
                if ($.inArray($(el).val().toString(), selected) >=0 ) {
43
                    $(el).iCheck('toggle');
44
                }
45
            });
46
        });
47
    };
48
49
    var update = function (callback) {
50
        $.ajax({
51
            url: "{$this->getResource()}/" + related.attr('key'),
52
            type: "POST",
53
            data: {
54
                {$this->columnName}: selected,
55
                _token: LA.token,
56
                _method: 'PUT'
57
            },
58
            success: function (data) {
59
                callback(data);
60
            }
61
        });
62
    };
63
64
    modal.on('show.bs.modal', function (e) {
65
        related = $(e.relatedTarget);
66
        selected = related.data('val').map(function (value) {
67
            return value.toString();
68
        });
69
70
        load("{$this->getLoadUrl(1)}");
71
    }).on('click', '.page-item a, .filter-box a', function (e) {
72
        load($(this).attr('href'));
73
        e.preventDefault();
74
    }).on('click', 'tr', function (e) {
75
        $(this).find('input.select').iCheck('toggle');
76
        e.preventDefault();
77
    }).on('submit', '.box-header form', function (e) {
78
        load($(this).attr('action')+'&'+$(this).serialize());
79
        e.preventDefault();
80
    }).on('ifChecked', 'input.select', function (e) {
81
        var val = $(this).val().toString();
82
        if (selected.indexOf(val) < 0) {
83
            selected.push(val);
84
        }
85
    }).on('ifUnchecked', 'input.select', function (e) {
86
           var val = $(this).val().toString();
87
           var index = selected.indexOf(val);
88
            if (index !== -1) {
89
                selected.splice(index, 1);
90
            }
91
    }).find('.modal-footer .submit').click(function () {
92
        update(function (data) {
93
            related.data('val', selected);
94
            related.find('.text').html(data.display["{$this->columnName}"]);
95
            related.find('a').toggleClass('text-green text-muted');
96
97
            setTimeout(function () {
98
                related.find('a').toggleClass('text-green text-muted');
99
            }, 2000);
100
101
            modal.modal('toggle');
102
103
            toastr.success(data.message);
104
        });
105
    });
106
})();
107
SCRIPT;
108
109
        Admin::script($script);
110
111
        return $this;
112
    }
113
114
    /**
115
     * Get other key for this many-to-many relation.
116
     *
117
     * @throws \Exception
118
     *
119
     * @return string
120
     */
121
    protected function getOtherKey()
122
    {
123
        if (isset(static::$otherKey[$this->getName()])) {
124
            return static::$otherKey[$this->getName()];
125
        }
126
127
        $model = $this->getGrid()->model()->getOriginalModel();
0 ignored issues
show
Bug introduced by
The method getOriginalModel does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
128
129
        if (is_callable([$model, $this->getName()]) &&
130
            ($relation = $model->{$this->getName()}()) instanceof Relation
131
        ) {
132
            /* @var Relation $relation */
133
            $fullKey = $relation->getQualifiedRelatedPivotKeyName();
134
            $fullKeyArray = explode('.', $fullKey);
135
136
            return static::$otherKey[$this->getName()] = end($fullKeyArray);
137
        }
138
139
        throw new \Exception('Column of this field must be a `BelongsToMany` relation.');
140
    }
141
142
    /**
143
     * @return false|string|void
144
     * @throws \Exception
145
     */
146
    protected function getOriginalData()
147
    {
148
        $relations = $this->getColumn()->getOriginal();
149
150
        if (is_string($relations)) {
151
            $data = explode(',', $relations);
152
        }
153
154
        if (!is_array($relations)) {
155
            return;
156
        }
157
158
        $first = current($relations);
159
160
        if (is_null($first)) {
161
            $data = null;
162
163
            // MultipleSelect value store as an ont-to-many relationship.
164
        } elseif (is_array($first)) {
165
            foreach ($relations as $relation) {
166
                $data[] = Arr::get($relation, "pivot.{$this->getOtherKey()}");
0 ignored issues
show
Bug introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
167
            }
168
169
            // MultipleSelect value store as a column.
170
        } else {
171
            $data = $relations;
172
        }
173
174
        return json_encode($data);
175
    }
176
}
177