Completed
Push — master ( 916d56...6e2c74 )
by Damian
02:26
created

AssetFormFactory::getPath()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 20
rs 8.2222
cc 7
eloc 13
nc 6
nop 2
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Forms;
4
5
use InvalidArgumentException;
6
use SilverStripe\Assets\File;
7
use SilverStripe\Control\RequestHandler;
8
use SilverStripe\Assets\Folder;
9
use SilverStripe\Core\Config\Configurable;
10
use SilverStripe\Core\Extensible;
11
use SilverStripe\Core\Injector\Injectable;
12
use SilverStripe\Forms\CheckboxSetField;
13
use SilverStripe\Forms\FieldList;
14
use SilverStripe\Forms\Form;
15
use SilverStripe\Forms\FormAction;
16
use SilverStripe\Forms\FormFactory;
17
use SilverStripe\Forms\HeaderField;
18
use SilverStripe\Forms\HiddenField;
19
use SilverStripe\Forms\OptionsetField;
20
use SilverStripe\Forms\PopoverField;
21
use SilverStripe\Forms\ReadonlyField;
22
use SilverStripe\Forms\RequiredFields;
23
use SilverStripe\Forms\Tab;
24
use SilverStripe\Forms\TabSet;
25
use SilverStripe\Forms\TextField;
26
use SilverStripe\Security\Group;
27
use SilverStripe\Forms\TreeDropdownField;
28
29
abstract class AssetFormFactory implements FormFactory
30
{
31
    use Extensible;
32
    use Injectable;
33
    use Configurable;
34
35
    /**
36
     * Insert into HTML content area
37
     */
38
    const TYPE_INSERT = 'insert';
39
40
    /**
41
     * Select file by ID only
42
     */
43
    const TYPE_SELECT = 'select';
44
45
    /**
46
     * Edit form: Default
47
     */
48
    const TYPE_ADMIN = 'admin';
49
50
    public function __construct()
51
    {
52
        $this->constructExtensions();
53
    }
54
55
    /**
56
     * @param RequestHandler $controller
57
     * @param string $name
58
     * @param array $context
59
     * @return Form
60
     */
61
    public function getForm(RequestHandler $controller = null, $name = FormFactory::DEFAULT_NAME, $context = [])
62
    {
63
        // Validate context
64
        foreach ($this->getRequiredContext() as $required) {
65
            if (!isset($context[$required])) {
66
                throw new InvalidArgumentException("Missing required context $required");
67
            }
68
        }
69
70
        $fields = $this->getFormFields($controller, $name, $context);
71
        $actions = $this->getFormActions($controller, $name, $context);
72
        $validator = $this->getValidator($controller, $name, $context);
73
        $form = Form::create($controller, $name, $fields, $actions, $validator);
74
75
        // Extend form
76
        $this->invokeWithExtensions('updateForm', $form, $controller, $name, $context);
77
78
        // Populate form from record
79
        if (isset($context['Record'])) {
80
            /** @var File $record */
81
            $record = $context['Record'];
82
            $form->loadDataFrom($record);
83
84
            if (!$record->canEdit()) {
85
                $form->makeReadonly();
86
            }
87
        }
88
89
        $form->addExtraClass('form--fill-height form--padded');
90
91
        return $form;
92
    }
93
94
    /**
95
     * Get the validator for the form to be built
96
     *
97
     * @param RequestHandler $controller
98
     * @param $formName
99
     * @param $context
100
     * @return RequiredFields
101
     */
102
    protected function getValidator(RequestHandler $controller = null, $formName, $context = [])
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $formName is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $context is not used and could be removed.

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

Loading history...
103
    {
104
        $validator = new RequiredFields('Name');
105
106
        return $validator;
107
    }
108
109
    /**
110
     * Get form type from 'type' context
111
     *
112
     * @param array $context
113
     * @return string
114
     */
115
    protected function getFormType($context)
116
    {
117
        return empty($context['Type']) ? static::TYPE_ADMIN : $context['Type'];
118
    }
119
120
    /**
121
     * Gets the main tabs for the file edit form
122
     *
123
     * @param File $record
124
     * @param array $context
125
     * @return TabSet
126
     */
127
    protected function getFormFieldTabs($record, $context = [])
128
    {
129
        return TabSet::create(
130
            'Editor',
131
            [
132
                $this->getFormFieldDetailsTab($record, $context),
133
                $this->getFormFieldSecurityTab($record, $context),
134
            ]
135
        );
136
    }
137
138
    /**
139
     * @param File $record
140
     * @return FormAction
141
     */
142 View Code Duplication
    protected function getSaveAction($record)
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...
143
    {
144
        if ($record && $record->isInDB() && $record->canEdit()) {
145
            return FormAction::create('save', _t('SilverStripe\\CMS\\Controllers\\CMSMain.SAVE', 'Save'))
146
                ->setIcon('save');
147
        }
148
        return null;
149
    }
150
151
    /**
152
     * Get delete action, if this record is deletable
153
     *
154
     * @param File $record
155
     * @return FormAction
156
     */
157 View Code Duplication
    protected function getDeleteAction($record)
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...
158
    {
159
        // Delete action
160
        if ($record && $record->isInDB() && $record->canDelete()) {
161
            $deleteText = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.DELETE_BUTTON', 'Delete');
162
            return FormAction::create('delete', $deleteText)
163
                ->setIcon('trash-bin');
164
        }
165
        return null;
166
    }
167
168
    /**
169
     * @param RequestHandler $controller
170
     * @param $formName
171
     * @param array $context
172
     * @return FieldList
173
     */
174
    protected function getFormActions(RequestHandler $controller = null, $formName, $context = [])
175
    {
176
        $record = isset($context['Record']) ? $context['Record'] : null;
177
178
        $actions = new FieldList();
179
        if ($saveAction = $this->getSaveAction($record)) {
180
            $actions->push($saveAction);
181
        }
182
        $menu = $this->getPopoverMenu($record);
183
        if ($menu && $menu->FieldList()->count()) {
184
            $actions->push($menu);
185
        }
186
187
        $this->invokeWithExtensions('updateFormActions', $actions, $controller, $formName, $context);
188
        return $actions;
189
    }
190
191
    /**
192
     * Get fields for this form
193
     *
194
     * @param RequestHandler $controller
195
     * @param string $formName
196
     * @param array $context
197
     * @return FieldList
198
     */
199
    protected function getFormFields(RequestHandler $controller = null, $formName, $context = [])
200
    {
201
        $record = isset($context['Record']) ? $context['Record'] : null;
202
203
        // Build standard fields for all folders / files
204
        /** @var File $record */
205
        $fields = new FieldList(
206
            HeaderField::create('TitleHeader', $record ? $record->Title : null, 1)
207
                ->addExtraClass('editor__heading'),
208
            $this->getFormFieldTabs($record, $context)
209
        );
210
        if ($record) {
211
            $fields->push(HiddenField::create('ID', $record->ID));
212
            $fields->insertAfter(
213
                'TitleHeader',
214
                PreviewImageField::create('PreviewImage')
215
                    ->setRecordID($record->ID)
216
                    ->addExtraClass('editor__file-preview')
217
            );
218
        }
219
220
        $this->invokeWithExtensions('updateFormFields', $fields, $controller, $formName, $context);
221
        return $fields;
222
    }
223
224
    /**
225
     * Build popup menu
226
     *
227
     * @param File $record
228
     * @return PopoverField
229
     */
230
    protected function getPopoverMenu($record)
231
    {
232
        // Build popover actions
233
        $popoverActions = $this->getPopoverActions($record);
234
        if ($popoverActions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $popoverActions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
235
            return PopoverField::create($popoverActions)
236
                ->setPlacement('top')
237
                ->setName('PopoverActions')
238
                ->setButtonTooltip(_t(
239
                    'SilverStripe\\AssetAdmin\\Forms\\FileFormFactory.OTHER_ACTIONS',
240
                    'Other actions'
241
                ));
242
        }
243
        return null;
244
    }
245
246
    /**
247
     * Get actions that go into the Popover menu
248
     *
249
     * @param File $record
250
     * @return array
251
     */
252
    protected function getPopoverActions($record)
253
    {
254
        $actions = [
255
            $this->getDeleteAction($record)
256
        ];
257
258
        $this->invokeWithExtensions('updatePopoverActions', $actions, $record);
259
        return array_filter($actions);
260
    }
261
262
    /**
263
     * Build "details" formfield tab
264
     *
265
     * @param File $record
266
     * @param array $context
267
     * @return Tab
268
     */
269
    protected function getFormFieldDetailsTab($record, $context = [])
270
    {
271
        /** @var Tab $tab */
272
        $tab = Tab::create(
273
            'Details',
274
            TextField::create('Name', File::singleton()->fieldLabel('Filename')),
275
            $location = TreeDropdownField::create('ParentID', 'FolderLocation', Folder::class),
276
            ReadonlyField::create(
277
                "Path",
278
                _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.PATH', 'Path'),
279
                $this->getPath($record, $context)
280
            )
281
        );
282
        
283
        $location->setEmptyString('(root)');
284
        return $tab;
285
    }
286
    
287
    /**
288
     * Get user-visible "Path" for this record
289
     *
290
     * @param File $record
291
     * @return string
292
     */
293
    protected function getPath($record, $context = [])
294
    {
295
        if ($record && $record->isInDB()) {
296
            if ($record->ParentID) {
297
                return $record->Parent()->getFilename();
298
            } else {
299
                return '/';
300
            }
301
        }
302
        if (isset($context['ParentID'])) {
303
            if ($context['ParentID'] === 0) {
304
                return '/';
305
            }
306
            $file = File::get()->byID($context['ParentID']);
307
            if ($file) {
308
                return $file->getFilename();
309
            }
310
        }
311
        return null;
312
    }
313
314
    /**
315
     * Build security tab
316
     *
317
     * @param File $record
318
     * @param array $context
319
     * @return Tab
320
     */
321
    protected function getFormFieldSecurityTab($record, $context = [])
0 ignored issues
show
Unused Code introduced by
The parameter $record is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $context is not used and could be removed.

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

Loading history...
322
    {
323
        // Get groups
324
        $groupsMap = array();
325
        foreach (Group::get() as $group) {
326
            $groupsMap[$group->ID] = $group->getBreadcrumbs(' > ');
327
        }
328
        asort($groupsMap);
329
330
        // Get permissions
331
        $viewersOptionsField = [
332
            'Inherit' => _t(__CLASS__.'.INHERIT', 'Inherit from parent folder'),
333
            'Anyone' => _t(__CLASS__.'.ANYONE', 'Anyone'),
334
            'LoggedInUsers' => _t(__CLASS__.'.LOGGED_IN', 'Logged-in users'),
335
            'OnlyTheseUsers' => _t(__CLASS__.'.ONLY_GROUPS', 'Only these people (choose from list)')
336
        ];
337
338
        // No "Anyone" editors option
339
        $editorsOptionsField = $viewersOptionsField;
340
        unset($editorsOptionsField['Anyone']);
341
342
        return Tab::create(
343
            'Permissions',
344
            OptionsetField::create(
345
                'CanViewType',
346
                _t(__CLASS__.'.ACCESSHEADER', 'Who can view this file?')
347
            )
348
                ->setSource($viewersOptionsField),
349
            CheckboxSetField::create('ViewerGroups', _t(__CLASS__.'.VIEWERGROUPS', 'Viewer Groups'))
350
                ->setSource($groupsMap),
351
            OptionsetField::create(
352
                "CanEditType",
353
                _t(__CLASS__.'.EDITHEADER', 'Who can edit this file?')
354
            )
355
                ->setSource($editorsOptionsField),
356
            CheckboxSetField::create('EditorGroups', _t(__CLASS__.'.EDITORGROUPS', 'Editor Groups'))
357
                ->setSource($groupsMap)
358
        );
359
    }
360
361
    public function getRequiredContext()
362
    {
363
        return ['Record'];
364
    }
365
}
366