Completed
Branch dev (bc6e47)
by Raffael
02:23
created

Subscription::notify()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 19
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Balloon
7
 *
8
 * @author      Raffael Sahli <[email protected]>
9
 * @copyright   Copryright (c) 2012-2017 gyselroth GmbH (https://gyselroth.com)
10
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
11
 */
12
13
namespace Balloon\App\Notification\Hook;
14
15
use Balloon\App\Notification\Exception;
16
use Balloon\App\Notification\Notifier;
17
use Balloon\Filesystem\Node\Collection;
18
use Balloon\Filesystem\Node\File;
19
use Balloon\Hook\AbstractHook;
20
use Balloon\Server;
21
use Balloon\Server\User;
22
use Psr\Log\LoggerInterface;
23
24
class Subscription extends AbstractHook
25
{
26
    /**
27
     * Body.
28
     *
29
     * @var string
30
     */
31
    protected $body = "Hi {user.name} \n\r There have been made changes in your balloon directory.";
32
33
    /**
34
     * Subject.
35
     *
36
     * @var string
37
     */
38
    protected $subject = 'change';
39
40
    /**
41
     * Notification throttle.
42
     *
43
     * @var int
44
     */
45
    protected $notification_throttle = 3600;
46
47
    /**
48
     * Notifier.
49
     *
50
     * @var Notifier
51
     */
52
    protected $notifier;
53
54
    /**
55
     * Server.
56
     *
57
     * @var Server
58
     */
59
    protected $server;
60
61
    /**
62
     * Logger.
63
     *
64
     * @var LoggerInterface
65
     */
66
    protected $logger;
67
68
    /**
69
     * User.
70
     *
71
     * @var User
72
     */
73
    protected $user;
74
75
    /**
76
     * Constructor.
77
     *
78
     * @param Notification $notifier
79
     * @param Server       $server
80
     */
81
    public function __construct(Notifier $notifier, Server $server, LoggerInterface $logger, ?Iterable $config = null)
82
    {
83
        $this->notifier = $notifier;
84
        $this->server = $server;
85
        $this->user = $server->getIdentity();
86
        $this->setOptions($config);
87
        $this->logger = $logger;
88
    }
89
90
    /**
91
     * Set config.
92
     *
93
     * @param iterable $config
94
     *
95
     * @return AbstractHook
96
     */
97
    public function setOptions(?Iterable $config = null): self
98
    {
99
        if (null === $config) {
100
            return $this;
101
        }
102
103
        foreach ($config as $option => $value) {
104
            switch ($option) {
105
                case 'body':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
106
                case 'subject':
107
                    $this->{$option} = (string) $value;
108
109
                break;
110
                default:
111
                    throw new Exception('invalid option '.$option.' given');
112
            }
113
        }
114
115
        return $this;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function postCreateCollection(Collection $parent, Collection $node, bool $clone): void
122
    {
123
        $this->notify($parent);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function postCreateFile(Collection $parent, File $node, bool $clone): void
130
    {
131
        $this->notify($parent);
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function postDeleteCollection(Collection $node, bool $force, ?string $recursion, bool $recursion_first): void
138
    {
139
        $this->notify($node->getParent());
0 ignored issues
show
Bug introduced by
It seems like $node->getParent() can be null; however, notify() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function postRestoreFile(File $node, int $version): void
146
    {
147
        $this->notify($node->getParent());
0 ignored issues
show
Bug introduced by
It seems like $node->getParent() can be null; however, notify() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function postDeleteFile(File $node, bool $force, ?string $recursion, bool $recursion_first): void
154
    {
155
        $this->notify($node->getParent());
0 ignored issues
show
Bug introduced by
It seems like $node->getParent() can be null; however, notify() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function postPutFile(File $node, $content, bool $force, array $attributes): void
162
    {
163
        $this->notify($node->getParent());
0 ignored issues
show
Bug introduced by
It seems like $node->getParent() can be null; however, notify() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
164
    }
165
166
    /**
167
     * Check if we need to notify.
168
     *
169
     * @param Collection $collection
170
     */
171
    protected function notify(Collection $collection): void
172
    {
173
        $subs = $collection->getAppAttribute('Balloon\\App\\Notification', 'subscription');
174
        if (isset($subs[(string) $this->user->getId()])) {
175
            $this->logger->info('user ['.$this->user->getId().'] got a subscription for node ['.$collection->getId().']', [
176
                'category' => get_class($this),
177
            ]);
178
        } else {
179
            $this->logger->info('user ['.$this->user->getId().'] has no subscription for node ['.$collection->getId().']', [
180
                'category' => get_class($this),
181
            ]);
182
183
            return;
184
        }
185
186
        $throttle = $collection->getAppAttribute('Balloon\\App\\Notification', 'notification_throttle');
187
        if (is_array($throttle) && isset($throttle[(string) $collection->getId()])) {
188
            $last = $throttle[(string) $collection->getId()];
0 ignored issues
show
Unused Code introduced by
$last is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
189
        }
190
191
        $body = preg_replace_callback('/(\{(([a-z]\.*)+)\})/', function ($match) use ($collection) {
192
            return $collection->getAttribute($match[2]);
193
        }, $this->body);
194
        $subject = preg_replace_callback('/(\{(([a-z]\.*)+)\})/', function ($match) use ($collection) {
195
            return $collection->getAttribute($match[2]);
196
        }, $this->subject);
197
198
        $this->notifier->notify($this->user, null, $subject, $body);
199
    }
200
}
201