Completed
Pull Request — master (#26)
by
unknown
07:04
created

Listener::createStream()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 22
rs 9.2
cc 2
eloc 13
nc 2
nop 0
1
<?php
2
3
namespace Mdb\PayPal\Ipn;
4
5
use Http\Client\Exception;
6
use Http\Message\StreamFactory;
7
use Mdb\PayPal\Ipn\Event\IpnInvalidEvent;
8
use Mdb\PayPal\Ipn\Event\IpnVerificationFailureEvent;
9
use Mdb\PayPal\Ipn\Event\IpnVerifiedEvent;
10
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
11
12
class Listener
13
{
14
    const IPN_VERIFIED_EVENT = 'ipn.message.verified';
15
    const IPN_INVALID_EVENT = 'ipn.message.invalid';
16
    const IPN_VERIFICATION_FAILURE_EVENT = 'ipn.message.verification_failure';
17
18
    /**
19
     * @var StreamFactory
20
     */
21
    private $streamFactory;
22
23
    /**
24
     * @var Verifier
25
     */
26
    private $verifier;
27
28
    /**
29
     * @var EventDispatcherInterface
30
     */
31
    private $eventDispatcher;
32
33
    /**
34
     * @param StreamFactory            $streamFactory
35
     * @param Verifier                 $verifier
36
     * @param EventDispatcherInterface $eventDispatcher
37
     */
38
    public function __construct(
39
        StreamFactory  $streamFactory,
40
        Verifier $verifier,
41
        EventDispatcherInterface $eventDispatcher
42
    ) {
43
        $this->streamFactory = $streamFactory;
44
        $this->verifier = $verifier;
45
        $this->eventDispatcher = $eventDispatcher;
46
    }
47
48
    public function listen()
49
    {
50
        $datas = $this->parseQuery($this->createStream()->getContents());
51
52
        try {
53
            $result = $this->verifier->verify($datas);
54
55
            if ($result) {
56
                $eventName = self::IPN_VERIFIED_EVENT;
57
                $event = new IpnVerifiedEvent($datas);
58
            } else {
59
                $eventName = self::IPN_INVALID_EVENT;
60
                $event = new IpnInvalidEvent($datas);
61
            }
62
        } catch (\UnexpectedValueException $e) {
63
            $eventName = self::IPN_VERIFICATION_FAILURE_EVENT;
64
            $event = new IpnVerificationFailureEvent($datas, $e->getMessage());
65
        } catch (Exception $e) {
66
            $eventName = self::IPN_VERIFICATION_FAILURE_EVENT;
67
            $event = new IpnVerificationFailureEvent($datas, $e->getMessage());
68
        }
69
70
        $this->eventDispatcher->dispatch($eventName, $event);
71
    }
72
73
    /**
74
     * @param callable $listener
75
     */
76
    public function onVerified($listener)
77
    {
78
        $this->eventDispatcher->addListener(self::IPN_VERIFIED_EVENT, $listener);
79
    }
80
81
    /**
82
     * @param callable $listener
83
     */
84
    public function onInvalid($listener)
85
    {
86
        $this->eventDispatcher->addListener(self::IPN_INVALID_EVENT, $listener);
87
    }
88
89
    /**
90
     * @param callable $listener
91
     */
92
    public function onVerificationFailure($listener)
93
    {
94
        $this->eventDispatcher->addListener(self::IPN_VERIFICATION_FAILURE_EVENT, $listener);
95
    }
96
97
    /**
98
     * @return \Psr\Http\Message\StreamInterface
99
     */
100
    protected function createStream()
101
    {
102
        $ex = null;
103
        set_error_handler(function () use ($filename, $mode, &$ex) {
0 ignored issues
show
Bug introduced by
The variable $filename does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $mode does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
104
            $ex = new \RuntimeException(sprintf(
105
                'Unable to open %s using mode %s: %s',
106
                $filename,
107
                $mode,
108
                func_get_args()[1]
109
            ));
110
        });
111
112
        $handle = fopen('php://input', 'r');
113
        restore_error_handler();
114
115
        if ($ex) {
116
            /* @var $ex \RuntimeException */
117
            throw $ex;
118
        }
119
120
        return $this->streamFactory->createStream($handle);
121
    }
122
123
    private function parseQuery($str)
124
    {
125
        $result = [];
126
127
        if ($str === '') {
128
            return $result;
129
        }
130
131
        foreach (explode('&', $str) as $kvp) {
132
            $parts = explode('=', $kvp, 2);
133
            $key = urldecode($parts[0]);
134
            $value = isset($parts[1]) ? urldecode($parts[1]) : null;
135
136
            if (!isset($result[$key])) {
137
                $result[$key] = $value;
138
            } else {
139
                if (!is_array($result[$key])) {
140
                    $result[$key] = [$result[$key]];
141
                }
142
                $result[$key][] = $value;
143
            }
144
        }
145
146
        return $result;
147
    }
148
}
149