Passed
Push — master ( 76cb70...440cff )
by Angel Fernando Quiroz
10:57
created

ControllerTrait::echoBuffer()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 15
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Traits;
8
9
use Chamilo\CoreBundle\Entity\AccessUrl;
10
use Chamilo\CoreBundle\Helpers\GlideHelper;
11
use Chamilo\CoreBundle\Repository\Node\IllustrationRepository;
12
use Chamilo\CoreBundle\Repository\Node\MessageAttachmentRepository;
13
use Chamilo\CoreBundle\Repository\ResourceFactory;
14
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
15
use Chamilo\CoreBundle\Settings\SettingsManager;
16
use Chamilo\CourseBundle\Repository\CAnnouncementAttachmentRepository;
17
use Chamilo\CourseBundle\Repository\CAnnouncementRepository;
18
use Chamilo\CourseBundle\Repository\CAttendanceRepository;
19
use Chamilo\CourseBundle\Repository\CCalendarEventAttachmentRepository;
20
use Chamilo\CourseBundle\Repository\CDocumentRepository;
21
use Chamilo\CourseBundle\Repository\CForumAttachmentRepository;
22
use Chamilo\CourseBundle\Repository\CForumRepository;
23
use Chamilo\CourseBundle\Repository\CLpCategoryRepository;
24
use Chamilo\CourseBundle\Repository\CLpRepository;
25
use Chamilo\CourseBundle\Repository\CQuizQuestionCategoryRepository;
26
use Chamilo\CourseBundle\Repository\CQuizQuestionRepository;
27
use Chamilo\CourseBundle\Repository\CStudentPublicationCommentRepository;
28
use Chamilo\CourseBundle\Repository\CStudentPublicationCorrectionRepository;
29
use Chamilo\CourseBundle\Repository\CStudentPublicationRepository;
30
use Chamilo\CourseBundle\Repository\CToolRepository;
31
use Chamilo\LtiBundle\Repository\ExternalToolRepository;
32
use Psr\Container\ContainerExceptionInterface;
33
use Psr\Container\ContainerInterface;
34
use Psr\Container\NotFoundExceptionInterface;
35
use Sylius\Bundle\SettingsBundle\Form\Factory\SettingsFormFactory;
36
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
37
use Symfony\Component\HttpFoundation\Request;
38
use Symfony\Component\HttpFoundation\Response;
39
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
40
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
41
use Symfony\Contracts\Translation\TranslatorInterface;
42
43
trait ControllerTrait
44
{
45
    /**
46
     * @var ContainerInterface
47
     */
48
    protected $container;
49
50
    public static function getSubscribedServices(): array
51
    {
52
        $services = AbstractController::getSubscribedServices();
53
        $services['translator'] = TranslatorInterface::class;
54
        $services['glide'] = GlideHelper::class;
55
        // $services['chamilo_settings.form_factory.settings'] = SettingsFormFactory::class;
56
57
        $services[] = SettingsManager::class;
58
        $services[] = MessageAttachmentRepository::class;
59
        $services[] = ResourceFactory::class;
60
        $services[] = ResourceNodeRepository::class;
61
        $services[] = SettingsFormFactory::class;
62
63
        /*
64
            The following classes are needed in order to load the resources files when using the /r/ path
65
            For example: http://my.chamilomaster.net/r/agenda/event_attachments/96/download?cid=1&sid=0&gid=0
66
            Then the repository CCalendarEventAttachmentRepository need to be added here,
67
            because it was set in the tools.yml like this:
68
            chamilo_core.tool.agenda:
69
                (...)
70
                event_attachments:
71
                    repository: Chamilo\CourseBundle\Repository\CCalendarEventAttachmentRepository
72
        */
73
        $services[] = CAnnouncementRepository::class;
74
        $services[] = CAnnouncementAttachmentRepository::class;
75
        $services[] = CAttendanceRepository::class;
76
        $services[] = CCalendarEventAttachmentRepository::class;
77
        $services[] = CDocumentRepository::class;
78
        $services[] = CForumRepository::class;
79
        $services[] = CForumAttachmentRepository::class;
80
        $services[] = CLpRepository::class;
81
        $services[] = CLpCategoryRepository::class;
82
        $services[] = CToolRepository::class;
83
        $services[] = CQuizQuestionRepository::class;
84
        $services[] = CQuizQuestionCategoryRepository::class;
85
        $services[] = CStudentPublicationRepository::class;
86
        $services[] = CStudentPublicationCommentRepository::class;
87
        $services[] = CStudentPublicationCorrectionRepository::class;
88
        $services[] = ExternalToolRepository::class;
89
        $services[] = IllustrationRepository::class;
90
91
        return $services;
92
    }
93
94
    public function getRequest(): ?Request
95
    {
96
        return $this->container->get('request_stack')->getCurrentRequest();
97
    }
98
99
    public function abort(string $message = ''): void
100
    {
101
        throw new NotFoundHttpException($message);
102
    }
103
104
    /**
105
     * Translator shortcut.
106
     */
107
    public function trans(string $variable): string
108
    {
109
        /** @var TranslatorInterface $translator */
110
        $translator = $this->container->get('translator');
111
112
        return $translator->trans($variable);
113
    }
114
115
    /**
116
     * @throws ContainerExceptionInterface
117
     * @throws NotFoundExceptionInterface
118
     */
119
    public function getGlide(): GlideHelper
120
    {
121
        return $this->container->get('glide');
122
    }
123
124
    public function getAccessUrl(): ?AccessUrl
125
    {
126
        $urlId = $this->getRequest()->getSession()->get('access_url_id');
127
128
        return $this->container->get('doctrine')->getRepository(AccessUrl::class)->find($urlId);
129
    }
130
131
    protected function getSettingsManager(): SettingsManager
132
    {
133
        return $this->container->get(SettingsManager::class);
134
    }
135
136
    protected function getSettingsFormFactory()
137
    {
138
        return $this->container->get(SettingsFormFactory::class);
139
    }
140
141
    /**
142
     * @return array<int, int>
143
     */
144
    protected function getRange(Request $request, int $fileSize): array
145
    {
146
        $range = $request->headers->get('Range');
147
148
        if ($range) {
149
            [, $range] = explode('=', $range, 2);
150
            [$start, $end] = explode('-', $range);
151
152
            $start = (int) $start;
153
            $end = ('' === $end) ? $fileSize - 1 : (int) $end;
154
155
            $length = $end - $start + 1;
156
        } else {
157
            $start = 0;
158
            $end = $fileSize - 1;
159
            $length = $fileSize;
160
        }
161
162
        return [$start, $end, $length];
163
    }
164
165
    /**
166
     * @param resource $stream
167
     */
168
    protected function echoBuffer($stream, int $start, int $length): void
169
    {
170
        fseek($stream, $start);
171
172
        $bytesSent = 0;
173
174
        while ($bytesSent < $length && !feof($stream)) {
175
            $buffer = fread($stream, min(1024 * 8, $length - $bytesSent));
176
177
            echo $buffer;
178
179
            $bytesSent += \strlen($buffer);
180
        }
181
182
        fclose($stream);
183
    }
184
185
    protected function setHeadersToStreamedResponse(
186
        Response $response,
187
        bool $forceDownload,
188
        string $filename,
189
        string $contentType,
190
        int $length,
191
        int $start,
192
        int $end,
193
        int $fileSize,
194
        int $finalStatus = Response::HTTP_OK
195
    ): void {
196
        $disposition = $response->headers->makeDisposition(
197
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
198
            $filename
199
        );
200
201
        $response->headers->set('Content-Disposition', $disposition);
202
        $response->headers->set('Content-Type', $contentType);
203
        $response->headers->set('Content-Length', (string) $length);
204
        $response->headers->set('Accept-Ranges', 'bytes');
205
        $response->headers->set('Content-Range', "bytes $start-$end/$fileSize");
206
        $response->setStatusCode(
207
            $start > 0 || $end < $fileSize - 1 ? Response::HTTP_PARTIAL_CONTENT : $finalStatus
208
        );
209
    }
210
}
211