Passed
Push — master ( a4bd11...e79927 )
by Thomas
13:40
created

getGridFieldExportButton()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace LeKoala\ExcelImportExport\Extensions;
4
5
use SilverStripe\Forms\Form;
6
use SilverStripe\Core\Extension;
7
use SilverStripe\Admin\ModelAdmin;
8
use SilverStripe\Forms\CheckboxField;
9
use SilverStripe\Forms\OptionsetField;
10
use LeKoala\ExcelImportExport\ExcelBulkLoader;
11
use LeKoala\ExcelImportExport\ExcelImportExport;
12
use SilverStripe\Forms\GridField\GridFieldConfig;
13
use SilverStripe\Forms\GridField\GridFieldExportButton;
14
use SilverStripe\Forms\GridField\GridFieldImportButton;
15
use LeKoala\ExcelImportExport\ExcelGridFieldExportButton;
16
use LeKoala\ExcelImportExport\ExcelGridFieldImportButton;
17
use LeKoala\ExcelImportExport\ExcelGroupBulkLoader;
18
use LeKoala\ExcelImportExport\ExcelMemberBulkLoader;
19
use SilverStripe\Admin\SecurityAdmin;
20
21
/**
22
 * Extends {@link ModelAdmin}. to bind new forms and features
23
 *
24
 * @author Koala
25
 */
26
class ModelAdminExcelExtension extends Extension
27
{
28
    /**
29
     * @var array<string>
30
     */
31
    private static $allowed_actions = array(
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
32
        'downloadsample'
33
    );
34
35
    /**
36
     * @return void
37
     */
38
    public function onAfterInit()
39
    {
40
        $this->updateModelImporters();
41
    }
42
43
    /**
44
     * Replace default model import with a predefined value
45
     *
46
     * @return void
47
     */
48
    protected function updateModelImporters()
49
    {
50
        /** @var ModelAdmin $owner */
51
        $owner = $this->owner;
52
        //@phpstan-ignore-next-line
53
        $config = $this->owner::config();
54
55
        // Overwrite model imports
56
        $importerClasses = $config->get('model_importers');
57
58
        if ($owner instanceof SecurityAdmin) {
59
            $importerClasses = [
60
                "users" => ExcelMemberBulkLoader::class,
61
                "SilverStripe\Security\Member" => ExcelMemberBulkLoader::class,
62
                "groups" => ExcelGroupBulkLoader::class,
63
                "SilverStripe\Security\Group" => ExcelGroupBulkLoader::class,
64
            ];
65
            $config->set('model_importers', $importerClasses);
66
        } elseif (is_null($importerClasses)) {
67
            $models = $owner->getManagedModels();
68
            foreach (array_keys($models) as $modelName) {
69
                $importerClasses[$modelName] = ExcelBulkLoader::class;
70
            }
71
72
            $config->set('model_importers', $importerClasses);
73
        }
74
    }
75
76
    /**
77
     * @return void
78
     */
79
    public function downloadsample()
80
    {
81
        /** @var \SilverStripe\Admin\ModelAdmin $owner */
82
        $owner = $this->owner;
83
        $importer = $owner->getRequest()->getVar('importer');
84
        if ($importer && class_exists($importer) && method_exists($importer, 'getSampleFile')) {
85
            $importer::getSampleFile();
86
        } else {
87
            ExcelImportExport::sampleFileForClass($owner->getModelClass());
88
        }
89
    }
90
91
    /**
92
     * @param GridFieldConfig $config
93
     * @return void
94
     */
95
    public function updateGridFieldConfig(GridFieldConfig $config)
96
    {
97
        /** @var ModelAdmin $owner */
98
        $owner = $this->owner;
99
        $class = $owner->getModelClass();
100
        $classConfig = $owner->config();
101
102
        // Add/remove csv export. Replace with our own implementation if necessary.
103
        if ($classConfig->export_csv) {
104
            $GridFieldExportButton = $this->getGridFieldExportButton($config);
105
            if ($GridFieldExportButton) {
106
                if ($classConfig->use_framework_csv) {
107
                    $GridFieldExportButton->setExportColumns(ExcelImportExport::exportFieldsForClass($class));
108
                } else {
109
                    $config->removeComponentsByType(GridFieldExportButton::class);
110
                    $ExcelGridFieldExportButton = new ExcelGridFieldExportButton('buttons-before-left');
111
                    $ExcelGridFieldExportButton->setExportType('csv');
112
                    $config->addComponent($ExcelGridFieldExportButton);
113
                }
114
            }
115
        } else {
116
            $config->removeComponentsByType(GridFieldExportButton::class);
117
        }
118
119
        // Add/remove csv export (add by default)
120
        if ($classConfig->export_excel) {
121
            $ExcelGridFieldExportButton = new ExcelGridFieldExportButton('buttons-before-left');
122
            $config->addComponent($ExcelGridFieldExportButton);
123
        }
124
125
        // Rename import button
126
        $config->removeComponentsByType(GridFieldImportButton::class);
127
        if ((is_bool($owner->showImportForm)
128
                && $owner->showImportForm)
129
            ||
130
            (is_array($owner->showImportForm)
131
                && in_array($class, $owner->showImportForm))
132
        ) {
133
            $importForm = $owner->ImportForm();
134
            if ($importForm) {
0 ignored issues
show
introduced by
The condition $importForm is always false.
Loading history...
135
                $ExcelGridFieldImportButton = new ExcelGridFieldImportButton('buttons-before-left');
136
                $ExcelGridFieldImportButton->setImportForm($importForm);
137
                $ExcelGridFieldImportButton->setModalTitle(_t('ExcelImportExport.IMPORTFROMFILE', 'Import from a file'));
138
                $config->addComponent($ExcelGridFieldImportButton);
139
            }
140
        }
141
    }
142
143
    /**
144
     * @param \SilverStripe\Forms\GridField\GridFieldConfig $config
145
     * @return GridFieldExportButton|null
146
     */
147
    protected function getGridFieldExportButton($config)
148
    {
149
        /** @var GridFieldExportButton|null $comp */
150
        $comp = $config->getComponentByType(GridFieldExportButton::class);
151
        if ($comp) {
152
            return $comp;
153
        }
154
        return null;
155
    }
156
157
    /**
158
     * @param Form $form
159
     * @return void
160
     */
161
    public function updateImportForm(Form $form)
162
    {
163
        /** @var ModelAdmin $owner */
164
        $owner = $this->owner;
165
        $class = $owner->getModelClass();
166
        $classConfig = $owner->config();
167
168
        $modelSNG = singleton($class);
169
        $modelConfig = $modelSNG->config();
170
        $modelName = $modelSNG->i18n_singular_name();
171
172
        $fields = $form->Fields();
173
174
        // We can implement a custom handler
175
        $importHandlers = [];
176
        $htmlDesc = '';
177
        $useDefaultSample = true;
178
        if ($modelSNG->hasMethod('listImportHandlers')) {
179
            $importHandlers = array_merge([
180
                'default' => _t('ExcelImportExport.DefaultHandler', 'Default import handler'),
181
            ], $modelSNG->listImportHandlers());
182
183
            $supportOnlyUpdate = [];
184
            foreach ($importHandlers as $class => $label) {
185
                if (!class_exists($class)) {
186
                    continue;
187
                }
188
                if (method_exists($class, 'setOnlyUpdate')) {
189
                    $supportOnlyUpdate[] = $class;
190
                }
191
                if (method_exists($class, 'getImportDescription')) {
192
                    $htmlDesc .= '<div class="js-import-desc" data-name="' . $class . '" hidden>' . $class::getImportDescription() . '</div>';
0 ignored issues
show
Bug introduced by
Are you sure $class of type object can be used in concatenation? ( Ignorable by Annotation )

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

192
                    $htmlDesc .= '<div class="js-import-desc" data-name="' . /** @scrutinizer ignore-type */ $class . '" hidden>' . $class::getImportDescription() . '</div>';
Loading history...
193
                }
194
                if (method_exists($class, 'getSampleFileLink')) {
195
                    $useDefaultSample = false;
196
                    $htmlDesc .= '<div class="js-import-desc" data-name="' . $class . '" hidden>' . $class::getSampleFileLink() . '</div>';
197
                }
198
            }
199
200
            if (!$useDefaultSample) {
0 ignored issues
show
introduced by
The condition $useDefaultSample is always true.
Loading history...
201
                $htmlDesc = '<div class="js-import-desc" data-name="default" hidden>' . ExcelImportExport::createDownloadSampleLink() . '</div>' . $htmlDesc;
202
            }
203
        }
204
205
        /** @var \SilverStripe\Forms\FileField|null $file */
206
        $file = $fields->dataFieldByName('_CsvFile');
207
        if ($file) {
0 ignored issues
show
introduced by
$file is of type SilverStripe\Forms\FileField, thus it always evaluated to true.
Loading history...
208
            $csvDescription = ExcelImportExport::getValidExtensionsText();
209
            if ($useDefaultSample) {
0 ignored issues
show
introduced by
The condition $useDefaultSample is always true.
Loading history...
210
                $downloadSample = ExcelImportExport::createDownloadSampleLink();
211
                $csvDescription .= '. ' . $downloadSample;
212
            }
213
            $file->setDescription($csvDescription);
214
            $file->getValidator()->setAllowedExtensions(ExcelImportExport::getValidExtensions());
215
        }
216
217
        // Hide by default, but allow on per class basis (opt-in)
218
        if ($classConfig->hide_replace_data && !$modelConfig->show_replace_data) {
219
            // This is way too dangerous and customers don't understand what this is most of the time
220
            $fields->removeByName("EmptyBeforeImport");
221
        }
222
        // If you cannot delete, you cannot empty
223
        if (!$modelSNG->canDelete()) {
224
            $fields->removeByName('EmptyBeforeImport');
225
        }
226
227
        // We moved the specs into a nice to use download sample button
228
        $fields->removeByName("SpecFor{$modelName}");
229
230
        if (!empty($importHandlers)) {
231
            $form->Fields()->push($OnlyUpdateRecords = new CheckboxField("OnlyUpdateRecords", _t('ExcelImportExport.OnlyUpdateRecords', "Only update records")));
232
            $OnlyUpdateRecords->setAttribute("data-handlers", implode(",", $supportOnlyUpdate));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $supportOnlyUpdate does not seem to be defined for all execution paths leading up to this point.
Loading history...
233
234
            $form->Fields()->push($ImportHandler = new OptionsetField("ImportHandler", _t('ExcelImportExport.PleaseSelectImportHandler', "Please select the import handler"), $importHandlers));
235
            // Simply check of this is supported or not for the given handler (if not, disable it)
236
            $js = <<<JS
237
var desc=document.querySelectorAll('.js-import-desc');var cb=document.querySelector('#OnlyUpdateRecords');var accepted=cb.dataset.handlers.split(',');var item=([...this.querySelectorAll('input')].filter((input) => input.checked)[0]); cb.disabled=(item && accepted.includes(item.value)) ? '': 'disabled';desc.forEach((el)=>el.hidden=!item||el.dataset.name!=item.value);;
238
JS;
239
            $ImportHandler->setAttribute("onclick", $js);
240
            if ($htmlDesc) {
241
                $ImportHandler->setDescription($htmlDesc); // Description is an HTMLFragment
242
            }
243
        }
244
245
        $actions = $form->Actions();
246
247
        // Update import button
248
        $import = $actions->dataFieldByName('action_import');
249
        if ($import) {
250
            $import->setTitle(_t(
251
                'ExcelImportExport.ImportExcel',
252
                "Import from Excel"
253
            ));
254
            $import->removeExtraClass('btn-outline-secondary');
255
            $import->addExtraClass('btn-primary');
256
        }
257
    }
258
}
259