AbstractChannel::checkSupportedNotifications()   A
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 22
rs 9.2222
1
<?php
2
declare(strict_types=1);
3
4
/*
5
 * Copyright (C)
6
 * Nathan Boiron <[email protected]>
7
 * Romain Canon <[email protected]>
8
 *
9
 * This file is part of the TYPO3 NotiZ project.
10
 * It is free software; you can redistribute it and/or modify it
11
 * under the terms of the GNU General Public License, either
12
 * version 3 of the License, or any later version.
13
 *
14
 * For the full copyright and license information, see:
15
 * http://www.gnu.org/licenses/gpl-3.0.html
16
 */
17
18
namespace CuyZ\Notiz\Core\Channel;
19
20
use CuyZ\Notiz\Core\Channel\Settings\ChannelSettings;
21
use CuyZ\Notiz\Core\Definition\Tree\Notification\NotificationDefinition;
22
use CuyZ\Notiz\Core\Exception\InvalidTypeException;
23
use CuyZ\Notiz\Core\Notification\Notification;
24
use CuyZ\Notiz\Service\Container;
25
use CuyZ\Notiz\Service\ObjectService;
26
use TYPO3\CMS\Extbase\Object\ObjectManager;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Object\ObjectManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use TYPO3\CMS\Extbase\Reflection\ReflectionService;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Reflection\ReflectionService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
29
/**
30
 * Default channel implementation provided by this extension, you can use it for
31
 * your own channels.
32
 *
33
 * It does inject all needed data in the class (from the given payload object).
34
 *
35
 * You can override the method `initialize()` to do your own stuff.
36
 *
37
 * You need to implement the method `process()` with the business logic of your
38
 * channel. It will be called whenever an event is fired.
39
 */
40
abstract class AbstractChannel implements Channel
41
{
42
    /**
43
     * Must contain a list of notification classes that can be handled by this
44
     * channel.
45
     *
46
     * An empty array means every notification can be handled.
47
     *
48
     * @var array
49
     */
50
    protected static $supportedNotifications = [];
51
52
    /**
53
     * @var bool
54
     */
55
    private static $supportedNotificationsWereChecked = false;
56
57
    /**
58
     * You can change the type of the settings in your child class.
59
     *
60
     * Please note that the class name must be fully written with its whole
61
     * namespace.
62
     *
63
     * @var \CuyZ\Notiz\Core\Channel\Settings\EmptyChannelSettings
64
     */
65
    protected $settings;
66
67
    /**
68
     * @var Payload
69
     */
70
    protected $payload;
71
72
    /**
73
     * @var ObjectManager
74
     */
75
    protected $objectManager;
76
77
    /**
78
     * WARNING
79
     * -------
80
     *
81
     * If you need to override the constructor, do not forget to call:
82
     * `parent::__construct`
83
     *
84
     * @param ChannelSettings $settings
85
     * @param ObjectManager $objectManager
86
     */
87
    public function __construct(ChannelSettings $settings, ObjectManager $objectManager)
88
    {
89
        $this->settings = $settings;
0 ignored issues
show
Documentation Bug introduced by
$settings is of type CuyZ\Notiz\Core\Channel\Settings\ChannelSettings, but the property $settings was declared to be of type CuyZ\Notiz\Core\Channel\...gs\EmptyChannelSettings. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
90
        $this->objectManager = $objectManager;
91
    }
92
93
    /**
94
     * Proxy method used to fill properties of this class to make them
95
     * accessible easily.
96
     *
97
     * An initialization method is also called to improve the code organization.
98
     *
99
     * @param Payload $payload
100
     *
101
     * @throws InvalidTypeException
102
     */
103
    final public function dispatch(Payload $payload)
104
    {
105
        if (!self::supportsNotification($payload->getNotificationDefinition())) {
106
            throw InvalidTypeException::channelUnsupportedNotificationDispatched($this, $payload->getNotificationDefinition());
107
        }
108
109
        $this->payload = $payload;
110
111
        $this->initialize();
112
        $this->process();
113
    }
114
115
    /**
116
     * You can override in your children classes to implement initialization
117
     * code.
118
     */
119
    protected function initialize()
120
    {
121
        // ...your code...
122
    }
123
124
    /**
125
     * The actual dispatch method that must be implemented by your class.
126
     *
127
     * It will be called when an event is fired and triggers a notification
128
     * dispatch.
129
     */
130
    abstract protected function process();
131
132
    /**
133
     * @param NotificationDefinition $notification
134
     * @return bool
135
     */
136
    public static function supportsNotification(NotificationDefinition $notification): bool
137
    {
138
        self::checkSupportedNotifications();
139
140
        if (empty(static::$supportedNotifications)) {
141
            return true;
142
        }
143
144
        $notificationClassName = $notification->getClassName();
145
146
        foreach (static::$supportedNotifications as $supportedNotification) {
147
            if (ObjectService::classInstanceOf($notificationClassName, $supportedNotification)) {
148
                return true;
149
            }
150
        }
151
152
        return false;
153
    }
154
155
    /**
156
     * Checks that the list of supported notifications is an array containing
157
     * valid values.
158
     *
159
     * @throws InvalidTypeException
160
     */
161
    private static function checkSupportedNotifications()
162
    {
163
        if (self::$supportedNotificationsWereChecked) {
164
            return;
165
        }
166
167
        self::$supportedNotificationsWereChecked = true;
168
169
        if (!is_array(static::$supportedNotifications)) {
0 ignored issues
show
introduced by
The condition is_array(static::supportedNotifications) is always true.
Loading history...
170
            throw InvalidTypeException::channelSupportedNotificationsWrongType(static::class);
171
        }
172
173
        $wrongNotificationClassNames = array_filter(
174
            static::$supportedNotifications,
175
            function ($supportedNotification) {
176
                return !(class_exists($supportedNotification) || interface_exists($supportedNotification))
177
                    || !in_array(Notification::class, class_implements($supportedNotification));
178
            }
179
        );
180
181
        if (!empty($wrongNotificationClassNames)) {
182
            throw InvalidTypeException::channelSupportedNotificationsInvalidListEntries(static::class, $wrongNotificationClassNames);
183
        }
184
    }
185
186
    /**
187
     * You may change the type of the settings property of this class to use a
188
     * custom setting class.
189
     *
190
     * @return string
191
     */
192
    public static function getSettingsClassName(): string
193
    {
194
        /** @var ReflectionService $reflectionService */
195
        $reflectionService = Container::get(ReflectionService::class);
196
197
        $settingsProperty = $reflectionService->getClassSchema(static::class)->getProperty('settings');
198
        $settingsClassName = $settingsProperty['type'];
199
200
        return $settingsClassName;
201
    }
202
}
203