Completed
Push — master ( bd02ec...4ff445 )
by Dmytro
04:14
created

WebhookController::getAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
declare(strict_types=1);
3
4
5
namespace Webhook\Bundle\Controller;
6
7
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
8
use Symfony\Component\HttpFoundation\JsonResponse;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
12
use Symfony\Component\PropertyAccess\PropertyAccessor;
13
use Symfony\Component\Validator\Constraints\All;
14
use Symfony\Component\Validator\Constraints\Choice;
15
use Symfony\Component\Validator\Constraints\Collection;
16
use Symfony\Component\Validator\Constraints\Length;
17
use Symfony\Component\Validator\Constraints\Optional;
18
use Symfony\Component\Validator\Constraints\Range;
19
use Symfony\Component\Validator\Constraints\Required;
20
use Symfony\Component\Validator\Constraints\Url;
21
use Symfony\Component\Validator\Validation;
22
use Webhook\Bundle\Repository\WebhookRepository;
23
use Webhook\Domain\Infrastructure\Strategy\StrategyFactory;
24
use Webhook\Domain\Infrastructure\Strategy\StrategyRegistry;
25
use Webhook\Domain\Model\Webhook;
26
27
28
/**
29
 * Class WebhookController
30
 *
31
 * @package Webhook\Bundle\Controller
32
 */
33
class WebhookController extends Controller
34
{
35
    /**
36
     * @param Request $request
37
     *
38
     * @return Response
39
     */
40
    public function createAction(Request $request): Response
41
    {
42
        $data = json_decode($request->getContent(), true);
43
44
        if (empty($data) || json_last_error() !== JSON_ERROR_NONE) {
45
            return new JsonResponse(['error' => 'Malformed json provided.'], 400);
46
        }
47
48
        if (true !== $response = $this->validate($data)) {
49
            return $response;
50
        }
51
52
        $message = $this->buildMessage($data);
53
54
        $this->get('webhook.repository')->save($message);
55
        $this->get('amqp.producer')->publish($message);
56
57
        return new JsonResponse($message, Response::HTTP_CREATED);
58
    }
59
60
    /**
61
     * @param array $data
62
     *
63
     * @return bool|JsonResponse
64
     */
65
    private function validate(array $data)
66
    {
67
        $validator = Validation::createValidator();
68
        $violations = $validator->validate($data, $this->getConstraints());
69
70
        if (0 !== $violations->count()) {
71
            $errors = [];
72
            foreach ($violations as $violation) {
73
                $field = preg_replace('/\[|\]/', '', $violation->getPropertyPath());
74
                $error = $violation->getMessage();
75
                $errors[$field] = $error;
76
            }
77
78
            return new JsonResponse(['errors' => $errors], 400);
79
        }
80
81
        return true;
82
    }
83
84
    /**
85
     * @return Collection
86
     */
87
    private function getConstraints(): Collection
88
    {
89
        $strategiesMap = StrategyRegistry::getMap();
90
        $strategies = array_keys($strategiesMap);
91
92
        return new Collection([
93
            'fields' => [
94
                'body'            => new Required(),
95
                'url'             => new Url(),
96
                'strategy'        => new Optional(
97
                    new Collection(
98
                        [
99
                            'fields' => [
100
                                'name'    => new Required(new Choice(['choices' => $strategies, 'strict' => true])),
101
                                'options' => new Optional(new All(new Length(['min' => 1]))),
102
                            ]
103
                        ])
104
                ),
105
                'raw'             => new Optional(new Choice(['choices' => [true, false], 'strict' => true])),
106
                'maxAttempts'     => new Optional(new Range(['min' => 1, 'max' => 100])),
107
                'expectedCode'    => new Optional(new Range(['min' => 200, 'max' => 515])),
108
                'expectedContent' => new Optional(new Length(['min' => 1, 'max' => 128])),
109
                'userAgent'       => new Optional(new Length(['min' => 1, 'max' => 128])),
110
                'metadata'        => new Optional(new All(new Length(['min' => 1, 'max' => 128]))),
111
                'callbackUrl'     => new Optional(new Url()),
112
            ]
113
        ]);
114
    }
115
116
    /**
117
     * @param $id
118
     *
119
     * @return JsonResponse
120
     */
121
    public function getAction($id): JsonResponse
122
    {
123
        $message = $this->get('webhook.repository')->get($id);
124
125
        if (null === $message) {
126
            return new JsonResponse(['error' => 'Message not found'], 404);
127
        }
128
129
        return new JsonResponse($message);
130
    }
131
132
    /**
133
     * @return JsonResponse
134
     */
135
    public function getLastAction(): JsonResponse
136
    {
137
        /** @var WebhookRepository $message */
138
        $repo = $this->get('webhook.repository');
139
140
        return new JsonResponse($repo->getLastWebhooks(50));
141
    }
142
143
    /**
144
     * @param $data
145
     *
146
     * @return Webhook
147
     */
148
    private function buildMessage($data): Webhook
149
    {
150
        $body = is_array($data['body']) ? json_encode($data['body']) : $data['body'];
151
        $message = new Webhook($data['url'], $body);
152
153
        unset($data['url'], $data['body']);
154
155
        if (null !== $data['strategy']) {
156
            $name = $data['strategy']['name'];  
157
            $options = $data['strategy']['options'] ?? [];
158
159
            $data['strategy'] = StrategyFactory::create($name, $options);
160
        }
161
162
        $accessor = new PropertyAccessor();
163
        foreach ($data as $k => $v) {
164
            if (null === $v || '' === $v) {
165
                continue;
166
            }
167
168
            if ($accessor->isWritable($message, $k)) {
169
                $accessor->setValue($message, $k, $v);
170
            }
171
        }
172
        return $message;
173
    }
174
}