Completed
Pull Request — master (#13)
by Rafael
06:46
created

Subscriber::__invoke()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 26
ccs 0
cts 20
cp 0
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Subscription;
12
13
use Symfony\Bundle\FrameworkBundle\Routing\Router;
14
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15
use Symfony\Component\HttpFoundation\RequestStack;
16
use Symfony\Component\Security\Core\AuthenticationEvents;
17
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
18
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
19
use Ynlo\GraphQLBundle\Events\GraphQLEvents;
20
use Ynlo\GraphQLBundle\Events\GraphQLOperationEvent;
21
use Ynlo\GraphQLBundle\Resolver\ResolverContext;
22
use Ynlo\GraphQLBundle\Util\Uuid;
23
24
/**
25
 * The subscriber is a resolver that resolve subscriptions and return a subscription link
26
 * act as a middleware before the real subscription resolver is executed
27
 */
28
class Subscriber implements EventSubscriberInterface
29
{
30
    public const DEFAULT_SUBSCRIPTION_TTL = 300;
31
32
    /**
33
     * @var SubscriptionManager
34
     */
35
    protected $subscriptionManager;
36
37
    /**
38
     * @var Router
39
     */
40
    protected $router;
41
42
    /**
43
     * @var RequestStack
44
     */
45
    protected $requestStack;
46
47
    /**
48
     * @var string
49
     */
50
    protected $username;
51
52
    /**
53
     * @var Endpoint
54
     */
55
    protected $endpoint;
56
57
    /**
58
     * @var int
59
     */
60
    protected $subscriptionsTtl = self::DEFAULT_SUBSCRIPTION_TTL;
61
62
    /**
63
     * Subscriber constructor.
64
     *
65
     * @param RequestStack        $requestStack
66
     * @param Router              $router
67
     * @param SubscriptionManager $subscriptionManager
68
     */
69
    public function __construct(RequestStack $requestStack, Router $router, ?SubscriptionManager $subscriptionManager = null)
70
    {
71
        $this->requestStack = $requestStack;
72
        $this->router = $router;
73
        $this->subscriptionManager = $subscriptionManager;
74
    }
75
76
    /**
77
     * @param int $subscriptionsTtl
78
     */
79
    public function setSubscriptionsTtl(int $subscriptionsTtl): void
80
    {
81
        $this->subscriptionsTtl = $subscriptionsTtl;
82
    }
83
84
    /**
85
     * @inheritDoc
86
     */
87
    public static function getSubscribedEvents(): array
88
    {
89
        return [
90
            GraphQLEvents::OPERATION_START => 'operationStart',
91
            AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onSymfonyAuthSuccess',
92
        ];
93
    }
94
95
    /**
96
     * @param AuthenticationEvent $event
97
     */
98
    public function onSymfonyAuthSuccess(AuthenticationEvent $event): void
99
    {
100
        $this->username = $event->getAuthenticationToken()->getUsername();
101
    }
102
103
    /**
104
     * @param GraphQLOperationEvent $event
105
     */
106
    public function operationStart(GraphQLOperationEvent $event): void
107
    {
108
        $this->endpoint = $event->getEndpoint();
109
    }
110
111
    /**
112
     * @param ResolverContext $context
113
     * @param array           $args
114
     *
115
     * @return SubscriptionLink
116
     *
117
     * @throws \Exception
118
     */
119
    public function __invoke(ResolverContext $context, $args = [])
120
    {
121
        $request = $this->requestStack->getCurrentRequest();
122
        if (!$request) {
123
            throw new \RuntimeException('Missing required request');
124
        }
125
126
        // subscriptions are created with a very lowest expiration date
127
        // the user must use the subscription otherwise will me marked as expired
128
        $expireAt = new \DateTime('+20seconds');
129
130
        $id = Uuid::createFromData(
131
            [
132
                $this->username,
133
                $this->endpoint,
134
                $request->getUri(),
135
                $request->getContent(),
136
            ]
137
        );
138
139
        $subscriptionName = $this->endpoint->getSubscriptionNameForResolver($context->getDefinition()->getResolver());
140
        $this->subscriptionManager->subscribe($id, $subscriptionName, $args, $request, $expireAt);
141
        $url = $this->router->generate('api_subscriptions', ['subscription' => $id], Router::ABSOLUTE_URL);
142
        $heartbeatUrl = $this->router->generate('api_subscriptions_heartbeat', ['subscription' => $id], Router::ABSOLUTE_URL);
143
144
        return new SubscriptionLink($url, $heartbeatUrl, $this->subscriptionsTtl);
145
    }
146
}
147