Passed
Push — master ( 852ede...d4265d )
by Greg
06:08
created

EditMediaController   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 447
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 204
c 3
b 0
f 0
dl 0
loc 447
rs 8.8
wmc 45

12 Methods

Rating   Name   Duplication   Size   Complexity  
B addMediaFileAction() 0 40 7
A linkMediaToFamily() 0 12 1
A editMediaFile() 0 32 4
A createMediaObject() 0 9 1
A createMediaObjectFromFileAction() 0 36 5
A __construct() 0 4 1
F editMediaFileAction() 0 86 16
A addMediaFile() 0 22 2
A createMediaObjectAction() 0 57 5
A linkMediaToSource() 0 12 1
A linkMediaToRecordAction() 0 15 1
A linkMediaToIndividual() 0 12 1

How to fix   Complexity   

Complex Class

Complex classes like EditMediaController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EditMediaController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Http\Controllers;
21
22
use Exception;
23
use Fig\Http\Message\StatusCodeInterface;
24
use Fisharebest\Webtrees\Auth;
25
use Fisharebest\Webtrees\FlashMessages;
26
use Fisharebest\Webtrees\GedcomRecord;
27
use Fisharebest\Webtrees\Html;
28
use Fisharebest\Webtrees\I18N;
29
use Fisharebest\Webtrees\Media;
30
use Fisharebest\Webtrees\Services\MediaFileService;
31
use Fisharebest\Webtrees\Services\PendingChangesService;
32
use Fisharebest\Webtrees\Tree;
33
use League\Flysystem\FileExistsException;
34
use League\Flysystem\FileNotFoundException;
35
use League\Flysystem\Util;
36
use Psr\Http\Message\ResponseInterface;
37
use Psr\Http\Message\ServerRequestInterface;
38
39
use function assert;
40
41
/**
42
 * Controller for edit forms and responses.
43
 */
44
class EditMediaController extends AbstractEditController
45
{
46
    /** @var MediaFileService */
47
    private $media_file_service;
48
49
    /** @var PendingChangesService */
50
    private $pending_changes_service;
51
52
    /**
53
     * EditMediaController constructor.
54
     *
55
     * @param MediaFileService      $media_file_service
56
     * @param PendingChangesService $pending_changes_service
57
     */
58
    public function __construct(MediaFileService $media_file_service, PendingChangesService $pending_changes_service)
59
    {
60
        $this->media_file_service      = $media_file_service;
61
        $this->pending_changes_service = $pending_changes_service;
62
    }
63
64
    /**
65
     * Add a media file to an existing media object.
66
     *
67
     * @param ServerRequestInterface $request
68
     *
69
     * @return ResponseInterface
70
     */
71
    public function addMediaFile(ServerRequestInterface $request): ResponseInterface
72
    {
73
        $tree = $request->getAttribute('tree');
74
        assert($tree instanceof Tree);
75
76
        $xref  = $request->getQueryParams()['xref'];
77
        $media = Media::getInstance($xref, $tree);
78
79
        try {
80
            $media = Auth::checkMediaAccess($media);
81
        } catch (Exception $ex) {
82
            return response(view('modals/error', [
83
                'title' => I18N::translate('Add a media file'),
84
                'error' => $ex->getMessage(),
85
            ]));
86
        }
87
88
        return response(view('modals/add-media-file', [
89
            'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
90
            'media'           => $media,
91
            'media_types'     => $this->media_file_service->mediaTypes(),
92
            'unused_files'    => $this->media_file_service->unusedFiles($tree),
93
        ]));
94
    }
95
96
    /**
97
     * Add a media file to an existing media object.
98
     *
99
     * @param ServerRequestInterface $request
100
     *
101
     * @return ResponseInterface
102
     */
103
    public function addMediaFileAction(ServerRequestInterface $request): ResponseInterface
104
    {
105
        $tree = $request->getAttribute('tree');
106
        assert($tree instanceof Tree);
107
108
        $xref  = $request->getQueryParams()['xref'];
109
        $media = Media::getInstance($xref, $tree);
110
        $title = $request->getParsedBody()['title'];
111
        $type  = $request->getParsedBody()['type'];
112
113
        // Tidy whitespace
114
        $type  = trim(preg_replace('/\s+/', ' ', $type));
115
        $title = trim(preg_replace('/\s+/', ' ', $title));
116
117
        if ($media === null || $media->isPendingDeletion() || !$media->canEdit()) {
118
            return redirect(route('tree-page', ['tree' => $tree->name()]));
119
        }
120
121
        $file = $this->media_file_service->uploadFile($request);
122
123
        if ($file === '') {
124
            FlashMessages::addMessage(I18N::translate('There was an error uploading your file.'));
125
126
            return redirect($media->url());
127
        }
128
129
        $gedcom = '1 FILE ' . $file;
130
        if ($type !== '') {
131
            $gedcom .= "\n2 FORM\n3 TYPE " . $type;
132
        }
133
        if ($title !== '') {
134
            $gedcom .= "\n2 TITL " . $title;
135
        }
136
137
        $media->createFact($gedcom, true);
138
139
        // Accept the changes, to keep the filesystem in sync with the GEDCOM data.
140
        $this->pending_changes_service->acceptRecord($media);
141
142
        return redirect($media->url());
143
    }
144
145
    /**
146
     * Edit an existing media file.
147
     *
148
     * @param ServerRequestInterface $request
149
     *
150
     * @return ResponseInterface
151
     */
152
    public function editMediaFile(ServerRequestInterface $request): ResponseInterface
153
    {
154
        $tree = $request->getAttribute('tree');
155
        assert($tree instanceof Tree);
156
157
        $params  = $request->getQueryParams();
158
        $xref    = $params['xref'];
159
        $fact_id = $params['fact_id'];
160
        $media   = Media::getInstance($xref, $tree);
161
162
        try {
163
            $media = Auth::checkMediaAccess($media);
164
        } catch (Exception $ex) {
165
            return response(view('modals/error', [
166
                'title' => I18N::translate('Edit a media file'),
167
                'error' => $ex->getMessage(),
168
            ]), StatusCodeInterface::STATUS_FORBIDDEN);
169
        }
170
171
        foreach ($media->mediaFiles() as $media_file) {
172
            if ($media_file->factId() === $fact_id) {
173
                return response(view('modals/edit-media-file', [
174
                    'media_file'      => $media_file,
175
                    'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
176
                    'media'           => $media,
177
                    'media_types'     => $this->media_file_service->mediaTypes(),
178
                    'unused_files'    => $this->media_file_service->unusedFiles($tree),
179
                ]));
180
            }
181
        }
182
183
        return response('', StatusCodeInterface::STATUS_NOT_FOUND);
184
    }
185
186
    /**
187
     * Save an edited media file.
188
     *
189
     * @param ServerRequestInterface $request
190
     *
191
     * @return ResponseInterface
192
     */
193
    public function editMediaFileAction(ServerRequestInterface $request): ResponseInterface
194
    {
195
        $tree = $request->getAttribute('tree');
196
        assert($tree instanceof Tree);
197
198
        $xref     = $request->getQueryParams()['xref'];
199
        $fact_id  = $request->getQueryParams()['fact_id'];
200
        $folder   = $request->getParsedBody()['folder'];
201
        $new_file = $request->getParsedBody()['new_file'];
202
        $remote   = $request->getParsedBody()['remote'];
203
        $title    = $request->getParsedBody()['title'];
204
        $type     = $request->getParsedBody()['type'];
205
        $media    = Media::getInstance($xref, $tree);
206
207
        // Tidy whitespace
208
        $type  = trim(preg_replace('/\s+/', ' ', $type));
209
        $title = trim(preg_replace('/\s+/', ' ', $title));
210
211
        // Media object oes not exist?  Media object is read-only?
212
        if ($media === null || $media->isPendingDeletion() || !$media->canEdit()) {
213
            return redirect(route('tree-page', ['tree' => $tree->name()]));
214
        }
215
216
        // Find the fact we are editing.
217
        $media_file = null;
218
        foreach ($media->mediaFiles() as $tmp) {
219
            if ($tmp->factId() === $fact_id) {
220
                $media_file = $tmp;
221
            }
222
        }
223
224
        // Media file does not exist?
225
        if ($media_file === null) {
0 ignored issues
show
introduced by
The condition $media_file === null is always true.
Loading history...
226
            return redirect(route('tree-page', ['tree' => $tree->name()]));
227
        }
228
229
        // We can edit the file as either a URL or a folder/file
230
        if ($remote !== '') {
231
            $file = $remote;
232
        } else {
233
            $new_file = str_replace('\\', '/', $new_file);
234
            $folder   = str_replace('\\', '/', $folder);
235
            $folder   = trim($folder, '/');
236
237
            if ($folder === '') {
238
                $file = $new_file;
239
            } else {
240
                $file = $folder . '/' . $new_file;
241
            }
242
        }
243
244
        // Invalid filename?  Do not change it.
245
        if ($new_file === '') {
246
            $file = $media_file->filename();
247
        }
248
249
        $filesystem = $media->tree()->mediaFilesystem();
250
        $old        = $media_file->filename();
251
        $new        = $file;
252
253
        // Update the filesystem, if we can.
254
        if ($old !== $new && !$media_file->isExternal()) {
255
            try {
256
                $new = Util::normalizePath($new);
257
                $filesystem->rename($old, $new);
258
                FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($media_file->filename()), Html::filename($file)), 'info');
259
            } catch (FileNotFoundException $ex) {
260
                // The "old" file may not exist.  For example, if the file was renamed on disk,
261
                // and we are now renaming the GEDCOM data to match.
262
            } catch (FileExistsException $ex) {
263
                // Don't overwrite existing file
264
                FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($media_file->filename()), Html::filename($file)), 'info');
265
                $file = $old;
266
            }
267
        }
268
269
        $gedcom = $this->media_file_service->createMediaFileGedcom($file, $type, $title);
270
271
        $media->updateFact($fact_id, $gedcom, true);
272
273
        // Accept the changes, to keep the filesystem in sync with the GEDCOM data.
274
        if ($old !== $new && !$media_file->isExternal()) {
275
            $this->pending_changes_service->acceptRecord($media);
276
        }
277
278
        return redirect($media->url());
279
    }
280
281
    /**
282
     * Show a form to create a new media object.
283
     *
284
     * @param ServerRequestInterface $request
285
     *
286
     * @return ResponseInterface
287
     */
288
    public function createMediaObject(ServerRequestInterface $request): ResponseInterface
289
    {
290
        $tree = $request->getAttribute('tree');
291
        assert($tree instanceof Tree);
292
293
        return response(view('modals/create-media-object', [
294
            'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
295
            'media_types'     => $this->media_file_service->mediaTypes(),
296
            'unused_files'    => $this->media_file_service->unusedFiles($tree),
297
        ]));
298
    }
299
300
    /**
301
     * @param ServerRequestInterface $request
302
     *
303
     * @return ResponseInterface
304
     */
305
    public function createMediaObjectFromFileAction(ServerRequestInterface $request): ResponseInterface
306
    {
307
        $tree = $request->getAttribute('tree');
308
        assert($tree instanceof Tree);
309
310
        $params = $request->getParsedBody();
311
        $file   = $params['file'];
312
        $type   = $params['type'];
313
        $title  = $params['title'];
314
        $note   = $params['note'];
315
316
        if (preg_match('/\.([a-zA-Z0-9]+)$/', $file, $match)) {
317
            $format = ' ' . $match[1];
318
        } else {
319
            $format = '';
320
        }
321
322
        $gedcom = "0 @@ OBJE\n1 FILE " . $file . "\n2 FORM " . $format;
323
324
        if ($type !== '') {
325
            $gedcom .= "\n3 TYPE " . $type;
326
        }
327
328
        if ($title !== '') {
329
            $gedcom .= "\n2 TITL " . $title;
330
        }
331
332
        if ($note !== '') {
333
            $gedcom .= "\n1 NOTE " . preg_replace('/\r?\n/', "\n2 CONT ", $note);
334
        }
335
336
        $media_object = $tree->createRecord($gedcom);
337
        // Accept the new record.  Rejecting it would leave the filesystem out-of-sync with the genealogy
338
        $this->pending_changes_service->acceptRecord($media_object);
339
340
        return redirect($media_object->url());
341
    }
342
343
    /**
344
     * Process a form to create a new media object.
345
     *
346
     * @param ServerRequestInterface $request
347
     *
348
     * @return ResponseInterface
349
     */
350
    public function createMediaObjectAction(ServerRequestInterface $request): ResponseInterface
351
    {
352
        $tree = $request->getAttribute('tree');
353
        assert($tree instanceof Tree);
354
355
        $params              = $request->getParsedBody();
356
        $note                = $params['media-note'];
357
        $title               = $params['title'];
358
        $type                = $params['type'];
359
        $privacy_restriction = $params['privacy-restriction'];
360
        $edit_restriction    = $params['edit-restriction'];
361
362
        // Tidy whitespace
363
        $type  = trim(preg_replace('/\s+/', ' ', $type));
364
        $title = trim(preg_replace('/\s+/', ' ', $title));
365
366
        // Convert line endings to GEDDCOM continuations
367
        $note = str_replace([
368
            "\r\n",
369
            "\r",
370
            "\n",
371
        ], "\n1 CONT ", $note);
372
373
        $file = $this->media_file_service->uploadFile($request);
374
375
        if ($file === '') {
376
            return response(['error_message' => I18N::translate('There was an error uploading your file.')], 406);
377
        }
378
379
        $gedcom = "0 @@ OBJE\n" . $this->media_file_service->createMediaFileGedcom($file, $type, $title);
380
381
        if ($note !== '') {
382
            $gedcom .= "\n1 NOTE " . preg_replace('/\r?\n/', "\n2 CONT ", $note);
383
        }
384
385
        if (in_array($privacy_restriction, $this->media_file_service::PRIVACY_RESTRICTIONS, true)) {
386
            $gedcom .= "\n1 RESN " . $privacy_restriction;
387
        }
388
389
        if (in_array($edit_restriction, $this->media_file_service::EDIT_RESTRICTIONS, true)) {
390
            $gedcom .= "\n1 RESN " . $edit_restriction;
391
        }
392
393
        $record = $tree->createMediaObject($gedcom);
394
395
        // Accept the new record to keep the filesystem synchronized with the genealogy.
396
        $this->pending_changes_service->acceptRecord($record);
397
398
        return response([
399
            'id'   => $record->xref(),
400
            'text' => view('selects/media', [
401
                'media' => $record,
402
            ]),
403
            'html' => view('modals/record-created', [
404
                'title' => I18N::translate('The media object has been created'),
405
                'name'  => $record->fullName(),
406
                'url'   => $record->url(),
407
            ]),
408
        ]);
409
    }
410
411
    /**
412
     * @param ServerRequestInterface $request
413
     *
414
     * @return ResponseInterface
415
     */
416
    public function linkMediaToIndividual(ServerRequestInterface $request): ResponseInterface
417
    {
418
        $tree = $request->getAttribute('tree');
419
        assert($tree instanceof Tree);
420
421
        $xref = $request->getQueryParams()['xref'];
422
423
        $media = Media::getInstance($xref, $tree);
424
425
        return response(view('modals/link-media-to-individual', [
426
            'media' => $media,
427
            'tree'  => $tree,
428
        ]));
429
    }
430
431
    /**
432
     * @param ServerRequestInterface $request
433
     *
434
     * @return ResponseInterface
435
     */
436
    public function linkMediaToFamily(ServerRequestInterface $request): ResponseInterface
437
    {
438
        $tree = $request->getAttribute('tree');
439
        assert($tree instanceof Tree);
440
441
        $xref = $request->getQueryParams()['xref'];
442
443
        $media = Media::getInstance($xref, $tree);
444
445
        return response(view('modals/link-media-to-family', [
446
            'media' => $media,
447
            'tree'  => $tree,
448
        ]));
449
    }
450
451
    /**
452
     * @param ServerRequestInterface $request
453
     *
454
     * @return ResponseInterface
455
     */
456
    public function linkMediaToSource(ServerRequestInterface $request): ResponseInterface
457
    {
458
        $tree = $request->getAttribute('tree');
459
        assert($tree instanceof Tree);
460
461
        $xref = $request->getQueryParams()['xref'];
462
463
        $media = Media::getInstance($xref, $tree);
464
465
        return response(view('modals/link-media-to-source', [
466
            'media' => $media,
467
            'tree'  => $tree,
468
        ]));
469
    }
470
471
    /**
472
     * @param ServerRequestInterface $request
473
     *
474
     * @return ResponseInterface
475
     */
476
    public function linkMediaToRecordAction(ServerRequestInterface $request): ResponseInterface
477
    {
478
        $tree = $request->getAttribute('tree');
479
        assert($tree instanceof Tree);
480
481
        $params = $request->getParsedBody();
482
        $xref   = $params['xref'];
483
        $link   = $params['link'];
484
485
        $media  = Media::getInstance($xref, $tree);
486
        $record = GedcomRecord::getInstance($link, $tree);
487
488
        $record->createFact('1 OBJE @' . $xref . '@', true);
489
490
        return redirect($media->url());
491
    }
492
}
493