Issues (24)

src/ModelAdminPlus.php (8 issues)

1
<?php
2
3
namespace ilateral\SilverStripe\ModelAdminPlus;
4
5
use SilverStripe\Forms\Form;
6
use SilverStripe\ORM\ArrayList;
7
use SilverStripe\Admin\ModelAdmin;
8
use SilverStripe\View\Requirements;
9
use Colymba\BulkManager\BulkManager;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Control\HTTPRequest;
12
use SilverStripe\Forms\GridField\GridField;
13
use Colymba\BulkManager\BulkAction\UnlinkHandler;
14
use SilverStripe\Forms\GridField\GridFieldConfig;
15
use SilverStripe\Forms\GridField\GridFieldButtonRow;
16
use SilverStripe\Forms\GridField\GridFieldPaginator;
17
use ilateral\SilverStripe\ModelAdminPlus\AutoCompleteField;
18
use Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator;
19
use SilverStripe\Forms\GridField\GridFieldFilterHeader as SSGridFieldFilterHeader;
20
21
/**
22
 * Custom version of model admin that adds extra features
23
 * (such as submitting search results via a POST, saving the query
24
 * as a session and automatic Bulk Editing support)
25
 *
26
 * @author ilateral
27
 * @package ModelAdminPlus
28
 */
29
abstract class ModelAdminPlus extends ModelAdmin
30
{
31
    const EXPORT_FIELDS = "export_fields";
32
33
    const ACTION_SUGGEST = 'suggest';
34
35
    /**
36
     * Automatically convert date fields on gridfields
37
     * to use `Date.Nice`.
38
     *
39
     * @var boolean
40
     */
41
    private static $auto_convert_dates = true;
42
43
    /**
44
     * Automatically convert DB text fields to AutoComplete fields
45
     *
46
     * @var boolean
47
     */
48
    private static $convert_to_autocomplete = true;
0 ignored issues
show
The private property $convert_to_autocomplete is not used, and could be removed.
Loading history...
49
50
    private static $allowed_actions = [
0 ignored issues
show
The private property $allowed_actions is not used, and could be removed.
Loading history...
51
        "SearchForm",
52
        self::ACTION_SUGGEST
53
    ];
54
55
    /**
56
     * List of currently registered ModelAdminSnippets, that is represented as
57
     * a list of classnames.
58
     *
59
     * These snippets are then setup when ModelAdminPlus is initilised and
60
     * rendered into the ModelAdminPlus content template.
61
     * 
62
     * This list can also be a divided up by managed classnames, so that snippets will
63
     * only be loaded when accessing that class, EG:
64
     * 
65
     * $registered_snippets = [
66
     *      MyObject::class => [
67
     *          MySnippetOne::class,
68
     *          MySnippetTwo::class
69
     *      ]
70
     * ];
71
     *
72
     * @var array
73
     */
74
    private static $registered_snippets = [];
75
76
    /**
77
     * Setup snippets for current screen
78
     */
79
    public function getSnippets()
80
    {
81
        $snippets = ArrayList::create();
82
        $model_class = $this->getModelClass();
83
84
        // Setup any model admin plus snippets
85
        foreach ($this->config()->registered_snippets as $key => $value) {
86
            if (is_int($key)) {
87
                $snippet = $this->createSnippetObject($value);
88
                $snippets->add($snippet);
89
            }
90
91
            if (is_array($value) && $key == $model_class) {
92
                foreach ($value as $snippet_class) {
93
                    $snippet = $this->createSnippetObject($snippet_class);
94
                    $snippets->add($snippet);
95
                }
96
            }
97
        }
98
99
        $snippets = $snippets->sort("Order", "DESC");
100
101
        $this->extend("updateSnippets", $snippets);
102
103
        return $snippets;
104
    }
105
106
    protected function createSnippetObject(string $class): ModelAdminSnippet
107
    {
108
        $snippet = new $class('snippets-before');
109
        $snippet->setParent($this);
110
        return $snippet;
111
    }
112
113
    public function init()
114
    {
115
        parent::init();
116
117
        Requirements::add_i18n_javascript('silverstripe/cms: client/lang', false, true);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\View\Requir...::add_i18n_javascript() has been deprecated. ( Ignorable by Annotation )

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

117
        /** @scrutinizer ignore-deprecated */ Requirements::add_i18n_javascript('silverstripe/cms: client/lang', false, true);
Loading history...
118
119
        $clear = $this->getRequest()->getVar("clear");
120
121
        if (isset($clear) && $clear == 1) {
122
            $this->clearSearchSession();
123
            // Remove clear flag
124
            return $this->redirect(
125
                $this->Link(
126
                    $this->sanitiseClassName($this->modelClass)
127
                )
128
            );
129
        }
130
    }
131
132
    /**
133
     * Get the default export fields for the current model.
134
     *
135
     * First this checks if there is an `export_fields` config variable set on
136
     * the model class, if not, it reverts to the default behaviour.
137
     *
138
     * @return array
139
     */
140
    public function getExportFields()
141
    {
142
        $export_fields = Config::inst()->get(
143
            $this->modelClass,
144
            self::EXPORT_FIELDS
145
        );
146
147
        if (isset($export_fields) && is_array($export_fields)) {
148
            $fields = $export_fields;
149
        } else {
150
            $fields = parent::getExportFields();
151
        }
152
153
        $this->extend("updateExportFields", $fields);
154
155
        return $fields;
156
    }
157
158
    /**
159
     * Get the name of the session to be useed by this model admin's search
160
     * form.
161
     *
162
     * @return string
163
     */
164
    public function getSearchSessionName()
165
    {
166
        $curr = $this->sanitiseClassName(self::class);
167
        $model = $this->sanitiseClassName($this->modelClass);
168
        return $curr . "." . $model;
169
    }
170
171
    /**
172
     * Empty the current search session
173
     *
174
     * @return Session
0 ignored issues
show
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...
175
     */
176
    public function clearSearchSession()
177
    {
178
        $session = $this->getRequest()->getSession();
179
        return $session->clear($this->getSearchSessionName());
180
    }
181
182
    /**
183
     * Get the current search session
184
     *
185
     * @return Session
186
     */
187
    public function getSearchSession()
188
    {
189
        $session = $this->getRequest()->getSession();
190
        return $session->get($this->getSearchSessionName());
191
    }
192
193
    /**
194
     * Set some data to a search session. This needs to be an array of
195
     * data (like the data submitted by a form).
196
     *
197
     * @param array $data An array of data to store in the session
198
     *
199
     * @return self
200
     */
201
    public function setSearchSession($data)
202
    {
203
        $session = $this->getRequest()->getSession();
204
        return $session->set($this->getSearchSessionName(), $data);
205
    }
206
207
    /**
208
     * Get the current search results, combined with any saved
209
     * search results and resturn (as an array).
210
     *
211
     * @return array
212
     */
213
    public function getSearchData()
214
    {
215
        $data = $this->getSearchSession();
216
217
        if (!$data || $data && !is_array($data)) {
0 ignored issues
show
$data is of type ilateral\SilverStripe\ModelAdminPlus\Session, thus it always evaluated to true.
Loading history...
The condition is_array($data) is always false.
Loading history...
218
            $data = [];
219
        }
220
221
        return $data;
222
    }
223
224
    protected function getGridField(): GridField
225
    {
226
        $field = parent::getGridField();
227
228
        if ($this->config()->auto_convert_dates) {
229
            GridFieldDateFinder::create($field)->convertDateFields();
230
        }
231
232
        return $field;
233
    }
234
235
    protected function getGridFieldConfig(): GridFieldConfig
236
    {
237
        $config = parent::getGridFieldConfig();
238
239
        // Add bulk editing to gridfield
240
        $manager = new BulkManager();
241
        $manager->removeBulkAction(UnlinkHandler::class);
242
243
        $config
244
            ->addComponent(new GridFieldSnippetRow(), GridFieldButtonRow::class)
245
            ->removeComponentsByType(GridFieldPaginator::class)
246
            ->addComponent($manager)
247
            ->addComponent(new GridFieldConfigurablePaginator());
248
249
        // Switch to custom filter header
250
        if ($config->getComponentsByType(SSGridFieldFilterHeader::class)->exists()) {
251
            $config
252
            ->removeComponentsByType(SSGridFieldFilterHeader::class)
253
            ->addComponent(new GridFieldFilterHeader(
254
                false,
255
                function ($context) {
256
                    $this->extend('updateSearchContext', $context);
257
                },
258
                function ($form) {
259
                    $this->extend('updateSearchForm', $form);
260
                }
261
            ));
262
        }
263
264
        // Add custom snippets
265
        foreach ($this->getSnippets() as $snippet) {
266
            $config->addComponent($snippet);
267
        }
268
269
        return $config;
270
    }
271
272
    /**
273
     * Find and return the recommended suggestion for an autocomplete
274
     * field
275
     *
276
     * @param array $data Submitted form
277
     * @param Form  $form The current form
278
     *
279
     * @return HTTPResponse
0 ignored issues
show
The type ilateral\SilverStripe\ModelAdminPlus\HTTPResponse was not found. Did you mean HTTPResponse? If so, make sure to prefix the type with \.
Loading history...
280
     */
281
    public function suggest(HTTPRequest $request)
282
    {
283
        $name = $request->param('n');
284
        $grid = $this->getGridField();
285
286
        // Manually re-assign gridfield to edit form
287
        $form = $this->getEditForm();
288
        $grid->setForm($form);
289
290
        $config = $grid->getConfig();
291
        /** @var GridFieldFilterHeader */
292
        $search = $config->getComponentByType(GridFieldFilterHeader::class);
293
        $form = isset($search) ? $search->getSearchForm($grid) : null;
0 ignored issues
show
The method getSearchForm() does not exist on SilverStripe\Forms\GridField\GridFieldComponent. It seems like you code against a sub-type of SilverStripe\Forms\GridField\GridFieldComponent such as SilverStripe\Forms\GridField\GridFieldFilterHeader or SilverStripe\Forms\GridField\GridFieldPrintButton or SilverStripe\Forms\GridField\GridFieldFilterHeader or SilverStripe\Forms\GridField\GridFieldPrintButton or Symbiote\GridFieldExtens...\GridFieldOrderableRows or SilverStripe\Forms\GridField\GridFieldFilterHeader or ilateral\SilverStripe\Mo...nPlus\ModelAdminSnippet or Symbiote\GridFieldExtens...\GridFieldOrderableRows or SilverStripe\Forms\GridField\GridFieldFilterHeader or Symbiote\GridFieldExtens...\GridFieldOrderableRows or SilverStripe\Forms\GridField\GridFieldPrintButton or Symbiote\GridFieldExtens...\GridFieldOrderableRows or SilverStripe\Forms\GridField\GridFieldFilterHeader or SilverStripe\Forms\Tests...ndlerTest\TestComponent or SilverStripe\Forms\GridField\GridFieldDetailForm or Symbiote\GridFieldExtens...\GridFieldOrderableRows. ( Ignorable by Annotation )

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

293
        $form = isset($search) ? $search->/** @scrutinizer ignore-call */ getSearchForm($grid) : null;
Loading history...
294
        
295
        /** @var AutoCompleteField */
296
        $field = isset($form) ? $form->Fields()->fieldByName($name) : null;
297
298
        if (isset($field)) {
299
            return $field->Suggest($request);
300
        }
301
302
        // the response body
303
        return json_encode([]);
304
    }
305
}
306