Passed
Push — 1 ( 9746a9...f9fc50 )
by Morven
02:08
created

ModelAdminPlus::SearchForm()   C

Complexity

Conditions 12
Paths 85

Size

Total Lines 85
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 57
nc 85
nop 0
dl 0
loc 85
rs 6.5115
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace ilateral\SilverStripe\ModelAdminPlus;
4
5
use SilverStripe\Forms\Form;
6
use SilverStripe\ORM\ArrayLib;
7
use SilverStripe\ORM\ArrayList;
8
use SilverStripe\Core\ClassInfo;
9
use SilverStripe\Forms\TextField;
10
use SilverStripe\Admin\ModelAdmin;
11
use SilverStripe\View\Requirements;
12
use Colymba\BulkManager\BulkManager;
13
use SilverStripe\Control\Controller;
14
use SilverStripe\Core\Config\Config;
15
use SilverStripe\Forms\DatetimeField;
16
use SilverStripe\Core\Injector\Injector;
17
use Colymba\BulkManager\BulkAction\UnlinkHandler;
18
use SilverStripe\Forms\GridField\GridFieldPaginator;
19
use SilverStripe\Forms\GridField\GridFieldDataColumns;
20
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
21
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
22
use ilateral\SilverStripe\ModelAdminPlus\AutoCompleteField;
23
use Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator;
24
25
/**
26
 * Custom version of model admin that adds extra features
27
 * (such as submitting search results via a POST, saving the query
28
 * as a session and automatic Bulk Editing support)
29
 *
30
 * @author ilateral
31
 * @package ModelAdminPlus
32
 */
33
abstract class ModelAdminPlus extends ModelAdmin
34
{
35
    const EXPORT_FIELDS = "export_fields";
36
37
    /**
38
     * Automatically convert date fields on gridfields
39
     * to use `Date.Nice`.
40
     *
41
     * @var boolean
42
     */
43
    private static $auto_convert_dates = true;
44
45
46
    /**
47
     * Automatically convert DB text fields to AutoComplete fields
48
     *
49
     * @var boolean
50
     */
51
    private static $convert_to_autocomplete = true;
52
53
    private static $allowed_actions = [
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
54
        "SearchForm"
55
    ];
56
57
    /**
58
     * List of currently registered ModelAdminSnippets, that is represented as
59
     * a list of classnames.
60
     *
61
     * These snippets are then setup when ModelAdminPlus is initilised and
62
     * rendered into the ModelAdminPlus content template.
63
     *
64
     * @var array
65
     */
66
    private static $registered_snippets = [];
67
68
    /**
69
     * Setup
70
     */
71
    public function getSnippets()
72
    {
73
        $snippets = ArrayList::create();
74
75
        // Setup any model admin plus snippets
76
        foreach ($this->config()->registered_snippets as $snippet) {
77
            $snippet = Injector::inst()->create($snippet);
78
            $snippet->setParent($this);
79
            $snippets->add($snippet);
80
        }
81
82
        $snippets = $snippets->sort("Order", "DESC");
83
84
        $this->extend("updateSnippets", $snippets);
85
86
        return $snippets;
87
    }
88
89
    public function init()
90
    {
91
        parent::init();
92
93
        // Require additional CSS
94
        Requirements::css("i-lateral/silverstripe-modeladminplus:client/dist/css/admin.css");
95
96
        $clear = $this->getRequest()->getVar("clear");
97
98
        if (isset($clear) && $clear == 1) {
99
            $this->clearSearchSession();
100
            // Remove clear flag
101
            return $this->redirect(
102
                $this->Link(
103
                    $this->sanitiseClassName($this->modelClass)
104
                )
105
            );
106
        }
107
    }
108
109
    /**
110
     * Get the default export fields for the current model.
111
     *
112
     * First this checks if there is an `export_fields` config variable set on
113
     * the model class, if not, it reverts to the default behaviour.
114
     *
115
     * @return array
116
     */
117
    public function getExportFields()
118
    {
119
        $export_fields = Config::inst()->get(
120
            $this->modelClass,
121
            self::EXPORT_FIELDS
122
        );
123
124
        if (isset($export_fields) && is_array($export_fields)) {
125
            $fields = $export_fields;
126
        } else {
127
            $fields = parent::getExportFields();
128
        }
129
130
        $this->extend("updateExportFields", $fields);
131
132
        return $fields;
133
    }
134
135
    /**
136
     * Get the name of the session to be useed by this model admin's search
137
     * form.
138
     *
139
     * @return string
140
     */
141
    public function getSearchSessionName()
142
    {
143
        $curr = $this->sanitiseClassName(self::class);
144
        $model = $this->sanitiseClassName($this->modelClass);
145
        return $curr . "." . $model;
146
    }
147
148
    /**
149
     * Empty the current search session
150
     *
151
     * @return Session
0 ignored issues
show
Bug introduced by
The type ilateral\SilverStripe\ModelAdminPlus\Session was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
152
     */
153
    public function clearSearchSession()
154
    {
155
        $session = $this->getRequest()->getSession();
156
        return $session->clear($this->getSearchSessionName());
157
    }
158
159
    /**
160
     * Get the current search session
161
     *
162
     * @return Session
163
     */
164
    public function getSearchSession()
165
    {
166
        $session = $this->getRequest()->getSession();
167
        return $session->get($this->getSearchSessionName());
168
    }
169
170
    /**
171
     * Set some data to a search session. This needs to be an array of
172
     * data (like the data submitted by a form).
173
     *
174
     * @param array $data An array of data to store in the session
175
     *
176
     * @return self
177
     */
178
    public function setSearchSession($data)
179
    {
180
        $session = $this->getRequest()->getSession();
181
        return $session->set($this->getSearchSessionName(), $data);
182
    }
183
184
    /**
185
     * Get the current search results, combined with any saved
186
     * search results and resturn (as an array).
187
     *
188
     * @return array
189
     */
190
    public function getSearchData()
191
    {
192
        $data = $this->getSearchSession();
193
194
        if (!$data || $data && !is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always false.
Loading history...
introduced by
$data is of type ilateral\SilverStripe\ModelAdminPlus\Session, thus it always evaluated to true.
Loading history...
195
            $data = [];
196
        }
197
198
        return $data;
199
    }
200
201
    /**
202
     * Overwrite the default search list to account for the new session based
203
     * search data.
204
     *
205
     * You can override how ModelAdmin returns DataObjects by either overloading this method,
206
     * or defining an extension to ModelAdmin that implements the `updateList` method
207
     * (and takes a {@link \SilverStripe\ORM\DataList} as the
208
     * first argument).
209
     *
210
     * @return \SilverStripe\ORM\DataList
211
     */
212
    public function getList()
213
    {
214
        $context = $this->getSearchContext();
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Admin\ModelAdmin::getSearchContext() has been deprecated: 5.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

214
        $context = /** @scrutinizer ignore-deprecated */ $this->getSearchContext();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
215
        $params = $this->getSearchData();
216
217
        if (is_array($params)) {
0 ignored issues
show
introduced by
The condition is_array($params) is always true.
Loading history...
218
            $params = ArrayLib::array_map_recursive('trim', $params);
219
220
            // Parse all DateFields to handle user input non ISO 8601 dates
221
            foreach ($context->getFields() as $field) {
222
                if ($field instanceof DatetimeField && !empty($params[$field->getName()])) {
223
                    $params[$field->getName()] = date(
224
                        'Y-m-d',
225
                        strtotime($params[$field->getName()])
226
                    );
227
                }
228
            }
229
        }
230
231
        $list = $context->getResults($params);
232
233
        $this->extend('updateList', $list);
234
235
        return $list;
236
    }
237
238
    /**
239
     * Gets a list of fields that have been searched
240
     *
241
     * @return SilverStripe\ORM\ArrayList
0 ignored issues
show
Bug introduced by
The type ilateral\SilverStripe\Mo...verStripe\ORM\ArrayList was not found. Did you mean SilverStripe\ORM\ArrayList? If so, make sure to prefix the type with \.
Loading history...
242
     */
243
    public function SearchSummary()
244
    {
245
        $context = $this->getSearchContext();
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Admin\ModelAdmin::getSearchContext() has been deprecated: 5.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

245
        $context = /** @scrutinizer ignore-deprecated */ $this->getSearchContext();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
246
        $params = $this->getSearchData();
247
        $context->setSearchParams($params);
248
249
        return $context->getSummary();
250
    }
251
252
    
253
    /**
254
     * Add bulk editor to Edit Form
255
     *
256
     * @param int|null  $id
257
     * @param FieldList $fields
0 ignored issues
show
Bug introduced by
The type ilateral\SilverStripe\ModelAdminPlus\FieldList was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
258
     *
259
     * @return Form A Form object
260
     */
261
    public function getEditForm($id = null, $fields = null)
262
    {
263
        $form = parent::getEditForm($id, $fields);
264
        $grid_field = $form
265
            ->Fields()
266
            ->fieldByName($this->sanitiseClassName($this->modelClass));
267
268
        // Add bulk editing to gridfield
269
        $manager = new BulkManager();
270
        $manager->removeBulkAction(UnlinkHandler::class);
271
272
        $config = $grid_field->getConfig();
273
274
        $config
275
            ->removeComponentsByType(GridFieldPaginator::class)
276
            ->addComponent($manager)
277
            ->addComponent(new GridFieldConfigurablePaginator());
278
279
        if ($this->config()->auto_convert_dates) {
280
            GridFieldDateFinder::create($grid_field)->convertDateFields();
281
        }
282
283
        return $form;
284
    }
285
286
    /**
287
     * Overwrite default search form
288
     *
289
     * @return Form
290
     */
291
    public function SearchForm()
292
    {
293
        $form = parent::SearchForm();
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Admin\ModelAdmin::SearchForm() has been deprecated: 5.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

293
        $form = /** @scrutinizer ignore-deprecated */ parent::SearchForm();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
294
        $fields = $form->Fields();
295
        $data = $this->getSearchData();
296
        $class = $this->modelClass;
297
        $use_autocomplete = $this->config()->convert_to_autocomplete;
298
299
        $db = Config::inst()->get($class, "db");
300
        $has_one = Config::inst()->get($class, "has_one");
301
        $has_many = Config::inst()->get($class, "has_many");
302
        $many_many = Config::inst()->get($class, "many_many");
303
        $belongs_many_many = Config::inst()->get($class, "belongs_many_many");
304
        $associations = array_merge(
305
            $has_one,
306
            $has_many,
307
            $many_many,
308
            $belongs_many_many
309
        );
310
311
        // Change currently scaffolded query fields to use conventional
312
        // field names
313
        foreach ($fields as $field) {
314
            $field_class = $this->modelClass;
315
            $name = $field->getName();
316
            $title = $field->Title();
317
            $in_db = false;
318
            $db_field = str_replace(["q[", "]"], "", $name);
319
320
            // Find any text fields an replace with autocomplete fields
321
            if ($field instanceof TextField && $use_autocomplete) {
322
                // If this is a relation, switch class name
323
                if (strpos($name, "__")) {
324
                    $parts = explode("__", $db_field);
325
                    $field_class = isset($associations[$parts[0]]) ? $associations[$parts[0]] : null;
326
                    $db_field = $parts[1];
327
                    $in_db = ($field_class) ? true : false;
328
                }
329
330
                // If this is in the DB (not casted)
331
                if (in_array($db_field, array_keys($db))) {
332
                    $in_db = true;
333
                }
334
335
                if ($in_db) {
336
                    $fields->replaceField(
337
                        $name,
338
                        $field = AutoCompleteField::create(
339
                            $name,
340
                            $title,
341
                            $field->Value(),
342
                            $field_class,
343
                            $db_field
344
                        )->setForm($form)
345
                        ->setDisplayField($db_field)
346
                        ->setLabelField($db_field)
347
                        ->setStoredField($db_field)
348
                    );
349
                }
350
            }
351
            
352
            if ($name[0] == "q" && $name[1] == "[") {
353
                $name = substr($name, 2);
354
            }
355
            
356
            if (substr($name, -1) == "]") {
357
                $name = substr($name, 0, -1);
358
            }
359
360
            $field->setName($name);
361
        }
362
        
363
        $form
364
            ->removeExtraClass('cms-search-form')
365
            ->setFormMethod('post')
366
            ->setFormAction(
367
                $this->Link(
368
                    Controller::join_links(
369
                        $this->sanitiseClassName($this->modelClass),
370
                        $form->getName()
371
                    )
372
                )
373
            )->loadDataFrom($data);
374
375
        return $form;
376
    }
377
378
    /**
379
     * Set the session from the submitted form data (and redirect back)
380
     *
381
     * @param array $data Submitted form
382
     * @param Form  $form The current form
383
     *
384
     * @return HTTPResponse
0 ignored issues
show
Bug introduced by
The type ilateral\SilverStripe\ModelAdminPlus\HTTPResponse was not found. Did you mean HTTPResponse? If so, make sure to prefix the type with \.
Loading history...
385
     */
386
    public function search($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

386
    public function search($data, /** @scrutinizer ignore-unused */ $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
387
    {
388
        foreach ($data as $key => $value) {
389
            // Ensure we clear any null values
390
            // so they don't mess up the list
391
            if (empty($data[$key])) {
392
                unset($data[$key]);
393
            }
394
395
            // Ensure we clear any null values
396
            // so they don't mess up the list
397
            if (strpos($key, "action_") !== false) {
398
                unset($data[$key]);
399
            }
400
        }
401
402
        $this->setSearchSession($data);
403
404
        return $this->redirectBack();
405
    }
406
}
407