Completed
Push — master ( 02ffc1...a5dd29 )
by David
02:35
created

CrudApi::getRelatedModel()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
cc 4
eloc 12
nc 3
nop 1
1
<?php
2
3
namespace Taskforcedev\CrudApi\Helpers;
4
5
use Illuminate\Console\AppNamespaceDetectorTrait;
6
7
class CrudApi
8
{
9
    use AppNamespaceDetectorTrait;
10
11
    public $model;
12
    public $instance;
13
    public $namespace;
14
    public $modelHelper;
15
    public $fieldHelper;
16
17
    public function __construct($options = [])
18
    {
19
        /* Set the namespace */
20
        if (array_key_exists('namespace', $options)) {
21
            $this->namespace = $options['namespace'];
22
        } else {
23
            $this->namespace = $this->getAppNamespace();
24
        }
25
26
        /* Set the model */
27
        if (array_key_exists('model', $options)) {
28
            $this->model = $options['model'];
29
        }
30
31
        $this->modelHelper = new Model($this);
32
        $this->fieldHelper = new Field($this);
33
    }
34
35
    /**
36
     * Set the namespace to search within.
37
     *
38
     * @param string $namespace
39
     */
40
    public function setNamespace($namespace)
41
    {
42
        $this->namespace = $namespace;
43
    }
44
45
    /**
46
     * Set the model to work with.
47
     *
48
     * @param $model
49
     *
50
     * @return $this
51
     */
52
    public function setModel($model)
53
    {
54
        $this->model = $model;
55
56
        return $this;
57
    }
58
59
    /**
60
     * Set a model instance from which to work.
61
     *
62
     * @param $item
63
     *
64
     * @return $this
65
     */
66
    public function setInstance($item)
67
    {
68
        $this->instance = $item;
69
70
        return $this;
71
    }
72
73
    public function getFields()
74
    {
75
        $model = $this->getModelInstance();
76
        $fields = $model->getFillable();
77
        $filtered_fields = [];
78
79
        foreach ($fields as $f) {
80
            if ($f !== 'password' && $f !== 'Password') {
81
                $filtered_fields[] = $f;
82
            }
83
        }
84
85
        return $filtered_fields;
86
    }
87
88
    public function getModelDisplayName()
89
    {
90
        $instance = $this->getModelInstance();
91
        $display = isset($instance->display) ? $instance->display : ucfirst($this->model);
92
93
        return $display;
94
    }
95
96
    public function getModelInstance()
97
    {
98
        if ($this->instance !== null) {
99
            return $this->instance;
100
        }
101
        $model = $this->getModel();
1 ignored issue
show
Bug introduced by
The method getModel() does not exist on Taskforcedev\CrudApi\Helpers\CrudApi. Did you maybe mean getModelDisplayName()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
102
        if ($model === false) {
103
            return false;
104
        }
105
        $instance = new $model();
106
107
        return $instance;
108
    }
109
110
    public function modal($type)
111
    {
112
        $trimmed_item = $this->trimmedModel();
113
114
        $modalId = $type.$trimmed_item.'Modal';
115
116
        $display = $this->getModelDisplayName();
117
118
        $modal = (object) [
119
            'id' => $modalId,
120
            'title' => ucfirst($type).' '.$display,
121
            'url' => $this->modalUrl($type),
122
        ];
123
124
        return $modal;
125
    }
126
127
    private function modalUrl($type)
1 ignored issue
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
128
    {
129
        switch ($type) {
130
        case 'edit':
131
            $action = 'update';
132
            break;
133
        default:
134
            $action = $type;
135
            break;
136
        }
137
138
        return route('crudapi.'.$action.'.item', $this->model);
139
    }
140
141
    public function jsMethodName($method)
142
    {
143
        // Method == create
144
        $jsMethod = $method.$this->trimmedModel();
145
146
        return $jsMethod;
147
    }
148
149
    public function renderFields($type, $fields = [])
150
    {
151
        if (empty($fields)) {
152
            $fields = $this->getFields();
153
        }
154
        $output = '';
155
156
        switch ($type) {
157
        case 'form-create':
158
            $output .= $this->fieldHelper->formCreate($fields);
159
            break;
160
        case 'form-edit':
161 View Code Duplication
            foreach ($fields as $f) {
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...
162
                $ucF = ucfirst($f);
163
164
                $input_attr = [
165
                    'class' => 'form-control',
166
                    'id' => 'editItem'.$ucF,
167
                    'name' => $f,
168
                ];
169
170
                $output .= '<fieldset class="form-group">';
171
172
                $output .= '<label for="'.$input_attr['id'].'">'.$ucF.'</label>';
173
174
                if ($this->fieldHelper->isIdField($f)) {
175
                    $input_attr['type'] = 'select';
176
177
                    $output .= '<select ';
178
                    foreach ($input_attr as $attr => $value) {
179
                        $output .= "{$attr}='{$value}'";
180
                    }
181
182
                    $relation = $this->getRelatedModel($f);
183
                    $output .= '>';
184
185
                    $output .= $this->getRelatedOptions($relation);
186
                    $output .= '</select>';
187
                } else {
188
                    $input_attr['type'] = 'text';
189
190
                    $output .= '<input ';
191
                    foreach ($input_attr as $attr => $value) {
192
                        $output .= "{$attr}='{$value}'";
193
                    }
194
                    $output .= '>';
195
                }
196
197
                $output .= '</fieldset>';
198
            }
199
            break;
200
        case 'table-headings':
201
            $output .= $this->fieldHelper->tableHeadings($fields);
202
            break;
203
        case 'table-content':
204
            $output .= $this->fieldHelper->tableContent($fields, $this->instance);
205
            break;
206
            // JavaScript Variables
207
        case 'js-var':
208
            foreach ($fields as $f) {
209
                $output .= 'var '.$f.' = '.$this->instance->$f.'; ';
210
            }
211
            break;
212
        case 'js-modal-create':
213
            foreach ($fields as $f) {
214
                $output .= '"'.$f.'": $(\'#createItem'.$f.'\').val(), ';
215
            }
216
            break;
217
        default:
218
            return;
219
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
220
        }
221
222
        echo $output;
223
    }
224
225
    public function trimmedModel()
226
    {
227
        return strpos($this->model, ' ') !== false ? implode('', explode(' ', $this->model)) : $this->model;
228
    }
229
230
    public function getRelatedOptions($relation)
231
    {
232
        $output = '';
233
234
        if (!method_exists($relation, 'toOptions')) {
235
            $relationItems = $relation::all();
236
            foreach ($relationItems as $item) {
237
                if (!isset($item->name)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
238
                    // Error - there is no toOptions or name property.
239
                } else {
240
                    $output .= '<option value="'.$item->id.'">'.$item->name.'</option>';
241
                }
242
            }
243
        } else {
244
            $output .= $relation->toOptions();
245
        }
246
247
        return $output;
248
    }
249
250
    public function getRelatedModel($f)
251
    {
252
        $field = $this->getRelatedField($f);
0 ignored issues
show
Documentation Bug introduced by
The method getRelatedField does not exist on object<Taskforcedev\CrudApi\Helpers\CrudApi>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
253
        $model = $this->getModel($field);
0 ignored issues
show
Bug introduced by
The method getModel() does not exist on Taskforcedev\CrudApi\Helpers\CrudApi. Did you maybe mean getModelDisplayName()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
254
255
        if (!class_exists($model)) {
256
            // Convert from DB format to Pascal
257
            $words = explode('_', $field);
258
            foreach ($words as $i => $w) {
259
                $words[$i] = ucfirst($w);
260
            }
261
            $formatted = implode('', $words);
262
            $model = 'App\\'.$formatted;
263
            if (!class_exists($model)) {
264
                return false;
265
            }
266
        }
267
268
        return new $model();
269
    }
270
271
    public function getRelatedDisplay($f)
272
    {
273
        $related_field = $this->getRelatedField($f);
0 ignored issues
show
Documentation Bug introduced by
The method getRelatedField does not exist on object<Taskforcedev\CrudApi\Helpers\CrudApi>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
274
275
        $field = $this->instance->$related_field;
276
277
        $class = get_class($field);
278
279
        switch ($class) {
280
        case 'App\\Helpers\\CrudApi':
281
            break;
282
        case 'App\\Indicator':
283
            return $field->indicator;
284
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
285
        case 'Taskforcedev\\CrudApi\\Helpers\\CrudApi':
286
            return false;
287
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
288
        default:
289
            return $field->name;
290
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
291
        }
292
    }
293
294
    /**
295
     * Allow certain methods to be passed through to the specified
296
     * helper in order to make methods easier to remember.
297
     *
298
     * @param $method
299
     * @param $args
300
     *
301
     * @return bool
302
     */
303
    public function __call($method, $args)
304
    {
305
        switch ($method) {
306
            case 'getRelatedField':
307
                return $this->fieldHelper->getRelatedField($args[0]);
308
            case 'getPrimaryField':
309
                return $this->fieldHelper->getPrimaryField($args[0]);
310
            case 'isIdField':
311
                return $this->fieldHelper->isIdField($args[0]);
312
            case 'getModel':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
313
                if (isset($args[0])) {
314
                    return $this->modelHelper->getModel($args[0]);
315
                } else {
316
                    return $this->modelHelper->getModel();
317
                }
318
            default:
319
                break;
320
        }
321
    }
322
}
323