GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#32)
by Tomasz
04:40
created

Processor::dispatchEvent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 9.4285
cc 3
eloc 7
nc 3
nop 2
crap 3
1
<?php
2
namespace Thunder\Shortcode\Processor;
3
4
use Thunder\Shortcode\Event\ReplaceShortcodesEvent;
5
use Thunder\Shortcode\Event\FilterShortcodesEvent;
6
use Thunder\Shortcode\EventContainer\EventContainerInterface;
7
use Thunder\Shortcode\Events;
8
use Thunder\Shortcode\HandlerContainer\HandlerContainerInterface as Handlers;
9
use Thunder\Shortcode\Parser\ParserInterface;
10
use Thunder\Shortcode\Shortcode\ReplacedShortcode;
11
use Thunder\Shortcode\Shortcode\ParsedShortcodeInterface;
12
use Thunder\Shortcode\Shortcode\ProcessedShortcode;
13
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
14
15
/**
16
 * @author Tomasz Kowalczyk <[email protected]>
17
 */
18
final class Processor implements ProcessorInterface
19
{
20
    /** @var Handlers */
21
    private $handlers;
22
    /** @var ParserInterface */
23
    private $parser;
24
    /** @var EventContainerInterface */
25
    private $eventContainer;
26
27
    private $recursionDepth = null; // infinite recursion
28
    private $maxIterations = 1; // one iteration
29
    private $autoProcessContent = true; // automatically process shortcode content
30
31 40
    public function __construct(ParserInterface $parser, Handlers $handlers)
32
    {
33 40
        $this->parser = $parser;
34 40
        $this->handlers = $handlers;
35 40
    }
36
37
    /**
38
     * Entry point for shortcode processing. Implements iterative algorithm for
39
     * both limited and unlimited number of iterations.
40
     *
41
     * @param string $text Text to process
42
     *
43
     * @return string
44
     */
45 36
    public function process($text)
46
    {
47 36
        $iterations = $this->maxIterations === null ? 1 : $this->maxIterations;
48 36
        $context = new ProcessorContext();
49 36
        $context->processor = $this;
50
51 36
        while ($iterations--) {
52 36
            $context->iterationNumber++;
53 36
            $newText = $this->processIteration($text, $context, null);
54 36
            if ($newText === $text) {
55 6
                break;
56
            }
57 34
            $text = $newText;
58 34
            $iterations += $this->maxIterations === null ? 1 : 0;
59 34
        }
60
61 36
        return $text;
62
    }
63
64 36
    private function dispatchEvent($name, $event)
65
    {
66 36
        if(null === $this->eventContainer) {
67 32
            return $event;
68
        }
69
70 4
        $handlers = $this->eventContainer->getListeners($name);
71 4
        foreach($handlers as $handler) {
72 4
            call_user_func_array($handler, array($event));
73 4
        }
74
75 4
        return $event;
76
    }
77
78 36
    private function processIteration($text, ProcessorContext $context, ShortcodeInterface $parent = null)
79
    {
80 36
        if (null !== $this->recursionDepth && $context->recursionLevel > $this->recursionDepth) {
81 2
            return $text;
82
        }
83
84 36
        $context->parent = $parent;
85 36
        $context->text = $text;
86 36
        $filterEvent = new FilterShortcodesEvent($this->parser->parse($text), $parent);
0 ignored issues
show
Bug introduced by
It seems like $parent defined by parameter $parent on line 78 can also be of type object<Thunder\Shortcode...ode\ShortcodeInterface>; however, Thunder\Shortcode\Event\...desEvent::__construct() does only seem to accept null|object<Thunder\Shor...ode\ProcessedShortcode>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
87 36
        $this->dispatchEvent(Events::FILTER_SHORTCODES, $filterEvent);
88 36
        $shortcodes = $filterEvent->getShortcodes();
89 36
        $replaces = array();
90 36
        foreach ($shortcodes as $shortcode) {
91 36
            $this->prepareHandlerContext($shortcode, $context);
92 36
            $handler = $this->handlers->get($shortcode->getName());
93 36
            $replace = $this->processHandler($shortcode, $context, $handler);
94
95 36
            $replaces[] = new ReplacedShortcode($shortcode, $replace);
96 36
        }
97 36
        $replaces = array_filter($replaces);
98
99 36
        $applyEvent = new ReplaceShortcodesEvent($text, $replaces, $parent);
100 36
        $this->dispatchEvent(Events::REPLACE_SHORTCODES, $applyEvent);
101
102 36
        return $applyEvent->hasResult() ? $applyEvent->getResult() : $this->applyReplaces($text, $replaces);
103
    }
104
105
    private function applyReplaces($text, array $replaces)
106
    {
107 35 View Code Duplication
        return array_reduce(array_reverse($replaces), function($state, ReplacedShortcode $s) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108 35
            $offset = $s->getOffset();
109 35
            $length = mb_strlen($s->getText());
110
111 35
            return mb_substr($state, 0, $offset).$s->getReplacement().mb_substr($state, $offset + $length);
112 35
        }, $text);
113
    }
114
115 36
    private function prepareHandlerContext(ParsedShortcodeInterface $shortcode, ProcessorContext $context)
116
    {
117 36
        $context->position++;
118 36
        $hasNamePosition = array_key_exists($shortcode->getName(), $context->namePosition);
119 36
        $context->namePosition[$shortcode->getName()] = $hasNamePosition ? $context->namePosition[$shortcode->getName()] + 1 : 1;
120
121 36
        $context->shortcodeText = $shortcode->getText();
122 36
        $context->offset = $shortcode->getOffset();
123 36
        $context->shortcode = $shortcode;
124 36
        $context->textContent = $shortcode->getContent();
125 36
    }
126
127 36
    private function processHandler(ParsedShortcodeInterface $parsed, ProcessorContext $context, $handler)
128
    {
129 36
        $processed = ProcessedShortcode::createFromContext(clone $context);
130 36
        $content = $this->processRecursion($processed, $context);
131 36
        $processed = $processed->withContent($content);
132
133
        return $handler
134 36
            ? call_user_func_array($handler, array($processed))
135 36
            : substr_replace($parsed->getText(), $processed->getContent(), strrpos($parsed->getText(), $parsed->getContent()), mb_strlen($parsed->getContent()));
136
    }
137
138 36
    private function processRecursion(ParsedShortcodeInterface $shortcode, ProcessorContext $context)
139
    {
140 36
        if ($this->autoProcessContent && null !== $shortcode->getContent()) {
141 28
            $context->recursionLevel++;
142
            // this is safe from using max iterations value because it's manipulated in process() method
143 28
            $content = $this->processIteration($shortcode->getContent(), clone $context, $shortcode);
144 28
            $context->recursionLevel--;
145
146 28
            return $content;
147
        }
148
149 21
        return $shortcode->getContent();
150
    }
151
152
    /**
153
     * Container for event handlers used in this processor.
154
     *
155
     * @param EventContainerInterface $eventContainer
156
     *
157
     * @return self
158
     */
159 4
    public function withEventContainer(EventContainerInterface $eventContainer)
160
    {
161 4
        $self = clone $this;
162 4
        $self->eventContainer = $eventContainer;
163
164 4
        return $self;
165
    }
166
167
    /**
168
     * Recursion depth level, null means infinite, any integer greater than or
169
     * equal to zero sets value (number of recursion levels). Zero disables
170
     * recursion. Defaults to null.
171
     *
172
     * @param int|null $depth
173
     *
174
     * @return self
175
     */
176 3 View Code Duplication
    public function withRecursionDepth($depth)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
    {
178 3
        if (null !== $depth && !(is_int($depth) && $depth >= 0)) {
179 1
            $msg = 'Recursion depth must be null (infinite) or integer >= 0!';
180 1
            throw new \InvalidArgumentException($msg);
181
        }
182
183 2
        $self = clone $this;
184 2
        $self->recursionDepth = $depth;
185
186 2
        return $self;
187
    }
188
189
    /**
190
     * Maximum number of iterations, null means infinite, any integer greater
191
     * than zero sets value. Zero is invalid because there must be at least one
192
     * iteration. Defaults to 1. Loop breaks if result of two consequent
193
     * iterations shows no change in processed text.
194
     *
195
     * @param int|null $iterations
196
     *
197
     * @return self
198
     */
199 3 View Code Duplication
    public function withMaxIterations($iterations)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
    {
201 3
        if (null !== $iterations && !(is_int($iterations) && $iterations > 0)) {
202 1
            $msg = 'Maximum number of iterations must be null (infinite) or integer > 0!';
203 1
            throw new \InvalidArgumentException($msg);
204
        }
205
206 2
        $self = clone $this;
207 2
        $self->maxIterations = $iterations;
208
209 2
        return $self;
210
    }
211
212
    /**
213
     * Whether shortcode content will be automatically processed and handler
214
     * already receives shortcode with processed content. If false, every
215
     * shortcode handler needs to process content on its own. Default true.
216
     *
217
     * @param bool $flag True if enabled (default), false otherwise
218
     *
219
     * @return self
220
     */
221 3
    public function withAutoProcessContent($flag)
222
    {
223 3
        if (!is_bool($flag)) {
224 1
            $msg = 'Auto processing flag must be a boolean value!';
225 1
            throw new \InvalidArgumentException($msg);
226
        }
227
228 2
        $self = clone $this;
229 2
        $self->autoProcessContent = (bool)$flag;
230
231 2
        return $self;
232
    }
233
}
234