These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 as a media object |
||
37 | */ |
||
38 | const TYPE_INSERT_MEDIA = 'insert-media'; |
||
39 | |||
40 | /** |
||
41 | * Insert into HTML content area as a link |
||
42 | */ |
||
43 | const TYPE_INSERT_LINK = 'insert-link'; |
||
44 | |||
45 | /** |
||
46 | * Select file by ID only |
||
47 | */ |
||
48 | const TYPE_SELECT = 'select'; |
||
49 | |||
50 | /** |
||
51 | * Edit form: Default |
||
52 | */ |
||
53 | const TYPE_ADMIN = 'admin'; |
||
54 | |||
55 | public function __construct() |
||
56 | { |
||
57 | $this->constructExtensions(); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * @param RequestHandler $controller |
||
62 | * @param string $name |
||
63 | * @param array $context |
||
64 | * @return Form |
||
65 | */ |
||
66 | public function getForm(RequestHandler $controller = null, $name = FormFactory::DEFAULT_NAME, $context = []) |
||
67 | { |
||
68 | // Validate context |
||
69 | foreach ($this->getRequiredContext() as $required) { |
||
70 | if (!isset($context[$required])) { |
||
71 | throw new InvalidArgumentException("Missing required context $required"); |
||
72 | } |
||
73 | } |
||
74 | |||
75 | $fields = $this->getFormFields($controller, $name, $context); |
||
76 | $actions = $this->getFormActions($controller, $name, $context); |
||
77 | $validator = $this->getValidator($controller, $name, $context); |
||
78 | $form = Form::create($controller, $name, $fields, $actions, $validator); |
||
79 | |||
80 | // Extend form |
||
81 | $this->invokeWithExtensions('updateForm', $form, $controller, $name, $context); |
||
82 | |||
83 | // Populate form from record |
||
84 | if (isset($context['Record'])) { |
||
85 | /** @var File $record */ |
||
86 | $record = $context['Record']; |
||
87 | $form->loadDataFrom($record); |
||
88 | |||
89 | if (!$record->canEdit()) { |
||
90 | $form->makeReadonly(); |
||
91 | } |
||
92 | } |
||
93 | |||
94 | $form->addExtraClass('form--fill-height form--padded'); |
||
95 | |||
96 | return $form; |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Get the validator for the form to be built |
||
101 | * |
||
102 | * @param RequestHandler $controller |
||
103 | * @param $formName |
||
104 | * @param $context |
||
105 | * @return RequiredFields |
||
106 | */ |
||
107 | protected function getValidator(RequestHandler $controller = null, $formName, $context = []) |
||
108 | { |
||
109 | $validator = new RequiredFields('Name'); |
||
110 | |||
111 | return $validator; |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Get form type from 'type' context |
||
116 | * |
||
117 | * @param array $context |
||
118 | * @return string |
||
119 | */ |
||
120 | protected function getFormType($context) |
||
121 | { |
||
122 | return empty($context['Type']) ? static::TYPE_ADMIN : $context['Type']; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Gets the main tabs for the file edit form |
||
127 | * |
||
128 | * @param File $record |
||
129 | * @param array $context |
||
130 | * @return TabSet |
||
131 | */ |
||
132 | protected function getFormFieldTabs($record, $context = []) |
||
133 | { |
||
134 | return TabSet::create( |
||
135 | 'Editor', |
||
136 | [ |
||
137 | $this->getFormFieldDetailsTab($record, $context), |
||
138 | $this->getFormFieldSecurityTab($record, $context), |
||
139 | ] |
||
140 | ); |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * @param File $record |
||
145 | * @return FormAction |
||
146 | */ |
||
147 | View Code Duplication | protected function getSaveAction($record) |
|
148 | { |
||
149 | if ($record && $record->isInDB() && $record->canEdit()) { |
||
150 | return FormAction::create('save', _t('SilverStripe\\CMS\\Controllers\\CMSMain.SAVE', 'Save')) |
||
151 | ->setIcon('save'); |
||
152 | } |
||
153 | return null; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Get delete action, if this record is deletable |
||
158 | * |
||
159 | * @param File $record |
||
160 | * @return FormAction |
||
161 | */ |
||
162 | View Code Duplication | protected function getDeleteAction($record) |
|
0 ignored issues
–
show
|
|||
163 | { |
||
164 | // Delete action |
||
165 | if ($record && $record->isInDB() && $record->canDelete()) { |
||
166 | $deleteText = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.DELETE_BUTTON', 'Delete'); |
||
167 | return FormAction::create('delete', $deleteText) |
||
168 | ->setIcon('trash-bin'); |
||
169 | } |
||
170 | return null; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @param RequestHandler $controller |
||
175 | * @param $formName |
||
176 | * @param array $context |
||
177 | * @return FieldList |
||
178 | */ |
||
179 | protected function getFormActions(RequestHandler $controller = null, $formName, $context = []) |
||
180 | { |
||
181 | $record = isset($context['Record']) ? $context['Record'] : null; |
||
182 | |||
183 | $actions = new FieldList(); |
||
184 | if ($saveAction = $this->getSaveAction($record)) { |
||
185 | $actions->push($saveAction); |
||
186 | } |
||
187 | $menu = $this->getPopoverMenu($record); |
||
188 | if ($menu && $menu->FieldList()->count()) { |
||
189 | $actions->push($menu); |
||
190 | } |
||
191 | |||
192 | $this->invokeWithExtensions('updateFormActions', $actions, $controller, $formName, $context); |
||
193 | return $actions; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Get fields for this form |
||
198 | * |
||
199 | * @param RequestHandler $controller |
||
200 | * @param string $formName |
||
201 | * @param array $context |
||
202 | * @return FieldList |
||
203 | */ |
||
204 | protected function getFormFields(RequestHandler $controller = null, $formName, $context = []) |
||
205 | { |
||
206 | $record = isset($context['Record']) ? $context['Record'] : null; |
||
207 | |||
208 | // Build standard fields for all folders / files |
||
209 | /** @var File $record */ |
||
210 | $fields = new FieldList( |
||
211 | HeaderField::create('TitleHeader', $record ? $record->Title : null, 1) |
||
212 | ->addExtraClass('editor__heading'), |
||
213 | $this->getFormFieldTabs($record, $context) |
||
214 | ); |
||
215 | if ($record) { |
||
216 | $fields->push(HiddenField::create('ID', $record->ID)); |
||
217 | $fields->insertAfter( |
||
218 | 'TitleHeader', |
||
219 | PreviewImageField::create('PreviewImage') |
||
220 | ->setRecordID($record->ID) |
||
221 | ->addExtraClass('editor__file-preview') |
||
222 | ); |
||
223 | } |
||
224 | |||
225 | $this->invokeWithExtensions('updateFormFields', $fields, $controller, $formName, $context); |
||
226 | return $fields; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Build popup menu |
||
231 | * |
||
232 | * @param File $record |
||
233 | * @return PopoverField |
||
234 | */ |
||
235 | protected function getPopoverMenu($record) |
||
236 | { |
||
237 | // Build popover actions |
||
238 | $popoverActions = $this->getPopoverActions($record); |
||
239 | if ($popoverActions) { |
||
240 | return PopoverField::create($popoverActions) |
||
241 | ->setPlacement('top') |
||
242 | ->setName('PopoverActions') |
||
243 | ->setButtonTooltip(_t( |
||
244 | 'SilverStripe\\AssetAdmin\\Forms\\FileFormFactory.OTHER_ACTIONS', |
||
245 | 'Other actions' |
||
246 | )); |
||
247 | } |
||
248 | return null; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Get actions that go into the Popover menu |
||
253 | * |
||
254 | * @param File $record |
||
255 | * @return array |
||
256 | */ |
||
257 | protected function getPopoverActions($record) |
||
258 | { |
||
259 | $actions = [ |
||
260 | $this->getDeleteAction($record) |
||
261 | ]; |
||
262 | |||
263 | $this->invokeWithExtensions('updatePopoverActions', $actions, $record); |
||
264 | return array_filter($actions); |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Build "details" formfield tab |
||
269 | * |
||
270 | * @param File $record |
||
271 | * @param array $context |
||
272 | * @return Tab |
||
273 | */ |
||
274 | protected function getFormFieldDetailsTab($record, $context = []) |
||
275 | { |
||
276 | /** @var Tab $tab */ |
||
277 | $tab = Tab::create( |
||
278 | 'Details', |
||
279 | TextField::create('Name', File::singleton()->fieldLabel('Filename')), |
||
280 | $location = TreeDropdownField::create('ParentID', 'FolderLocation', Folder::class), |
||
281 | ReadonlyField::create( |
||
282 | "Path", |
||
283 | _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.PATH', 'Path'), |
||
284 | $this->getPath($record, $context) |
||
285 | ) |
||
286 | ); |
||
287 | |||
288 | $location->setEmptyString('(root)'); |
||
289 | return $tab; |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Get user-visible "Path" for this record |
||
294 | * |
||
295 | * @param File $record |
||
296 | * @param array $context |
||
297 | * @return string |
||
298 | */ |
||
299 | protected function getPath($record, $context = []) |
||
300 | { |
||
301 | if ($record && $record->isInDB()) { |
||
302 | if ($record->ParentID) { |
||
303 | return $record->Parent()->getFilename(); |
||
304 | } else { |
||
305 | return '/'; |
||
306 | } |
||
307 | } |
||
308 | if (isset($context['ParentID'])) { |
||
309 | if ($context['ParentID'] === 0) { |
||
310 | return '/'; |
||
311 | } |
||
312 | $file = File::get()->byID($context['ParentID']); |
||
313 | if ($file) { |
||
314 | return $file->getFilename(); |
||
315 | } |
||
316 | } |
||
317 | return null; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Build security tab |
||
322 | * |
||
323 | * @param File $record |
||
324 | * @param array $context |
||
325 | * @return Tab |
||
326 | */ |
||
327 | protected function getFormFieldSecurityTab($record, $context = []) |
||
328 | { |
||
329 | // Get groups |
||
330 | $groupsMap = array(); |
||
331 | foreach (Group::get() as $group) { |
||
332 | $groupsMap[$group->ID] = $group->getBreadcrumbs(' > '); |
||
333 | } |
||
334 | asort($groupsMap); |
||
335 | |||
336 | // Get permissions |
||
337 | $viewersOptionsField = [ |
||
338 | 'Inherit' => _t(__CLASS__.'.INHERIT', 'Inherit from parent folder'), |
||
339 | 'Anyone' => _t(__CLASS__.'.ANYONE', 'Anyone'), |
||
340 | 'LoggedInUsers' => _t(__CLASS__.'.LOGGED_IN', 'Logged-in users'), |
||
341 | 'OnlyTheseUsers' => _t(__CLASS__.'.ONLY_GROUPS', 'Only these people (choose from list)') |
||
342 | ]; |
||
343 | |||
344 | // No "Anyone" editors option |
||
345 | $editorsOptionsField = $viewersOptionsField; |
||
346 | unset($editorsOptionsField['Anyone']); |
||
347 | |||
348 | return Tab::create( |
||
349 | 'Permissions', |
||
350 | OptionsetField::create( |
||
351 | 'CanViewType', |
||
352 | _t(__CLASS__.'.ACCESSHEADER', 'Who can view this file?') |
||
353 | ) |
||
354 | ->setSource($viewersOptionsField), |
||
355 | CheckboxSetField::create('ViewerGroups', _t(__CLASS__.'.VIEWERGROUPS', 'Viewer Groups')) |
||
356 | ->setSource($groupsMap), |
||
357 | OptionsetField::create( |
||
358 | "CanEditType", |
||
359 | _t(__CLASS__.'.EDITHEADER', 'Who can edit this file?') |
||
360 | ) |
||
361 | ->setSource($editorsOptionsField), |
||
362 | CheckboxSetField::create('EditorGroups', _t(__CLASS__.'.EDITORGROUPS', 'Editor Groups')) |
||
363 | ->setSource($groupsMap) |
||
364 | ); |
||
365 | } |
||
366 | |||
367 | public function getRequiredContext() |
||
368 | { |
||
369 | return ['Record']; |
||
370 | } |
||
371 | } |
||
372 |
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.