Passed
Push — master ( e9e739...1e7f19 )
by Yannick
09:01
created

uniqueFilenameForAttachments()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 2
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller\Api;
8
9
use Chamilo\CoreBundle\Entity\ResourceFile;
10
use Chamilo\CoreBundle\Helpers\UserHelper;
11
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
12
use Chamilo\CourseBundle\Entity\CBlog;
13
use Chamilo\CourseBundle\Entity\CBlogAttachment;
14
use Chamilo\CourseBundle\Entity\CBlogPost;
15
use Chamilo\CourseBundle\Repository\CBlogAttachmentRepository;
16
use Doctrine\ORM\EntityManagerInterface;
17
use Symfony\Component\HttpFoundation\File\UploadedFile;
18
use Symfony\Component\HttpFoundation\JsonResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpKernel\Attribute\AsController;
21
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
22
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
23
24
#[AsController]
25
final class CreateBlogAttachmentAction
26
{
27
    public function __invoke(
28
        Request $request,
29
        EntityManagerInterface $em,
30
        UserHelper $userHelper,
31
        CBlogAttachmentRepository $attachRepo,
32
        ResourceNodeRepository $resourceNodeRepo
33
34
    ): JsonResponse {
35
        $user = $userHelper->getCurrent();
36
        if (!$user) {
37
            throw new UnauthorizedHttpException('', 'Unauthorized.');
38
        }
39
40
        /** @var UploadedFile|null $file */
41
        $file = $request->files->get('uploadFile');
42
        if (!$file) {
43
            foreach ($request->files as $val) {
44
                if ($val instanceof UploadedFile) { $file = $val; break; }
45
            }
46
        }
47
        if (!$file) {
48
            throw new BadRequestHttpException('"uploadFile" is required');
49
        }
50
51
        // IRIs
52
        $blogIri = (string) $request->request->get('blog', '');
53
        $postIri = (string) $request->request->get('post', '');
54
        if ($blogIri === '' || $postIri === '') {
55
            throw new BadRequestHttpException('Both "blog" and "post" are required IRIs.');
56
        }
57
58
        /** @var CBlog|null $blog */
59
        $blog = $em->getRepository(CBlog::class)->find(self::idFromIri($blogIri));
60
        /** @var CBlogPost|null $post */
61
        $post = $em->getRepository(CBlogPost::class)->find(self::idFromIri($postIri));
62
        if (!$blog || !$post) {
63
            throw new BadRequestHttpException('Invalid blog/post IRI.');
64
        }
65
66
        $node = $blog->getResourceNode();
67
        if (!$node) {
68
            throw new BadRequestHttpException('Blog has no resource node.');
69
        }
70
71
        $original  = $file->getClientOriginalName() ?: 'upload.bin';
72
        $filename  = $this->uniqueFilenameForAttachments($original, $attachRepo);
73
74
        $rf = new ResourceFile();
75
        $rf->setResourceNode($node);
76
        $rf->setTitle($filename);
77
        $rf->setFile($file);
78
79
        $em->persist($rf);
80
        $em->flush();
81
82
        $downloadUrl = $resourceNodeRepo->getResourceFileUrl($node);
83
84
        $att = new CBlogAttachment();
85
        $att->setBlog($blog);
86
        $att->setPost($post);
87
        $att->setFilename($filename);
88
        $att->setSize((int) ($rf->getSize() ?? 0));
89
        $att->setPath($downloadUrl);
90
        $att->setComment($request->request->get('comment') ?: null);
91
92
        $em->persist($att);
93
        $em->flush();
94
95
        return new JsonResponse([
96
            'ok'             => true,
97
            'id'             => (int) $att->getIid(),
98
            'filename'       => $att->getFilename(),
99
            'size'           => $att->getSize(),
100
            'path'           => $downloadUrl,
101
            'resourceFileId' => (int) $rf->getId(),
102
        ], 201);
103
    }
104
105
    private static function idFromIri(string $iri): ?int
106
    {
107
        return preg_match('~(\d+)$~', $iri, $m) ? (int) $m[1] : null;
108
    }
109
110
    private function uniqueFilenameForAttachments(string $original, CBlogAttachmentRepository $repo): string
111
    {
112
        $candidate = $original;
113
        $i = 1;
114
        while ($repo->findOneBy(['filename' => $candidate])) {
115
            $pi   = pathinfo($original);
116
            $name = $pi['filename'] ?? 'file';
117
            $ext  = isset($pi['extension']) ? '.'.$pi['extension'] : '';
118
            $candidate = $name.'_'.$i.$ext;
119
            $i++;
120
        }
121
        return $candidate;
122
    }
123
}
124