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