Completed
Pull Request — master (#3)
by Rumus
03:25
created

ApiManager::getEntityReflectionFromRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Kami\ApiCoreBundle\Manager;
4
5
use Doctrine\Bundle\DoctrineBundle\Registry;
6
use Doctrine\ORM\Query;
7
use Doctrine\ORM\QueryBuilder;
8
use JMS\Serializer\Serializer;
9
use Kami\ApiCoreBundle\ApiCoreEvents;
10
use Kami\ApiCoreBundle\Event\CrudEvent;
11
use Kami\ApiCoreBundle\Form\Factory;
12
use Kami\ApiCoreBundle\Security\AccessManager;
13
use Symfony\Component\EventDispatcher\EventDispatcher;
14
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
19
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
20
21
/**
22
 * Class ApiManager
23
 *
24
 * @package Kami\ApiCoreBundle\Manager
25
 */
26
class ApiManager
27
{
28
    /**
29
     * @var Registry
30
     */
31
    private $doctrine;
32
33
34
    /**
35
     * @var Serializer
36
     */
37
    private $serializer;
38
39
    /**
40
     * @var AccessManager
41
     */
42
    private $accessManager;
43
44
    /**
45
     * @var Factory
46
     */
47
    private $formFactory;
48
49
    /**
50
     * @var EventDispatcherInterface
51
     */
52
    private $eventDispatcher;
53
54
    /**
55
     * @var int
56
     */
57
    private $perPage;
58
59
    /**
60
     * ApiManager constructor.
61
     *
62
     * @param Registry $doctrine
63
     * @param AccessManager $accessManager
64
     * @param Factory $formFactory
65
     * @param Serializer $serializer
66
     * @param EventDispatcherInterface $eventDispatcher
67
     * @param int $perPage
68
     */
69
    public function __construct(
70
        Registry $doctrine,
71
                                AccessManager $accessManager,
72
                                Factory $formFactory,
73
                                Serializer $serializer,
74
                                EventDispatcherInterface $eventDispatcher,
75
                                $perPage
76
    ) {
77
        $this->doctrine = $doctrine;
78
        $this->accessManager = $accessManager;
79
        $this->formFactory = $formFactory;
80
        $this->serializer = $serializer;
81
        $this->eventDispatcher = $eventDispatcher;
82
        $this->perPage = $perPage;
83
    }
84
85
    /**
86
     * @param Request $request
87
     * @return Response
88
     */
89
    public function getIndex(Request $request)
90
    {
91
        $entity = $this->getEntityReflectionFromRequest($request);
92
        $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_INDEX_REQUEST, new CrudEvent($entity));
93
94
        if (!$this->accessManager->canAccessResource($entity)) {
95
            throw new AccessDeniedHttpException();
96
        }
97
98
        $perPage = $request->query->getInt('per_page', $this->perPage);
99
        $currentPage = $request->query->getInt('page', 1);
100
        $data = $this->buildIndexQuery($entity, $perPage, $currentPage)->getResult();
101
102
        $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_INDEX_RESPONSE, new CrudEvent($data));
103
104
        return $this->createResponse($data, $request);
105
    }
106
107
    public function filter(Request $request)
108
    {
109
        $entity = $this->getEntityReflectionFromRequest($request);
110
111
        if(!$this->accessManager->canAccessResource($entity)) {
112
            throw new AccessDeniedHttpException();
113
        }
114
        $builder = $this->doctrine->getRepository($entity->getName())->createQueryBuilder('e');
115
116
        $sort = $request->get('sort');
117
        if ($sort) {
118
            $sort = lcfirst(implode('', array_map(function($key) {
119
                return ucfirst($key);
120
            }, explode('_', $sort))));
121
122
            if (!$entity->hasProperty($sort)) {
123
                throw new BadRequestHttpException(sprintf('There is no such field %s', $sort));
124
            }
125
            $builder->orderBy(
126
                'e.'.$sort,
127
                in_array($request->get('order'), ['asc', 'desc']) ? $request->get('order') : 'desc'
128
            );
129
        }
130
131
        foreach ($entity->getProperties() as $property) {
132
            $name = $property->getName();
133
            if ($value = $request->get($name)) {
134
                $builder->andWhere($builder->expr()->orX(
135
                    $builder->expr()->like('e.'.$name, ':value')
136
                ));
137
                $builder->setParameter('value', '%'.$value.'%');
138
            }
139
        }
140
141
        $countBuilder = clone $builder;
142
143
        return $this->createResponse([
144
            'total' => $countBuilder->select('count(e.id)')->getQuery()->getSingleScalarResult(),
145
            'rows' => $builder
146
                ->setMaxResults($request->get('limit') ? $request->get('limit') : 20)
147
                ->setFirstResult($request->get('offset') ? $request->get('offset') : 0)
148
                ->getQuery()
149
                ->getResult()
150
        ], $request);
151
152
    }
153
154
155
    /**
156
     * @param Request $request
157
     * @return Response
158
     */
159
    public function getSingleResource(Request $request)
160
    {
161
        $entity = $this->getEntityReflectionFromRequest($request);
162
        $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_REQUEST, new CrudEvent($entity));
163
        if (!$this->accessManager->canAccessResource($entity)) {
164
            throw new AccessDeniedHttpException();
165
        }
166
167
        $entity = $this->doctrine->getManager()->getRepository($entity->getName())->find($request->get('id'));
168
169
        if (!$entity) {
170
            throw new NotFoundHttpException();
171
        }
172
173
        $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_RESPONSE, new CrudEvent($entity));
174
        return $this->createResponse($entity, $request);
175
    }
176
177
    /**
178
     * @param Request $request
179
     * @return Response
180
     */
181
    public function createResource(Request $request)
182
    {
183
        $entity = $this->getEntityReflectionFromRequest($request);
184
185
        $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_CREATE, new CrudEvent($entity));
186
        if (!$this->accessManager->canCreateResource($entity)) {
187
            throw new AccessDeniedHttpException();
188
        }
189
190
        $className = $entity->getName();
191
        $persistentObject = new $className;
192
193
        $form = $this->formFactory->getCreateForm($persistentObject);
194
        $form->handleRequest($request);
195
196
        if ($form->isSubmitted() && $form->isValid()) {
197
            $this->doctrine->getManager()->persist($persistentObject);
198
            $this->doctrine->getManager()->flush();
199
200
            $this->eventDispatcher->dispatch(ApiCoreEvents::RESOURCE_CREATED, new CrudEvent($persistentObject));
201
            return $this->createResponse($persistentObject, $request);
202
        }
203
204
        return $this->createResponse($form->getErrors(), $request, 400);
205
    }
206
207
    /**
208
     * @param Request $request
209
     * @return Response
210
     */
211
    public function editResource(Request $request)
212
    {
213
        $entity = $this->getEntityReflectionFromRequest($request);
214
        if (!$this->accessManager->canEditResource($entity)) {
215
            throw new AccessDeniedHttpException();
216
        }
217
218
        $persistentObject = $this->doctrine->getManager()
219
            ->getRepository($entity->getName())
220
            ->find($request->get('id'));
221
222
        if (!$persistentObject) {
223
            throw new NotFoundHttpException();
224
        }
225
226
        $form = $this->formFactory->getEditForm($persistentObject);
227
        $form->handleRequest($request);
228
229
        if ($form->isSubmitted() && $form->isValid()) {
230
            $this->doctrine->getManager()->persist($persistentObject);
231
            $this->doctrine->getManager()->flush();
232
233
            return $this->createResponse($persistentObject, $request);
234
        }
235
236
        return $this->createResponse($form->getErrors(), $request, 400);
237
    }
238
239
    /**
240
     * @param Request $request
241
     * @return Response
242
     */
243
    public function deleteResource(Request $request)
244
    {
245
        $entityName = $request->attributes->get('_entity');
246
        $reflection = new \ReflectionClass($entityName);
247
        if (!$this->accessManager->canDeleteResource($reflection)) {
248
            throw new AccessDeniedHttpException();
249
        }
250
251
        $entity = $this->doctrine->getManager()
252
            ->getRepository($entityName)
253
            ->find($request->get('id'));
254
255
        if (!$entity) {
256
            throw new NotFoundHttpException();
257
        }
258
259
        $this->doctrine->getManager()->remove($entity);
260
        $this->doctrine->getManager()->flush();
261
262
        return $this->createResponse('', $request, 201);
263
    }
264
265
    /**
266
     * @param \ReflectionClass $entity
267
     * @param $perPage
268
     * @param $currentPage
269
     * @return Query
270
     */
271
    private function buildIndexQuery(\ReflectionClass $entity, $perPage, $currentPage)
272
    {
273
        /** @var QueryBuilder $queryBuilder */
274
        $queryBuilder = $this->doctrine->getManager()
275
            ->createQueryBuilder()
276
            ->select('e')
277
            ->from($entity->getName(), 'e')
278
            ->setMaxResults($perPage)
279
            ->setFirstResult($perPage*($currentPage - 1))
280
        ;
281
282
        return $queryBuilder->getQuery();
283
    }
284
285
    /**
286
     * @param mixed $data
287
     * @param Request $request
288
     * @param int $status
289
     *
290
     * @return Response
291
     */
292
    private function createResponse($data, Request $request, $status = 200)
293
    {
294
        $format = $request->attributes->get('_format');
295
296
        return new Response(
297
            $this->serializer->serialize($data, $format),
298
            $status,
299
            ['Content-type' => $this->getContentTypeByFormat($format)]
300
        );
301
    }
302
303
    private function getEntityReflectionFromRequest(Request $request)
304
    {
305
        try {
306
            return new \ReflectionClass($request->attributes->get('_entity'));
307
        } catch (\ReflectionException $e) {
308
            throw new BadRequestHttpException();
309
        }
310
    }
311
312
    /**
313
     * @param string $format
314
     * @return string
315
     */
316
    private function getContentTypeByFormat($format)
317
    {
318
        switch ($format) {
319
            case 'json':
320
                return 'application/json';
321
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
322
            case 'xml':
323
                return 'application/xml';
324
                break;
325
            default:
326
                return 'text/plain';
327
                break;
328
        }
329
    }
330
}
331