Completed
Pull Request — develop (#337)
by Bastian
06:24
created

FileController::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 22

Duplication

Lines 25
Ratio 100 %

Code Coverage

Tests 13
CRAP Score 1
Metric Value
dl 25
loc 25
ccs 13
cts 13
cp 1
rs 8.8571
cc 1
eloc 22
nc 1
nop 10
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * controller for gaufrette based file store
4
 */
5
6
namespace Graviton\FileBundle\Controller;
7
8
use Graviton\FileBundle\FileManager;
9
use Graviton\RestBundle\Controller\RestController;
10
use Graviton\RestBundle\Service\RestUtilsInterface;
11
use Graviton\SchemaBundle\SchemaUtils;
12
use GravitonDyn\FileBundle\Document\File;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
use Symfony\Component\HttpFoundation\FileBag;
15
use Symfony\Component\HttpFoundation\ParameterBag;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Bundle\FrameworkBundle\Routing\Router;
19
use Symfony\Component\Validator\Validator\ValidatorInterface;
20
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
21
use Symfony\Component\Form\FormFactory;
22
use Graviton\DocumentBundle\Form\Type\DocumentType;
23
24
/**
25
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
26
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
27
 * @link     http://swisscom.ch
28
 */
29
class FileController extends RestController
30
{
31
    /**
32
     * @var FileManager
33
     */
34
    private $fileManager;
35
36
    /**
37
     * @param Response           $response    Response
38
     * @param RestUtilsInterface $restUtils   Rest utils
39
     * @param Router             $router      Router
40
     * @param ValidatorInterface $validator   Validator
41
     * @param EngineInterface    $templating  Templating
42
     * @param FormFactory        $formFactory form factory
43
     * @param DocumentType       $formType    generic form
44
     * @param ContainerInterface $container   Container
45
     * @param SchemaUtils        $schemaUtils schema utils
46
     * @param FileManager        $fileManager Handles file specific tasks
47
     */
48 7 View Code Duplication
    public function __construct(
49
        Response $response,
50
        RestUtilsInterface $restUtils,
51
        Router $router,
52
        ValidatorInterface $validator,
53
        EngineInterface $templating,
54
        FormFactory $formFactory,
55
        DocumentType $formType,
56
        ContainerInterface $container,
57
        SchemaUtils $schemaUtils,
58
        FileManager $fileManager
59
    ) {
60 7
        parent::__construct(
61 7
            $response,
62 7
            $restUtils,
63 7
            $router,
64 7
            $validator,
65 7
            $templating,
66 7
            $formFactory,
67 7
            $formType,
68 7
            $container,
69
            $schemaUtils
70 7
        );
71 7
        $this->fileManager = $fileManager;
72 7
    }
73
74
    /**
75
     * Writes a new Entry to the database
76
     *
77
     * @param Request $request Current http request
78
     *
79
     * @return Response $response Result of action with data (if successful)
80
     */
81 4
    public function postAction(Request $request)
82
    {
83 4
        $response = $this->getResponse();
84 4
        $fileData = $this->validateRequest($request, $response, $request->get('metadata'));
85 4
        $files = $this->fileManager->saveFiles($request, $this->getModel(), $fileData);
86
87
        // store id of new record so we don't need to re-parse body later when needed
88 4
        $request->attributes->set('id', $files[0]);
89
90
        // Set status code and content
91 4
        $response->setStatusCode(Response::HTTP_CREATED);
92
93
        // TODO: this not is correct for multiple uploaded files!!
94
        // TODO: Probably use "Link" header to address this.
95 4
        $locations = $this->determineRoutes($request->get('_route'), $files, ['post', 'postNoSlash']);
96 4
        $response->headers->set(
97 4
            'Location',
98 4
            $locations[0]
99 4
        );
100
101 4
        return $response;
102
    }
103
104
    /**
105
     * respond with document if non json mime-type is requested
106
     *
107
     * @param Request $request Current http request
108
     * @param string  $id      id of file
109
     *
110
     * @return Response
111
     */
112 4
    public function getAction(Request $request, $id)
113
    {
114 4
        $accept = $request->headers->get('accept');
115 4
        if (substr(strtolower($accept), 0, 16) === 'application/json') {
116 4
            return parent::getAction($request, $id);
117
        }
118 1
        $response = $this->getResponse();
119
120 1
        if (!$this->fileManager->has($id)) {
121
            $response->setStatusCode(Response::HTTP_NOT_FOUND);
122
123
            return $response;
124
        }
125
126 1
        $record = $this->findRecord($id);
127 1
        $data = $this->fileManager->read($id);
128
129 1
        $response->setStatusCode(Response::HTTP_OK);
130 1
        $response->headers->set('Content-Type', $record->getMetadata()->getMime());
131
132 1
        return $this->render(
133 1
            'GravitonFileBundle:File:index.raw.twig',
134 1
            ['data' => $data],
135
            $response
136 1
        );
137
    }
138
139
    /**
140
     * Update a record
141
     *
142
     * @param Number  $id      ID of record
143
     * @param Request $request Current http request
144
     *
145
     * @return Response $response Result of action with data (if successful)
146
     */
147 3
    public function putAction($id, Request $request)
148
    {
149 3
        $contentType = $request->headers->get('Content-Type');
150 3
        if (substr(strtolower($contentType), 0, 16) === 'application/json') {
151 1
            return parent::putAction($id, $request);
152
        }
153 3
        if (0 === strpos($contentType, 'multipart/form-data')) {
154
            $request = $this->normalizeRequest($request);
155
        }
156
157 3
        $response = $this->getResponse();
158 3
        $fileData = $this->validateRequest($request, $response, $request->get('metadata'));
159 3
        $files = $this->fileManager->saveFiles($request, $this->getModel(), $fileData);
160
161
        // store id of new record so we don't need to re-parse body later when needed
162 3
        $request->attributes->set('id', $files[0]);
163
164 3
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
165
166
        // no service sends Location headers on PUT - /file shouldn't as well
167
168 3
        return $response;
169
    }
170
171
    /**
172
     * Deletes a record
173
     *
174
     * @param Number $id ID of record
175
     *
176
     * @return Response $response Result of the action
177
     */
178 1
    public function deleteAction($id)
179
    {
180 1
        if ($this->fileManager->has($id)) {
181 1
            $this->fileManager->delete($id);
182 1
        }
183
184 1
        return parent::deleteAction($id);
185
    }
186
187
    /**
188
     * Determines the routes and replaces the http method
189
     *
190
     * @param string $routeName  Name of the route to be generated
191
     * @param array  $files      Set of uploaded files
192
     * @param array  $routeTypes Set of route types to be recognized
193
     *
194
     * @return array
195
     */
196 4
    private function determineRoutes($routeName, array $files, array $routeTypes)
197
    {
198 4
        $locations = [];
199 4
        $newRouteName = '';
200 4
        foreach ($routeTypes as $routeType) {
201 4
            $routeParts = explode('.', $routeName);
202
203 4
            if ($routeType == array_pop($routeParts)) {
204 4
                $reduce = (-1) * strlen($routeType);
205 4
                $newRouteName = substr($routeName, 0, $reduce).'get';
206 4
                break;
207
            }
208 4
        }
209
210 4
        if (!empty($newRouteName)) {
211 4
            foreach ($files as $id) {
212 4
                $locations[] = $this->getRouter()->generate($newRouteName, array('id' => $id));
213 4
            }
214 4
        }
215
216 4
        return $locations;
217
    }
218
219
    /**
220
     * Validates the provided request
221
     *
222
     * @param Request  $request  Http request to be validated
223
     * @param Response $response Http response to be returned in case of an error
224
     * @param string   $fileData Alternative content to be validated
225
     *
226
     * @throws \Exception
227
     * @return File|null
228
     */
229 5
    private function validateRequest(Request $request, Response $response, $fileData = '')
230
    {
231 5
        if (!empty($fileData)) {
232 1
            $this->formValidator->checkJsonRequest($request, $response, $fileData);
233 1
            $model = $this->getModel();
234 1
            return $this->formValidator->checkForm(
235 1
                $this->formValidator->getForm($request, $model),
236 1
                $model,
237 1
                $this->formDataMapper,
238
                $fileData
239 1
            );
240
        }
241 5
    }
242
243
    /**
244
     * Gathers information into a request
245
     *
246
     * @param Request $request master request sent by client.
247
     *
248
     * @return Request
249
     */
250
    private function normalizeRequest(Request $request)
251
    {
252
        $contentData = $this->fileManager->extractDataFromRequestContent($request);
253
        $normalized = $request->duplicate(
254
            null,
255
            null,
256
            $contentData['attributes'],
257
            null,
258
            $contentData['files']
259
        );
260
261
        return $normalized;
262
    }
263
}
264