Completed
Push — feature/EVO-5751-text-index-mo... ( 0ab3ac...8fecb1 )
by
unknown
62:16 queued 57:01
created

FileController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 19
ccs 0
cts 19
cp 0
rs 9.4285
cc 1
eloc 16
nc 1
nop 7
crap 2
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\Bundle\FrameworkBundle\Templating\EngineInterface;
18
19
/**
20
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
21
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
22
 * @link     http://swisscom.ch
23
 */
24
class FileController extends RestController
25
{
26
    /**
27
     * @var FileManager
28
     */
29
    private $fileManager;
30
31
    /**
32
     * @param Response           $response    Response
33
     * @param RestUtilsInterface $restUtils   Rest utils
34
     * @param Router             $router      Router
35
     * @param EngineInterface    $templating  Templating
36
     * @param ContainerInterface $container   Container
37
     * @param SchemaUtils        $schemaUtils schema utils
38
     * @param FileManager        $fileManager Handles file specific tasks
39
     */
40
    public function __construct(
41
        Response $response,
42
        RestUtilsInterface $restUtils,
43
        Router $router,
44
        EngineInterface $templating,
45
        ContainerInterface $container,
46
        SchemaUtils $schemaUtils,
47
        FileManager $fileManager
48
    ) {
49
        parent::__construct(
50
            $response,
51
            $restUtils,
52
            $router,
53
            $templating,
54
            $container,
55
            $schemaUtils
56
        );
57
        $this->fileManager = $fileManager;
58
    }
59
60
    /**
61
     * Writes a new Entry to the database
62
     *
63
     * @param Request $request Current http request
64
     *
65
     * @return Response $response Result of action with data (if successful)
66
     */
67
    public function postAction(Request $request)
68
    {
69
        $response = $this->getResponse();
70
        $fileData = $this->validateFileRequest($request->get('metadata'));
71
        $files = $this->fileManager->saveFiles($request, $this->getModel(), $fileData);
0 ignored issues
show
Bug introduced by
It seems like $fileData defined by $this->validateFileReque...quest->get('metadata')) on line 70 can also be of type object; however, Graviton\FileBundle\FileManager::saveFiles() does only seem to accept null|object<GravitonDyn\FileBundle\Document\File>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
72
73
        // store id of new record so we don't need to re-parse body later when needed
74
        $request->attributes->set('id', $files[0]);
75
76
        // Set status code and content
77
        $response->setStatusCode(Response::HTTP_CREATED);
78
79
        // TODO: this not is correct for multiple uploaded files!!
80
        // TODO: Probably use "Link" header to address this.
81
        $locations = $this->determineRoutes($request->get('_route'), $files, ['post', 'postNoSlash']);
82
        $response->headers->set(
83
            'Location',
84
            $locations[0]
85
        );
86
87
        return $response;
88
    }
89
90
    /**
91
     * respond with document if non json mime-type is requested
92
     *
93
     * @param Request $request Current http request
94
     * @param string  $id      id of file
95
     *
96
     * @return Response
97
     */
98
    public function getAction(Request $request, $id)
99
    {
100
        $accept = $request->headers->get('accept');
101
        if (substr(strtolower($accept), 0, 16) === 'application/json') {
102
            return parent::getAction($request, $id);
103
        }
104
        $response = $this->getResponse();
105
106
        if (!$this->fileManager->has($id)) {
107
            $response->setStatusCode(Response::HTTP_NOT_FOUND);
108
109
            return $response;
110
        }
111
112
        $record = $this->findRecord($id);
113
        $data = $this->fileManager->read($id);
114
115
        $response->setStatusCode(Response::HTTP_OK);
116
        $response->headers->set('Content-Type', $record->getMetadata()->getMime());
117
118
        return $this->render(
119
            'GravitonFileBundle:File:index.raw.twig',
120
            ['data' => $data],
121
            $response
122
        );
123
    }
124
125
    /**
126
     * Update a record
127
     *
128
     * @param Number  $id      ID of record
129
     * @param Request $request Current http request
130
     *
131
     * @return Response $response Result of action with data (if successful)
132
     */
133
    public function putAction($id, Request $request)
134
    {
135
        $contentType = $request->headers->get('Content-Type');
136
        if (substr(strtolower($contentType), 0, 16) === 'application/json') {
137
            return parent::putAction($id, $request);
138
        }
139
        if (0 === strpos($contentType, 'multipart/form-data')) {
140
            $request = $this->normalizeRequest($request);
141
        }
142
143
        $response = $this->getResponse();
144
        $fileData = $this->validateFileRequest($request->get('metadata'));
145
        $files = $this->fileManager->saveFiles($request, $this->getModel(), $fileData);
0 ignored issues
show
Bug introduced by
It seems like $fileData defined by $this->validateFileReque...quest->get('metadata')) on line 144 can also be of type object; however, Graviton\FileBundle\FileManager::saveFiles() does only seem to accept null|object<GravitonDyn\FileBundle\Document\File>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
146
147
        // store id of new record so we don't need to re-parse body later when needed
148
        $request->attributes->set('id', $files[0]);
149
150
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
151
152
        // no service sends Location headers on PUT - /file shouldn't as well
153
154
        return $response;
155
    }
156
157
    /**
158
     * Deletes a record
159
     *
160
     * @param Number $id ID of record
161
     *
162
     * @return Response $response Result of the action
163
     */
164
    public function deleteAction($id)
165
    {
166
        if ($this->fileManager->has($id)) {
167
            $this->fileManager->delete($id);
168
        }
169
170
        return parent::deleteAction($id);
171
    }
172
173
    /**
174
     * Determines the routes and replaces the http method
175
     *
176
     * @param string $routeName  Name of the route to be generated
177
     * @param array  $files      Set of uploaded files
178
     * @param array  $routeTypes Set of route types to be recognized
179
     *
180
     * @return array
181
     */
182
    private function determineRoutes($routeName, array $files, array $routeTypes)
183
    {
184
        $locations = [];
185
        $newRouteName = '';
186
        foreach ($routeTypes as $routeType) {
187
            $routeParts = explode('.', $routeName);
188
189
            if ($routeType == array_pop($routeParts)) {
190
                $reduce = (-1) * strlen($routeType);
191
                $newRouteName = substr($routeName, 0, $reduce).'get';
192
                break;
193
            }
194
        }
195
196
        if (!empty($newRouteName)) {
197
            foreach ($files as $id) {
198
                $locations[] = $this->getRouter()->generate($newRouteName, array('id' => $id));
199
            }
200
        }
201
202
        return $locations;
203
    }
204
205
    /**
206
     * Validates the provided request
207
     *
208
     * @param string $fileData Alternative content to be validated
209
     *
210
     * @throws \Exception
211
     * @return File|null
0 ignored issues
show
Documentation introduced by
Should the return type not be object|array|integer|double|string|boolean|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
212
     */
213
    protected function validateFileRequest($fileData)
214
    {
215
        if (!empty($fileData)) {
216
            return $this->validateRequest($fileData, $this->getModel());
217
        }
218
    }
219
220
    /**
221
     * Gathers information into a request
222
     *
223
     * @param Request $request master request sent by client.
224
     *
225
     * @return Request
226
     */
227
    private function normalizeRequest(Request $request)
228
    {
229
        $contentData = $this->fileManager->extractDataFromRequestContent($request);
230
        $normalized = $request->duplicate(
231
            null,
232
            null,
233
            $contentData['attributes'],
234
            null,
235
            $contentData['files']
236
        );
237
238
        return $normalized;
239
    }
240
}
241