Completed
Pull Request — master (#406)
by Damian
02:06
created

AssetAdmin::remoteCreateForm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Controller;
4
5
use Embed\Exceptions\InvalidUrlException;
6
use InvalidArgumentException;
7
use SilverStripe\Admin\AddToCampaignHandler;
8
use SilverStripe\Admin\CMSBatchActionHandler;
9
use SilverStripe\Admin\LeftAndMain;
10
use SilverStripe\AssetAdmin\BatchAction\DeleteAssets;
11
use SilverStripe\AssetAdmin\Forms\AssetFormFactory;
12
use SilverStripe\AssetAdmin\Forms\FileSearchFormFactory;
13
use SilverStripe\AssetAdmin\Forms\RemoteFileFormFactory;
14
use SilverStripe\AssetAdmin\Forms\UploadField;
15
use SilverStripe\AssetAdmin\Forms\FileFormFactory;
16
use SilverStripe\AssetAdmin\Forms\FolderFormFactory;
17
use SilverStripe\AssetAdmin\Forms\FileHistoryFormFactory;
18
use SilverStripe\AssetAdmin\Forms\ImageFormFactory;
19
use SilverStripe\Assets\File;
20
use SilverStripe\Assets\Folder;
21
use SilverStripe\Assets\Image;
22
use SilverStripe\Assets\Storage\AssetNameGenerator;
23
use SilverStripe\Assets\Upload;
24
use SilverStripe\Control\Controller;
25
use SilverStripe\Control\HTTPRequest;
26
use SilverStripe\Control\HTTPResponse;
27
use SilverStripe\Control\RequestHandler;
28
use SilverStripe\Core\Injector\Injector;
29
use SilverStripe\Forms\FieldList;
30
use SilverStripe\Forms\Form;
31
use SilverStripe\Forms\FormFactory;
32
use SilverStripe\ORM\ArrayList;
33
use SilverStripe\ORM\DataObject;
34
use SilverStripe\ORM\FieldType\DBHTMLText;
35
use SilverStripe\ORM\ValidationResult;
36
use SilverStripe\Security\Member;
37
use SilverStripe\Security\PermissionProvider;
38
use SilverStripe\Security\SecurityToken;
39
use SilverStripe\View\Requirements;
40
use SilverStripe\ORM\Versioning\Versioned;
41
use Exception;
42
43
/**
44
 * AssetAdmin is the 'file store' section of the CMS.
45
 * It provides an interface for manipulating the File and Folder objects in the system.
46
 */
47
class AssetAdmin extends LeftAndMain implements PermissionProvider
48
{
49
    private static $url_segment = 'assets';
0 ignored issues
show
Unused Code introduced by
The property $url_segment is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
50
51
    private static $url_rule = '/$Action/$ID';
0 ignored issues
show
Unused Code introduced by
The property $url_rule is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
52
53
    private static $menu_title = 'Files';
0 ignored issues
show
Unused Code introduced by
The property $menu_title is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
54
55
    private static $menu_icon_class = 'font-icon-image';
0 ignored issues
show
Unused Code introduced by
The property $menu_icon_class is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
56
57
    private static $tree_class = 'SilverStripe\\Assets\\Folder';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $tree_class is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
58
59
    private static $url_handlers = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $url_handlers is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
60
        // Legacy redirect for SS3-style detail view
61
        'EditForm/field/File/item/$FileID/$Action' => 'legacyRedirectForEditView',
62
        // Pass all URLs to the index, for React to unpack
63
        'show/$FolderID/edit/$FileID' => 'index',
64
        // API access points with structured data
65
        'POST api/createFile' => 'apiCreateFile',
66
        'POST api/uploadFile' => 'apiUploadFile',
67
        'GET api/history' => 'apiHistory',
68
        // for validating before generating the schema
69
        'schemaWithValidate/$FormName' => 'schemaWithValidate'
70
    ];
71
72
    /**
73
     * Amount of results showing on a single page.
74
     *
75
     * @config
76
     * @var int
77
     */
78
    private static $page_length = 15;
0 ignored issues
show
Unused Code introduced by
The property $page_length is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
79
80
    /**
81
     * @config
82
     * @see Upload->allowedMaxFileSize
83
     * @var int
84
     */
85
    private static $allowed_max_file_size;
0 ignored issues
show
Unused Code introduced by
The property $allowed_max_file_size is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
86
87
    /**
88
     * @config
89
     *
90
     * @var int
91
     */
92
    private static $max_history_entries = 100;
0 ignored issues
show
Unused Code introduced by
The property $max_history_entries is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
93
94
    /**
95
     * @var array
96
     */
97
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
98
        'legacyRedirectForEditView',
99
        'apiCreateFile',
100
        'apiUploadFile',
101
        'apiHistory',
102
        'fileEditForm',
103
        'fileHistoryForm',
104
        'addToCampaignForm',
105
        'fileInsertForm',
106
        'remoteEditForm',
107
        'remoteCreateForm',
108
        'schema',
109
        'fileSelectForm',
110
        'fileSearchForm',
111
        'schemaWithValidate',
112
    );
113
114
    private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $required_permission_codes is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
115
116
    private static $thumbnail_width = 400;
0 ignored issues
show
Unused Code introduced by
The property $thumbnail_width is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
117
118
    private static $thumbnail_height = 300;
0 ignored issues
show
Unused Code introduced by
The property $thumbnail_height is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
119
120
    /**
121
     * Set up the controller
122
     */
123
    public function init()
124
    {
125
        parent::init();
126
127
        Requirements::add_i18n_javascript(ASSET_ADMIN_DIR . '/client/lang', false, true);
128
        Requirements::javascript(ASSET_ADMIN_DIR . "/client/dist/js/bundle.js");
129
        Requirements::css(ASSET_ADMIN_DIR . "/client/dist/styles/bundle.css");
130
131
        CMSBatchActionHandler::register('delete', DeleteAssets::class, Folder::class);
132
    }
133
134
    public function getClientConfig()
135
    {
136
        $baseLink = $this->Link();
137
        return array_merge(parent::getClientConfig(), [
138
            'reactRouter' => true,
139
            'createFileEndpoint' => [
140
                'url' => Controller::join_links($baseLink, 'api/createFile'),
141
                'method' => 'post',
142
                'payloadFormat' => 'urlencoded',
143
            ],
144
            'uploadFileEndpoint' => [
145
                'url' => Controller::join_links($baseLink, 'api/uploadFile'),
146
                'method' => 'post',
147
                'payloadFormat' => 'urlencoded',
148
            ],
149
            'historyEndpoint' => [
150
                'url' => Controller::join_links($baseLink, 'api/history'),
151
                'method' => 'get',
152
                'responseFormat' => 'json',
153
            ],
154
            'limit' => $this->config()->page_length,
155
            'form' => [
156
                'fileEditForm' => [
157
                    'schemaUrl' => $this->Link('schema/fileEditForm')
158
                ],
159
                'fileInsertForm' => [
160
                    'schemaUrl' => $this->Link('schema/fileInsertForm')
161
                ],
162
                'remoteEditForm' => [
163
                    'schemaUrl' => $this->Link('schemaWithValidate/remoteEditForm')
164
                ],
165
                'remoteCreateForm' => [
166
                    'schemaUrl' => $this->Link('schema/remoteCreateForm')
167
                ],
168
                'fileSelectForm' => [
169
                    'schemaUrl' => $this->Link('schema/fileSelectForm')
170
                ],
171
                'addToCampaignForm' => [
172
                    'schemaUrl' => $this->Link('schema/addToCampaignForm')
173
                ],
174
                'fileHistoryForm' => [
175
                    'schemaUrl' => $this->Link('schema/fileHistoryForm')
176
                ],
177
                'fileSearchForm' => [
178
                    'schemaUrl' => $this->Link('schema/fileSearchForm')
179
                ],
180
            ],
181
        ]);
182
    }
183
184
    /**
185
     * Creates a single file based on a form-urlencoded upload.
186
     *
187
     * @param HTTPRequest $request
188
     * @return HTTPRequest|HTTPResponse
189
     */
190
    public function apiCreateFile(HTTPRequest $request)
191
    {
192
        $data = $request->postVars();
193
194
        // When creating new files, rename on conflict
195
        $upload = $this->getUpload();
196
        $upload->setReplaceFile(false);
197
198
        // CSRF check
199
        $token = SecurityToken::inst();
200 View Code Duplication
        if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
201
            return new HTTPResponse(null, 400);
202
        }
203
204
        // Check parent record
205
        /** @var Folder $parentRecord */
206
        $parentRecord = null;
207
        if (!empty($data['ParentID']) && is_numeric($data['ParentID'])) {
208
            $parentRecord = Folder::get()->byID($data['ParentID']);
209
        }
210
        $data['Parent'] = $parentRecord;
211
212
        $tmpFile = $request->postVar('Upload');
213 View Code Duplication
        if (!$upload->validate($tmpFile)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
214
            $result = ['message' => null];
215
            $errors = $upload->getErrors();
216
            if ($message = array_shift($errors)) {
217
                $result['message'] = [
218
                    'type' => 'error',
219
                    'value' => $message,
220
                ];
221
            }
222
            return (new HTTPResponse(json_encode($result), 400))
223
                ->addHeader('Content-Type', 'application/json');
224
        }
225
226
        // TODO Allow batch uploads
227
        $fileClass = File::get_class_for_file_extension(File::get_file_extension($tmpFile['name']));
228
        /** @var File $file */
229
        $file = Injector::inst()->create($fileClass);
230
231
        // check canCreate permissions
232 View Code Duplication
        if (!$file->canCreate(null, $data)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
233
            $result = ['message' => [
234
                'type' => 'error',
235
                'value' => _t(
236
                    'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.CreatePermissionDenied',
237
                    'You do not have permission to add files'
238
                )
239
            ]];
240
            return (new HTTPResponse(json_encode($result), 403))
241
                ->addHeader('Content-Type', 'application/json');
242
        }
243
244
        $uploadResult = $upload->loadIntoFile($tmpFile, $file, $parentRecord ? $parentRecord->getFilename() : '/');
245 View Code Duplication
        if (!$uploadResult) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
246
            $result = ['message' => [
247
                'type' => 'error',
248
                'value' => _t(
249
                    'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.LoadIntoFileFailed',
250
                    'Failed to load file'
251
                )
252
            ]];
253
            return (new HTTPResponse(json_encode($result), 400))
254
                ->addHeader('Content-Type', 'application/json');
255
        }
256
257
        $file->ParentID = $parentRecord ? $parentRecord->ID : 0;
258
        $file->write();
259
260
        $result = [$this->getObjectFromData($file)];
261
262
        return (new HTTPResponse(json_encode($result)))
263
            ->addHeader('Content-Type', 'application/json');
264
    }
265
266
    /**
267
     * Upload a new asset for a pre-existing record. Returns the asset tuple.
268
     *
269
     * Note that conflict resolution is as follows:
270
     *  - If uploading a file with the same extension, we simply keep the same filename,
271
     *    and overwrite any existing files (same name + sha = don't duplicate).
272
     *  - If uploading a new file with a different extension, then the filename will
273
     *    be replaced, and will be checked for uniqueness against other File dataobjects.
274
     *
275
     * @param HTTPRequest $request Request containing vars 'ID' of parent record ID,
276
     * and 'Name' as form filename value
277
     * @return HTTPRequest|HTTPResponse
278
     */
279
    public function apiUploadFile(HTTPRequest $request)
280
    {
281
        $data = $request->postVars();
282
283
        // When updating files, replace on conflict
284
        $upload = $this->getUpload();
285
        $upload->setReplaceFile(true);
286
287
        // CSRF check
288
        $token = SecurityToken::inst();
289 View Code Duplication
        if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
290
            return new HTTPResponse(null, 400);
291
        }
292
        $tmpFile = $data['Upload'];
293
        if (empty($data['ID']) || empty($tmpFile['name']) || !array_key_exists('Name', $data)) {
294
            return new HTTPResponse('Invalid request', 400);
295
        }
296
297
        // Check parent record
298
        /** @var File $file */
299
        $file = File::get()->byID($data['ID']);
300
        if (!$file) {
301
            return new HTTPResponse('File not found', 404);
302
        }
303
        $folder = $file->ParentID ? $file->Parent()->getFilename() : '/';
304
305
        // If extension is the same, attempt to re-use existing name
306
        if (File::get_file_extension($tmpFile['name']) === File::get_file_extension($data['Name'])) {
307
            $tmpFile['name'] = $data['Name'];
308
        } else {
309
            // If we are allowing this upload to rename the underlying record,
310
            // do a uniqueness check.
311
            $renamer = $this->getNameGenerator($tmpFile['name']);
312
            foreach ($renamer as $name) {
313
                $filename = File::join_paths($folder, $name);
314
                if (!File::find($filename)) {
315
                    $tmpFile['name'] = $name;
316
                    break;
317
                }
318
            }
319
        }
320
321 View Code Duplication
        if (!$upload->validate($tmpFile)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
322
            $result = ['message' => null];
323
            $errors = $upload->getErrors();
324
            if ($message = array_shift($errors)) {
325
                $result['message'] = [
326
                    'type' => 'error',
327
                    'value' => $message,
328
                ];
329
            }
330
            return (new HTTPResponse(json_encode($result), 400))
331
                ->addHeader('Content-Type', 'application/json');
332
        }
333
334
        try {
335
            $tuple = $upload->load($tmpFile, $folder);
336
        } catch (Exception $e) {
337
            $result = [
338
                'message' => [
339
                    'type' => 'error',
340
                    'value' => $e->getMessage(),
341
                ]
342
            ];
343
            return (new HTTPResponse(json_encode($result), 400))
344
                ->addHeader('Content-Type', 'application/json');
345
        }
346
347
        if ($upload->isError()) {
348
            $result['message'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
349
                'type' => 'error',
350
                'value' => implode(' ' . PHP_EOL, $upload->getErrors()),
351
            ];
352
            return (new HTTPResponse(json_encode($result), 400))
353
                ->addHeader('Content-Type', 'application/json');
354
        }
355
356
        $tuple['Name'] = basename($tuple['Filename']);
357
        return (new HTTPResponse(json_encode($tuple)))
358
            ->addHeader('Content-Type', 'application/json');
359
    }
360
361
    /**
362
     * Returns a JSON array for history of a given file ID. Returns a list of all the history.
363
     *
364
     * @param HTTPRequest $request
365
     * @return HTTPResponse
366
     */
367
    public function apiHistory(HTTPRequest $request)
368
    {
369
        // CSRF check not required as the GET request has no side effects.
370
        $fileId = $request->getVar('fileId');
371
372
        if (!$fileId || !is_numeric($fileId)) {
373
            return new HTTPResponse(null, 400);
374
        }
375
376
        $class = File::class;
377
        $file = DataObject::get($class)->byID($fileId);
378
379
        if (!$file) {
380
            return new HTTPResponse(null, 404);
381
        }
382
383
        if (!$file->canView()) {
384
            return new HTTPResponse(null, 403);
385
        }
386
387
        $versions = Versioned::get_all_versions($class, $fileId)
388
            ->limit($this->config()->max_history_entries)
389
            ->sort('Version', 'DESC');
390
391
        $output = array();
392
        $next = array();
393
        $prev = null;
394
395
        // swap the order so we can get the version number to compare against.
396
        // i.e version 3 needs to know version 2 is the previous version
397
        $copy = $versions->map('Version', 'Version')->toArray();
398
        foreach (array_reverse($copy) as $k => $v) {
399
            if ($prev) {
400
                $next[$v] = $prev;
401
            }
402
403
            $prev = $v;
404
        }
405
406
        $_cachedMembers = array();
407
408
        /** @var File $version */
409
        foreach ($versions as $version) {
410
            $author = null;
411
412
            if ($version->AuthorID) {
413
                if (!isset($_cachedMembers[$version->AuthorID])) {
414
                    $_cachedMembers[$version->AuthorID] = DataObject::get(Member::class)
415
                        ->byID($version->AuthorID);
416
                }
417
418
                $author = $_cachedMembers[$version->AuthorID];
419
            }
420
421
            if ($version->canView()) {
422
                if (isset($next[$version->Version])) {
423
                    $summary = $version->humanizedChanges(
424
                        $version->Version,
425
                        $next[$version->Version]
426
                    );
427
428
                    // if no summary returned by humanizedChanges, i.e we cannot work out what changed, just show a
429
                    // generic message
430
                    if (!$summary) {
431
                        $summary = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.SAVEDFILE', "Saved file");
432
                    }
433
                } else {
434
                    $summary = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.UPLOADEDFILE', "Uploaded file");
435
                }
436
437
                $output[] = array(
438
                    'versionid' => $version->Version,
439
                    'date_ago' => $version->dbObject('LastEdited')->Ago(),
440
                    'date_formatted' => $version->dbObject('LastEdited')->Nice(),
441
                    'status' => ($version->WasPublished) ? _t('File.PUBLISHED', 'Published') : '',
442
                    'author' => ($author)
443
                        ? $author->Name
444
                        : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.UNKNOWN', "Unknown"),
445
                    'summary' => ($summary)
446
                        ? $summary
447
                        : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.NOSUMMARY', "No summary available")
448
                );
449
            }
450
        }
451
452
        return
453
            (new HTTPResponse(json_encode($output)))->addHeader('Content-Type', 'application/json');
454
    }
455
456
    /**
457
     * Redirects 3.x style detail links to new 4.x style routing.
458
     *
459
     * @param HTTPRequest $request
460
     */
461
    public function legacyRedirectForEditView($request)
462
    {
463
        $fileID = $request->param('FileID');
464
        /** @var File $file */
465
        $file = File::get()->byID($fileID);
466
        $link = $this->getFileEditLink($file) ?: $this->Link();
467
        $this->redirect($link);
468
    }
469
470
    /**
471
     * Given a file return the CMS link to edit it
472
     *
473
     * @param File $file
474
     * @return string
475
     */
476
    public function getFileEditLink($file)
477
    {
478
        if (!$file || !$file->isInDB()) {
479
            return null;
480
        }
481
482
        return Controller::join_links(
483
            $this->Link('show'),
484
            $file->ParentID,
485
            'edit',
486
            $file->ID
487
        );
488
    }
489
490
    /**
491
     * Get an asset renamer for the given filename.
492
     *
493
     * @param  string             $filename Path name
494
     * @return AssetNameGenerator
495
     */
496
    protected function getNameGenerator($filename)
497
    {
498
        return Injector::inst()
499
            ->createWithArgs('AssetNameGenerator', array($filename));
500
    }
501
502
    /**
503
     * @todo Implement on client
504
     *
505
     * @param bool $unlinked
506
     * @return ArrayList
507
     */
508
    public function breadcrumbs($unlinked = false)
509
    {
510
        return null;
511
    }
512
513
514
    /**
515
     * Don't include class namespace in auto-generated CSS class
516
     */
517
    public function baseCSSClasses()
518
    {
519
        return 'AssetAdmin LeftAndMain';
520
    }
521
522
    public function providePermissions()
523
    {
524
        return array(
525
            "CMS_ACCESS_AssetAdmin" => array(
526
                'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array(
527
                    'title' => static::menu_title()
528
                )),
529
                'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
530
            )
531
        );
532
    }
533
534
    /**
535
     * Build a form scaffolder for this model
536
     *
537
     * NOTE: Volatile api. May be moved to {@see LeftAndMain}
538
     *
539
     * @param File $file
540
     * @return FormFactory
541
     */
542
    public function getFormFactory(File $file)
543
    {
544
        // Get service name based on file class
545
        $name = null;
0 ignored issues
show
Unused Code introduced by
$name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
546
        if ($file instanceof Folder) {
547
            $name = FolderFormFactory::class;
548
        } elseif ($file instanceof Image) {
549
            $name = ImageFormFactory::class;
550
        } else {
551
            $name = FileFormFactory::class;
552
        }
553
        return Injector::inst()->get($name);
554
    }
555
556
    /**
557
     * The form is used to generate a form schema,
558
     * as well as an intermediary object to process data through API endpoints.
559
     * Since it's used directly on API endpoints, it does not have any form actions.
560
     * It handles both {@link File} and {@link Folder} records.
561
     *
562
     * @param int $id
563
     * @return Form
564
     */
565
    public function getFileEditForm($id)
566
    {
567
        return $this->getAbstractFileForm($id, 'fileEditForm');
568
    }
569
570
    /**
571
     * Get file edit form
572
     *
573
     * @return Form
574
     */
575 View Code Duplication
    public function fileEditForm()
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...
576
    {
577
        // Get ID either from posted back value, or url parameter
578
        $request = $this->getRequest();
579
        $id = $request->param('ID') ?: $request->postVar('ID');
580
        return $this->getFileEditForm($id);
581
    }
582
583
    /**
584
     * The form is used to generate a form schema,
585
     * as well as an intermediary object to process data through API endpoints.
586
     * Since it's used directly on API endpoints, it does not have any form actions.
587
     * It handles both {@link File} and {@link Folder} records.
588
     *
589
     * @param int $id
590
     * @return Form
591
     */
592
    public function getFileInsertForm($id)
593
    {
594
        return $this->getAbstractFileForm($id, 'fileInsertForm', [ 'Type' => AssetFormFactory::TYPE_INSERT ]);
595
    }
596
597
    /**
598
     * Get file insert form
599
     *
600
     * @return Form
601
     */
602 View Code Duplication
    public function fileInsertForm()
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...
603
    {
604
        // Get ID either from posted back value, or url parameter
605
        $request = $this->getRequest();
606
        $id = $request->param('ID') ?: $request->postVar('ID');
607
        return $this->getFileInsertForm($id);
608
    }
609
610
    /**
611
     * Abstract method for generating a form for a file
612
     *
613
     * @param int $id Record ID
614
     * @param string $name Form name
615
     * @param array $context Form context
616
     * @return Form
617
     */
618
    protected function getAbstractFileForm($id, $name, $context = [])
619
    {
620
        /** @var File $file */
621
        $file = File::get()->byID($id);
622
623 View Code Duplication
        if (!$file->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
624
            $this->httpError(403, _t(
625
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
626
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
627
                '',
628
                ['ObjectTitle' => $file->i18n_singular_name()]
629
            ));
630
            return null;
631
        }
632
633
        // Pass to form factory
634
        $augmentedContext = array_merge($context, ['Record' => $file]);
635
        $scaffolder = $this->getFormFactory($file);
636
        $form = $scaffolder->getForm($this, $name, $augmentedContext);
637
638
        // Configure form to respond to validation errors with form schema
639
        // if requested via react.
640
        $form->setValidationResponseCallback(function (ValidationResult $error) use ($form, $id, $name) {
641
            $schemaId = Controller::join_links($this->Link('schema'), $name, $id);
642
            return $this->getSchemaResponse($schemaId, $form, $error);
643
        });
644
645
        return $form;
646
    }
647
648
    /**
649
     * Get form for selecting a file
650
     *
651
     * @return Form
652
     */
653
    public function fileSelectForm()
654
    {
655
        // Get ID either from posted back value, or url parameter
656
        $request = $this->getRequest();
657
        $id = $request->param('ID') ?: $request->postVar('ID');
658
        return $this->getFileSelectForm($id);
659
    }
660
661
    /**
662
     * Get form for selecting a file
663
     *
664
     * @param int $id ID of the record being selected
665
     * @return Form
666
     */
667
    public function getFileSelectForm($id)
668
    {
669
        return $this->getAbstractFileForm($id, 'fileSelectForm', [ 'Type' => AssetFormFactory::TYPE_SELECT ]);
670
    }
671
672
    /**
673
     * @param array $context
674
     * @return Form
675
     * @throws InvalidArgumentException
676
     */
677
    public function getFileHistoryForm($context)
678
    {
679
        // Check context
680
        if (!isset($context['RecordID']) || !isset($context['RecordVersion'])) {
681
            throw new InvalidArgumentException("Missing RecordID / RecordVersion for this form");
682
        }
683
        $id = $context['RecordID'];
684
        $versionId = $context['RecordVersion'];
685
        if (!$id || !$versionId) {
686
            return $this->httpError(404);
687
        }
688
689
        /** @var File $file */
690
        $file = Versioned::get_version(File::class, $id, $versionId);
691
        if (!$file) {
692
            return $this->httpError(404);
693
        }
694
695 View Code Duplication
        if (!$file->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
696
            $this->httpError(403, _t(
697
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
698
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
699
                '',
700
                ['ObjectTitle' => $file->i18n_singular_name()]
701
            ));
702
            return null;
703
        }
704
705
        $effectiveContext = array_merge($context, ['Record' => $file]);
706
        /** @var FormFactory $scaffolder */
707
        $scaffolder = Injector::inst()->get(FileHistoryFormFactory::class);
708
        $form = $scaffolder->getForm($this, 'fileHistoryForm', $effectiveContext);
709
710
        // Configure form to respond to validation errors with form schema
711
        // if requested via react.
712 View Code Duplication
        $form->setValidationResponseCallback(function (ValidationResult $errors) use ($form, $id, $versionId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
713
            $schemaId = Controller::join_links($this->Link('schema/fileHistoryForm'), $id, $versionId);
714
            return $this->getSchemaResponse($schemaId, $form, $errors);
715
        });
716
717
        return $form;
718
    }
719
720
    /**
721
     * Gets a JSON schema representing the current edit form.
722
     *
723
     * WARNING: Experimental API.
724
     *
725
     * @param HTTPRequest $request
726
     * @return HTTPResponse
727
     */
728
    public function schema($request)
729
    {
730
        $formName = $request->param('FormName');
731
        if ($formName !== 'fileHistoryForm') {
732
            return parent::schema($request);
733
        }
734
735
        // Get schema for history form
736
        // @todo Eventually all form scaffolding will be based on context rather than record ID
737
        // See https://github.com/silverstripe/silverstripe-framework/issues/6362
738
        $itemID = $request->param('ItemID');
739
        $version = $request->param('OtherItemID');
740
        $form = $this->getFileHistoryForm([
741
            'RecordID' => $itemID,
742
            'RecordVersion' => $version,
743
        ]);
744
745
        // Respond with this schema
746
        $response = $this->getResponse();
747
        $response->addHeader('Content-Type', 'application/json');
748
        $schemaID = $this->getRequest()->getURL();
749
        return $this->getSchemaResponse($schemaID, $form);
750
    }
751
752
    /**
753
     * Get file history form
754
     *
755
     * @return Form
756
     */
757
    public function fileHistoryForm()
758
    {
759
        $request = $this->getRequest();
760
        $id = $request->param('ID') ?: $request->postVar('ID');
761
        $version = $request->param('OtherID') ?: $request->postVar('Version');
762
        $form = $this->getFileHistoryForm([
763
            'RecordID' => $id,
764
            'RecordVersion' => $version,
765
        ]);
766
        return $form;
767
    }
768
769
    /**
770
     * @param array $data
771
     * @param Form $form
772
     * @return HTTPResponse
773
     */
774
    public function save($data, $form)
775
    {
776
        return $this->saveOrPublish($data, $form, false);
777
    }
778
779
    /**
780
     * @param array $data
781
     * @param Form $form
782
     * @return HTTPResponse
783
     */
784
    public function publish($data, $form)
785
    {
786
        return $this->saveOrPublish($data, $form, true);
787
    }
788
789
    /**
790
     * Update thisrecord
791
     *
792
     * @param array $data
793
     * @param Form $form
794
     * @param bool $doPublish
795
     * @return HTTPResponse
796
     */
797
    protected function saveOrPublish($data, $form, $doPublish = false)
798
    {
799 View Code Duplication
        if (!isset($data['ID']) || !is_numeric($data['ID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
800
            return (new HTTPResponse(json_encode(['status' => 'error']), 400))
801
                ->addHeader('Content-Type', 'application/json');
802
        }
803
804
        $id = (int) $data['ID'];
805
        /** @var File $record */
806
        $record = DataObject::get_by_id(File::class, $id);
807
808
        if (!$record) {
809
            return (new HTTPResponse(json_encode(['status' => 'error']), 404))
810
                ->addHeader('Content-Type', 'application/json');
811
        }
812
813
        if (!$record->canEdit() || ($doPublish && !$record->canPublish())) {
814
            return (new HTTPResponse(json_encode(['status' => 'error']), 401))
815
                ->addHeader('Content-Type', 'application/json');
816
        }
817
818
        // check File extension
819
        if (!empty($data['FileFilename'])) {
820
            $extension = File::get_file_extension($data['FileFilename']);
821
            $newClass = File::get_class_for_file_extension($extension);
822
823
            // if the class has changed, cast it to the proper class
824
            if ($record->getClassName() !== $newClass) {
825
                $record = $record->newClassInstance($newClass);
826
827
                // update the allowed category for the new file extension
828
                $category = File::get_app_category($extension);
829
                $record->File->setAllowedCategories($category);
830
            }
831
        }
832
833
        $form->saveInto($record);
834
        $record->write();
835
836
        // Publish this record and owned objects
837
        if ($doPublish) {
838
            $record->publishRecursive();
839
        }
840
841
        // Note: Force return of schema / state in success result
842
        return $this->getRecordUpdatedResponse($record, $form);
0 ignored issues
show
Compatibility introduced by
$record of type object<SilverStripe\ORM\DataObject> is not a sub-type of object<SilverStripe\Assets\File>. It seems like you assume a child class of the class SilverStripe\ORM\DataObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
843
    }
844
845
    public function unpublish($data, $form)
846
    {
847 View Code Duplication
        if (!isset($data['ID']) || !is_numeric($data['ID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
848
            return (new HTTPResponse(json_encode(['status' => 'error']), 400))
849
                ->addHeader('Content-Type', 'application/json');
850
        }
851
852
        $id = (int) $data['ID'];
853
        /** @var File $record */
854
        $record = DataObject::get_by_id(File::class, $id);
855
856
        if (!$record) {
857
            return (new HTTPResponse(json_encode(['status' => 'error']), 404))
858
                ->addHeader('Content-Type', 'application/json');
859
        }
860
861
        if (!$record->canUnpublish()) {
862
            return (new HTTPResponse(json_encode(['status' => 'error']), 401))
863
                ->addHeader('Content-Type', 'application/json');
864
        }
865
866
        $record->doUnpublish();
867
        return $this->getRecordUpdatedResponse($record, $form);
868
    }
869
870
    /**
871
     * @param File $file
872
     *
873
     * @return array
874
     */
875
    public function getObjectFromData(File $file)
876
    {
877
        $object = array(
878
            'id' => $file->ID,
879
            'created' => $file->Created,
880
            'lastUpdated' => $file->LastEdited,
881
            'owner' => null,
882
            'parent' => null,
883
            'title' => $file->Title,
884
            'exists' => $file->exists(), // Broken file check
885
            'type' => $file instanceof Folder ? 'folder' : $file->FileType,
886
            'category' => $file instanceof Folder ? 'folder' : $file->appCategory(),
887
            'name' => $file->Name,
888
            'filename' => $file->Filename,
889
            'extension' => $file->Extension,
0 ignored issues
show
Bug introduced by
The property Extension does not seem to exist. Did you mean allowed_extensions?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
890
            'size' => $file->AbsoluteSize,
891
            'url' => $file->AbsoluteURL,
892
            'published' => $file->isPublished(),
893
            'modified' => $file->isModifiedOnDraft(),
894
            'draft' => $file->isOnDraftOnly(),
895
            'canEdit' => $file->canEdit(),
896
            'canDelete' => $file->canArchive(),
897
        );
898
899
        /** @var Member $owner */
900
        $owner = $file->Owner();
901
902
        if ($owner) {
903
            $object['owner'] = array(
904
                'id' => $owner->ID,
905
                'title' => trim($owner->FirstName . ' ' . $owner->Surname),
906
            );
907
        }
908
909
        /** @var Folder $parent */
910
        $parent = $file->Parent();
911
912
        if ($parent) {
913
            $object['parent'] = array(
914
                'id' => $parent->ID,
915
                'title' => $parent->Title,
916
                'filename' => $parent->Filename,
917
            );
918
        }
919
920
        /** @var File $file */
921
        if ($file->getIsImage()) {
922
            // Small thumbnail
923
            $smallWidth = UploadField::config()->uninherited('thumbnail_width');
924
            $smallHeight = UploadField::config()->uninherited('thumbnail_height');
925
            $smallThumbnail = $file->FitMax($smallWidth, $smallHeight);
926
            if ($smallThumbnail && $smallThumbnail->exists()) {
927
                $object['smallThumbnail'] = $smallThumbnail->getAbsoluteURL();
928
            }
929
930
            // Large thumbnail
931
            $width = $this->config()->get('thumbnail_width');
932
            $height = $this->config()->get('thumbnail_height');
933
            $thumbnail = $file->FitMax($width, $height);
934
            if ($thumbnail && $thumbnail->exists()) {
935
                $object['thumbnail'] = $thumbnail->getAbsoluteURL();
936
            }
937
            $object['width'] = $file->Width;
938
            $object['height'] = $file->Height;
0 ignored issues
show
Bug introduced by
The property Height does not seem to exist. Did you mean asset_preview_height?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
939
        } else {
940
            $object['thumbnail'] = $file->PreviewLink();
941
        }
942
943
        return $object;
944
    }
945
946
    /**
947
     * Action handler for adding pages to a campaign
948
     *
949
     * @param array $data
950
     * @param Form $form
951
     * @return DBHTMLText|HTTPResponse
952
     */
953
    public function addtocampaign($data, $form)
954
    {
955
        $id = $data['ID'];
956
        $record = File::get()->byID($id);
957
958
        $handler = AddToCampaignHandler::create($this, $record, 'addToCampaignForm');
959
        $results = $handler->addToCampaign($record, $data['Campaign']);
0 ignored issues
show
Bug introduced by
It seems like $record defined by \SilverStripe\Assets\File::get()->byID($id) on line 956 can be null; however, SilverStripe\Admin\AddTo...andler::addToCampaign() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
960
        if (!isset($results)) {
961
            return null;
962
        }
963
964
        // Send extra "message" data with schema response
965
        $extraData = ['message' => $results];
966
        $schemaId = Controller::join_links($this->Link('schema/addToCampaignForm'), $id);
967
        return $this->getSchemaResponse($schemaId, $form, null, $extraData);
968
    }
969
970
    /**
971
     * Url handler for add to campaign form
972
     *
973
     * @param HTTPRequest $request
974
     * @return Form
975
     */
976
    public function addToCampaignForm($request)
977
    {
978
        // Get ID either from posted back value, or url parameter
979
        $id = $request->param('ID') ?: $request->postVar('ID');
980
        return $this->getAddToCampaignForm($id);
981
    }
982
983
    /**
984
     * @param int $id
985
     * @return Form
986
     */
987
    public function getAddToCampaignForm($id)
988
    {
989
        // Get record-specific fields
990
        $record = File::get()->byID($id);
991
992
        if (!$record) {
993
            $this->httpError(404, _t(
994
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorNotFound',
995
                'That {Type} couldn\'t be found',
996
                '',
997
                ['Type' => File::singleton()->i18n_singular_name()]
998
            ));
999
            return null;
1000
        }
1001 View Code Duplication
        if (!$record->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1002
            $this->httpError(403, _t(
1003
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
1004
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
1005
                '',
1006
                ['ObjectTitle' => $record->i18n_singular_name()]
1007
            ));
1008
            return null;
1009
        }
1010
1011
        $handler = AddToCampaignHandler::create($this, $record, 'addToCampaignForm');
1012
        $form = $handler->Form($record);
1013
1014 View Code Duplication
        $form->setValidationResponseCallback(function (ValidationResult $errors) use ($form, $id) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1015
            $schemaId = Controller::join_links($this->Link('schema/addToCampaignForm'), $id);
1016
            return $this->getSchemaResponse($schemaId, $form, $errors);
1017
        });
1018
1019
        return $form;
1020
    }
1021
1022
    /**
1023
     * @return Upload
1024
     */
1025
    protected function getUpload()
1026
    {
1027
        $upload = Upload::create();
1028
        $upload->getValidator()->setAllowedExtensions(
1029
            // filter out '' since this would be a regex problem on JS end
1030
            array_filter(File::config()->uninherited('allowed_extensions'))
1031
        );
1032
1033
        return $upload;
1034
    }
1035
1036
    /**
1037
     * Get response for successfully updated record
1038
     *
1039
     * @param File $record
1040
     * @param Form $form
1041
     * @return HTTPResponse
1042
     */
1043
    protected function getRecordUpdatedResponse($record, $form)
1044
    {
1045
        // Return the record data in the same response as the schema to save a postback
1046
        $schemaData = ['record' => $this->getObjectFromData($record)];
1047
        $schemaId = Controller::join_links($this->Link('schema/fileEditForm'), $record->ID);
1048
        return $this->getSchemaResponse($schemaId, $form, null, $schemaData);
1049
    }
1050
1051
    /**
1052
     * Scaffold a search form.
1053
     * Note: This form does not submit to itself, but rather uses the apiReadFolder endpoint
1054
     * (to be replaced with graphql)
1055
     *
1056
     * @return Form
1057
     */
1058
    public function fileSearchForm()
1059
    {
1060
        $scaffolder = FileSearchFormFactory::singleton();
1061
        return $scaffolder->getForm($this, 'fileSearchForm', []);
1062
    }
1063
1064
    /**
1065
     * Allow search form to be accessible to schema
1066
     *
1067
     * @return Form
1068
     */
1069
    public function getFileSearchform()
1070
    {
1071
        return $this->fileSearchForm();
1072
    }
1073
    
1074
    /**
1075
     * Form for creating a new OEmbed object in the WYSIWYG, used by the InsertEmbedModal component
1076
     *
1077
     * @param null $id
1078
     * @return mixed
1079
     */
1080
    public function getRemoteCreateForm($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id 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...
1081
    {
1082
        return Injector::inst()->get(RemoteFileFormFactory::class)
1083
            ->getForm($this, 'remoteCreateForm', ['type' => 'create']);
1084
    }
1085
    
1086
    /**
1087
     * Allow form to be accessible for schema
1088
     *
1089
     * @return mixed
1090
     */
1091
    public function remoteCreateForm()
1092
    {
1093
        return $this->getRemoteCreateForm();
1094
    }
1095
    
1096
    /**
1097
     * Form for editing a OEmbed object in the WYSIWYG, used by the InsertEmbedModal component
1098
     *
1099
     * @return mixed
1100
     */
1101
    public function getRemoteEditForm()
1102
    {
1103
        $url = $this->request->requestVar('embedurl');
1104
        $form = null;
0 ignored issues
show
Unused Code introduced by
$form is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1105
        $form = Injector::inst()->get(RemoteFileFormFactory::class)
1106
            ->getForm($this, 'remoteEditForm', ['type' => 'edit', 'url' => $url]);
1107
        return $form;
1108
    }
1109
    
1110
    /**
1111
     * Allow form to be accessible for schema
1112
     *
1113
     * @return mixed
1114
     */
1115
    public function remoteEditForm()
1116
    {
1117
        return $this->getRemoteEditForm();
1118
    }
1119
    
1120
    /**
1121
     * Capture the schema handling process, as there is validation done to the URL provided before form is generated
1122
     *
1123
     * @param $request
1124
     * @return HTTPResponse
1125
     */
1126
    public function schemaWithValidate(HTTPRequest $request)
1127
    {
1128
        $formName = $request->param('FormName');
1129
        $itemID = $request->param('ItemID');
1130
    
1131
        if (!$formName) {
1132
            return (new HTTPResponse('Missing request params', 400));
1133
        }
1134
    
1135
        $formMethod = "get{$formName}";
1136
        if (!$this->hasMethod($formMethod)) {
1137
            var_dump($formMethod);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($formMethod); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
1138
            return (new HTTPResponse('Form not found', 404));
1139
        }
1140
    
1141
        if (!$this->hasAction($formName)) {
1142
            return (new HTTPResponse('Form not accessible', 401));
1143
        }
1144
    
1145
        $schemaID = $request->getURL();
1146
        try {
1147
            if ($itemID) {
1148
                $form = $this->{$formMethod}($itemID);
1149
            } else {
1150
                $form = $this->{$formMethod}();
1151
            }
1152
            return $this->getSchemaResponse($schemaID, $form);
1153
        } catch (InvalidUrlException $exception) {
1154
            $errors = ValidationResult::create()
1155
                ->addError($exception->getMessage());
1156
            $form = Form::create(null, 'Form', FieldList::create(), FieldList::create());
1157
            $code = $exception->getCode();
1158
            
1159
            if ($code < 300) {
1160
                $code = 500;
1161
            }
1162
            
1163
            return $this->getSchemaResponse($schemaID, $form, $errors)
1164
                ->setStatusCode($code);
1165
        }
1166
    }
1167
}
1168