Completed
Push — master ( 9abbc7...a687e5 )
by Fabrizio
03:03
created

SenderManager::customSender()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 36
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
c 4
b 2
f 0
dl 0
loc 36
rs 8.439
cc 5
eloc 13
nc 5
nop 2
1
<?php
2
3
namespace Fenos\Notifynder\Senders;
4
5
use BadMethodCallException;
6
use Closure;
7
use Fenos\Notifynder\Contracts\DefaultSender;
8
use Fenos\Notifynder\Contracts\NotifynderSender;
9
use Fenos\Notifynder\Contracts\Sender;
10
use Fenos\Notifynder\Contracts\StoreNotification;
11
use Illuminate\Contracts\Container\Container;
12
use LogicException;
13
14
/**
15
 * Class SenderManager.
16
 */
17
class SenderManager implements NotifynderSender
18
{
19
    /**
20
     * @var SenderFactory
21
     */
22
    protected $senderFactory;
23
24
    /**
25
     * @var StoreNotification
26
     */
27
    protected $storeNotification;
28
29
    /**
30
     * @var array
31
     */
32
    protected $senders = [];
33
34
    /**
35
     * @var Container
36
     */
37
    protected $container;
38
39
    /**
40
     * @param SenderFactory     $senderFactory
41
     * @param StoreNotification $storeNotification
42
     * @param Container       $container
43
     */
44
    public function __construct(SenderFactory $senderFactory,
45
                         StoreNotification $storeNotification,
46
                         Container $container)
47
    {
48
        $this->senderFactory = $senderFactory;
49
        $this->storeNotification = $storeNotification;
50
        $this->container = $container;
51
    }
52
53
    /**
54
     * Send any notifications.
55
     *
56
     * @param  array $info
57
     * @param  null  $category
58
     * @return mixed
59
     */
60
    public function send($info, $category = null)
61
    {
62
        return $this->sendNow($info, $category);
63
    }
64
65
    /**
66
     * Send now whatever data passed.
67
     *
68
     * @param  array $info
69
     * @param        $category
70
     * @return mixed
71
     */
72
    public function sendNow($info, $category = null)
73
    {
74
        $sender = $this->senderFactory->getSender($info, $category);
75
76
        return $sender->send($this->storeNotification);
77
    }
78
79
    /**
80
     * Send one method to get fully working
81
     * older version.
82
     *
83
     * @param $info
84
     * @param $category
85
     * @return SendOne
86
     */
87
    public function sendOne($info, $category = null)
88
    {
89
        return $this->senderFactory->sendSingle($info, $category)
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->senderFact...tification, $category); (Fenos\Notifynder\Models\Notification) is incompatible with the return type declared by the interface Fenos\Notifynder\Contrac...tifynderSender::sendOne of type Fenos\Notifynder\Senders\SendOne.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
90
            ->send($this->storeNotification, $category);
0 ignored issues
show
Unused Code introduced by
The call to SendOne::send() has too many arguments starting with $category.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
91
    }
92
93
    /**
94
     * Send Multiple method to get fully working
95
     * older version.
96
     *
97
     * @param $info
98
     * @return SendMultiple
99
     */
100
    public function sendMultiple($info)
101
    {
102
        return $this->senderFactory->sendMultiple($info)
103
                    ->send($this->storeNotification);
104
    }
105
106
    /**
107
     * Send a group of notifications
108
     * at once.
109
     *
110
     * @param        $groupName
111
     * @param  array $info
112
     * @return mixed
113
     */
114
    public function sendGroup($groupName, $info = [])
115
    {
116
        return $this->senderFactory->sendGroup(
117
            $groupName,
118
            $info
119
        )->send($this->storeNotification);
120
    }
121
122
    /**
123
     * This method allow to Extend
124
     * notifynder with custom sender.
125
     *
126
     * @param           $name
127
     * @param  callable $extendSender
128
     * @return $this
129
     */
130
    public function extend($name, $extendSender)
131
    {
132
        $this->senders[$name] = $extendSender;
133
134
        return $this;
135
    }
136
137
    /**
138
     * Call a custom method.
139
     *
140
     * @param $customMethod
141
     * @param $notification
142
     * @return mixed
143
     */
144
    public function customSender($customMethod, $notification)
145
    {
146
        if (array_key_exists($customMethod, $this->senders)) {
147
148
            // get the extended method
149
            $extendedSender = $this->senders[$customMethod];
150
151
            // If is a closure means that i'll return an instance
152
            // with the
153
            if ($extendedSender instanceof Closure) {
154
155
                // I invoke the closure expecting an Instance of a custom
156
                // Sender
157
                $invoker = call_user_func_array($extendedSender, [$notification, $this->container]);
158
159
                // If the invoker is a custom sender
160
                // then I invoke it passing the sender class
161
                if ($invoker instanceof Sender) {
162
                    return $invoker->send($this);
163
                }
164
165
                // If the dev is attempting to create a custom
166
                // way of storing notifications then
167
                // i'll pass the store notification contract
168
                if ($invoker instanceof DefaultSender) {
169
                    return $invoker->send($this->storeNotification);
170
                }
171
            }
172
173
            $error = 'The extension must be an instance of Closure';
174
            throw new LogicException($error);
175
        }
176
177
        $error = "The method $customMethod does not exists on the class ".get_class($this);
178
        throw new BadMethodCallException($error);
179
    }
180
181
    /**
182
     * When calling a not existing method
183
     * try to resolve with an extended.
184
     *
185
     * @param $name
186
     * @param $arguments
187
     * @return mixed
188
     */
189
    public function __call($name, $arguments)
190
    {
191
        if (isset($arguments[0])) {
192
            return $this->customSender($name, $arguments[0]);
193
        }
194
195
        $error = 'No argument passed to the custom sender,
196
                 please provide notifications array';
197
        throw new BadMethodCallException($error);
198
    }
199
}
200