EventPipe::listen()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 3 Features 0
Metric Value
c 4
b 3
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace PEIP\Pipe;
4
5
/*
6
 * This file is part of the PEIP package.
7
 * (c) 2009-2016 Timo Michna <timomichna/yahoo.de>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
/**
14
 * EventPipe
15
 * Concrete base class for event handling Pipes.
16
 *
17
 * @author Timo Michna <timomichna/yahoo.de>
18
 * @extends \PEIP\ABS\Pipe\EventPipe
19
 * @implements \PEIP\INF\Message\MessageBuilder, \PEIP\INF\Handler\Handler, \PEIP\INF\Channel\Channel, \PEIP\INF\Channel\SubscribableChannel, \PEIP\INF\Event\Connectable, \PEIP\INF\Event\Listener
20
 */
21
class EventPipe extends \PEIP\ABS\Pipe\EventPipe implements \PEIP\INF\Event\Listener
22
{
23
    protected $eventName;
24
25
    public function connectChannel(\PEIP\INF\Channel\Channel $inputChannel)
26
    {
27
        $this->inputChannel = $inputChannel;
28
    }
29
30
    /**
31
     * Sets the input channel for this event-pipe. Contrary to Pipe event-pipes
32
     * listen to a given event on the input-channel and hanle resulting event-objects.
33
     *
34
     * @param \PEIP\INF\Channel\Channel $inputChannel the input-channel to listen for events.
35
     *
36
     * @return
37
     */
38
    public function setInputChannel(\PEIP\INF\Channel\Channel $inputChannel)
39
    {
40
        $this->connectChannel($inputChannel);
41
    }
42
43
    /**
44
     * Does the message replying logic for the event-pipe.
45
     * In context of an event-pipe the message is normally a instance of
46
     * \PEIP\INF\Event\Event representing an event on a channel/pipe. This method
47
     * looks for a header 'MESSAGE' on the event object. If the header is a
48
     * message (instance of \PEIP\INF\Message\Message) replies with the message.
49
     * Implements PEIP\ABS\Handler\ReplyProducingMessageHandler::doReply.
50
     *
51
     * @abstract
52
     *
53
     * @param \PEIP\INF\Message\Message $message the message to reply with
54
     */
55
    protected function doReply(\PEIP\INF\Message\Message $message)
56
    {
57
        $headerMessage = $message->getHeader('MESSAGE');
58
        if ($headerMessage instanceof \PEIP\INF\Message\Message) {
59
            return $this->replyMessage($headerMessage);
60
        }
61
    }
62
63
    /**
64
     * Connects the event-pipe to a \PEIP\INF\Event\Connectable instance by
65
     * listening to the event-type registered with this event-pipe.
66
     *
67
     * @param \PEIP\INF\Event\Connectable $connectable the connectable to listen to
68
     *
69
     * @return
70
     */
71
    public function listen(\PEIP\INF\Event\Connectable $connectable)
72
    {
73
        return $this->doListen($this->eventName, $connectable);
74
    }
75
76
    /**
77
     * Disconnects the event-pipe from a \PEIP\INF\Event\Connectable instance by
78
     * listening to the event-type registered with this event-pipe.
79
     *
80
     * @param \PEIP\INF\Event\Connectable $connectable the connectable to unlisten
81
     *
82
     * @return
83
     */
84
    public function unlisten(\PEIP\INF\Event\Connectable $connectable)
85
    {
86
        return $this->doUnlisten($this->eventName, $connectable);
87
    }
88
89
    /**
90
     * Returns the instances of \PEIP\INF\Event\Connectable the event-pipe is litening to.
91
     *
92
     * @return array array of \PEIP\INF\Event\Connectable instances
93
     */
94
    public function getConnected()
95
    {
96
        return $this->doGetConnected();
97
    }
98
99
    /**
100
     * Disconnects a \PEIP\INF\Channel\Channel instance from the event-pipe.
101
     *
102
     * @param \PEIP\INF\Channel\Channel $channel \PEIP\INF\Channel\Channel instance to disconnect from
103
     *
104
     * @return
105
     */
106
    public function disconnectChannel(\PEIP\INF\Channel\Channel $channel)
107
    {
108
        $this->disconnectInputChannel();
109
        $this->inputChannel = $channel;
110
        $this->connectInputChannel();
111
    }
112
113
    /**
114
     * Connects the registered input-channel to this event-pipe by
115
     * listening to the event-type registered with this event-pipe.
116
     *
117
     * @return
118
     */
119
    protected function connectInputChannel()
120
    {
121
        if ($this->inputChannel && $this->eventName) {
122
            $this->inputChannel->connect($this->eventName, $this);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface PEIP\INF\Channel\Channel as the method connect() does only exist in the following implementations of said interface: DrinkAggregator, DrinkRouter, OrderSplitter, PEIP\ABS\Channel\Channel, PEIP\ABS\Channel\PollableChannel, PEIP\ABS\Channel\SubscribableChannel, PEIP\ABS\Pipe\EventPipe, PEIP\ABS\Router\Router, PEIP\ABS\Service\ServiceActivator, PEIP\ABS\Splitter\MessageSplitter, PEIP\ABS\Transformer\ContentTransformer, PEIP\ABS\Transformer\Transformer, PEIP\Channel\DirectChannel, PEIP\Channel\PollableChannel, PEIP\Channel\PriorityChannel, PEIP\Channel\PublishSubscribeChannel, PEIP\Channel\QueueChannel, PEIP\Listener\Wiretap, PEIP\Pipe\CommandPipe, PEIP\Pipe\EventPipe, PEIP\Pipe\FixedEventPipe, PEIP\Pipe\Pipe, PEIP\Pipe\SimpleEventPipe, PEIP\Service\HeaderServiceActivator, PEIP\Service\ServiceActivator, PEIP\Service\SplittingServiceActivator, PEIP\Service\StringServiceActivator.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
123
        }
124
    }
125
126
    /**
127
     * Disconnects the registered input-channel from this event-pipe by
128
     * unlistening to the event-type registered with this event-pipe.
129
     *
130
     * @return
131
     */
132
    protected function disconnectInputChannel()
133
    {
134
        if ($this->inputChannel && $this->eventName) {
135
            $this->inputChannel->disconnect($this->eventName, $this);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface PEIP\INF\Channel\Channel as the method disconnect() does only exist in the following implementations of said interface: DrinkAggregator, DrinkRouter, OrderSplitter, PEIP\ABS\Channel\Channel, PEIP\ABS\Channel\PollableChannel, PEIP\ABS\Channel\SubscribableChannel, PEIP\ABS\Pipe\EventPipe, PEIP\ABS\Router\Router, PEIP\ABS\Service\ServiceActivator, PEIP\ABS\Splitter\MessageSplitter, PEIP\ABS\Transformer\ContentTransformer, PEIP\ABS\Transformer\Transformer, PEIP\Channel\DirectChannel, PEIP\Channel\PollableChannel, PEIP\Channel\PriorityChannel, PEIP\Channel\PublishSubscribeChannel, PEIP\Channel\QueueChannel, PEIP\Listener\Wiretap, PEIP\Pipe\CommandPipe, PEIP\Pipe\EventPipe, PEIP\Pipe\FixedEventPipe, PEIP\Pipe\Pipe, PEIP\Pipe\SimpleEventPipe, PEIP\Service\HeaderServiceActivator, PEIP\Service\ServiceActivator, PEIP\Service\SplittingServiceActivator, PEIP\Service\StringServiceActivator.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
136
        }
137
    }
138
139
    /**
140
     * Registers the event-name this event-pipe should listen to.
141
     *
142
     * @param $eventName
143
     *
144
     * @return
145
     */
146
    public function setEventName($eventName)
147
    {
148
        $this->disconnectInputChannel();
149
        $this->eventName = $eventName;
150
        $this->connectInputChannel();
151
    }
152
}
153