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
02:13
created

Processor::applyReplaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 3
Ratio 50 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 3
loc 6
rs 9.4285
ccs 3
cts 3
cp 1
cc 1
eloc 4
nc 1
nop 2
crap 1
1
<?php
2
namespace Thunder\Shortcode\Processor;
3
4
use Thunder\Shortcode\Event\ApplyResultsEvent;
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\ParsedShortcodeInterface;
11
use Thunder\Shortcode\Shortcode\ProcessedShortcode;
12
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
13
14
/**
15
 * @author Tomasz Kowalczyk <[email protected]>
16
 */
17
final class Processor implements ProcessorInterface
18
{
19
    /** @var Handlers */
20
    private $handlers;
21 36
    /** @var ParserInterface */
22
    private $parser;
23 36
    /** @var EventContainerInterface */
24 36
    private $eventContainer;
25 36
26
    private $recursionDepth = null; // infinite recursion
27
    private $maxIterations = 1; // one iteration
28
    private $autoProcessContent = true; // automatically process shortcode content
29
30
    public function __construct(ParserInterface $parser, Handlers $handlers)
31
    {
32
        $this->parser = $parser;
33
        $this->handlers = $handlers;
34
    }
35 32
36
    /**
37 32
     * Entry point for shortcode processing. Implements iterative algorithm for
38 32
     * both limited and unlimited number of iterations.
39 32
     *
40
     * @param string $text Text to process
41 32
     *
42 32
     * @return string
43 32
     */
44 32
    public function process($text)
45 6
    {
46
        $iterations = $this->maxIterations === null ? 1 : $this->maxIterations;
47 30
        $context = new ProcessorContext();
48 30
        $context->processor = $this;
49
50
        while ($iterations--) {
51 32
            $context->iterationNumber++;
52
            $newText = $this->processIteration($text, $context, null);
53
            if ($newText === $text) {
54 32
                break;
55
            }
56 32
            $text = $newText;
57 2
            $iterations += $this->maxIterations === null ? 1 : 0;
58
        }
59
60 32
        return $text;
61 32
    }
62 32
63 32
    private function dispatchEvent($name, $event)
64 32
    {
65 32
        if(null === $this->eventContainer) {
66 32
            return $event;
67 32
        }
68 32
69
        $handlers = $this->eventContainer->getListeners($name);
70 32
        foreach($handlers as $handler) {
71
            call_user_func_array($handler, array($event));
72 32
        }
73
74 32
        return $event;
75 32
    }
76 32
77
    private function processIteration($text, ProcessorContext $context, ShortcodeInterface $parent = null)
78
    {
79 32
        if (null !== $this->recursionDepth && $context->recursionLevel > $this->recursionDepth) {
80
            return $text;
81 32
        }
82 32
83 32
        $context->parent = $parent;
84
        $context->text = $text;
85 32
        $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 77 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...
86 32
        $this->dispatchEvent(Events::FILTER_SHORTCODES, $filterEvent);
87 32
        $shortcodes = $filterEvent->getShortcodes();
88 32
        $replaces = array();
89 32
        foreach ($shortcodes as $shortcode) {
90
            $this->prepareHandlerContext($shortcode, $context);
91 32
            $handler = $this->handlers->get($shortcode->getName());
92
            $replace = $this->processHandler($shortcode, $context, $handler);
93 32
            $length = mb_strlen($shortcode->getText());
94 32
95
            $replaces[] = array($replace, $shortcode->getOffset(), $length);
96 32
        }
97 30
        $replaces = array_filter($replaces);
98 32
99
        $applyEvent = new ApplyResultsEvent($parent, $text, $replaces);
100
        $this->dispatchEvent(Events::APPLY_RESULTS, $applyEvent);
101 32
102
        return $applyEvent->hasResult() ? $applyEvent->getResult() : $this->applyReplaces($text, $replaces);
103 32
    }
104 24
105
    private function applyReplaces($text, array $replaces)
106 24
    {
107 24 View Code Duplication
        return array_reduce(array_reverse($replaces), function($state, array $item) {
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
            return mb_substr($state, 0, $item[1]).$item[0].mb_substr($state, $item[1] + $item[2]);
109 24
        }, $text);
110
    }
111
112 17
    private function prepareHandlerContext(ParsedShortcodeInterface $shortcode, ProcessorContext $context)
113
    {
114
        $context->position++;
115
        $hasNamePosition = array_key_exists($shortcode->getName(), $context->namePosition);
116
        $context->namePosition[$shortcode->getName()] = $hasNamePosition ? $context->namePosition[$shortcode->getName()] + 1 : 1;
117
118
        $context->shortcodeText = $shortcode->getText();
119
        $context->offset = $shortcode->getOffset();
120
        $context->shortcode = $shortcode;
121
        $context->textContent = $shortcode->getContent();
122
    }
123
124 3
    private function processHandler(ParsedShortcodeInterface $parsed, ProcessorContext $context, $handler)
125
    {
126 3
        $processed = ProcessedShortcode::createFromContext(clone $context);
127 1
        $content = $this->processRecursion($processed, $context);
128 1
        $processed = $processed->withContent($content);
129
130
        return $handler
131 2
            ? call_user_func_array($handler, array($processed))
132 2
            : substr_replace($parsed->getText(), $processed->getContent(), strrpos($parsed->getText(), $parsed->getContent()), mb_strlen($parsed->getContent()));
133
    }
134 2
135
    private function processRecursion(ParsedShortcodeInterface $shortcode, ProcessorContext $context)
136
    {
137
        if ($this->autoProcessContent && null !== $shortcode->getContent()) {
138
            $context->recursionLevel++;
139
            // this is safe from using max iterations value because it's manipulated in process() method
140
            $content = $this->processIteration($shortcode->getContent(), clone $context, $shortcode);
141
            $context->recursionLevel--;
142
143
            return $content;
144
        }
145
146
        return $shortcode->getContent();
147 3
    }
148
149 3
    /**
150 1
     * Container for event handlers used in this processor.
151 1
     *
152
     * @param EventContainerInterface $eventContainer
153
     *
154 2
     * @return self
155 2
     */
156
    public function withEventContainer(EventContainerInterface $eventContainer)
157 2
    {
158
        $self = clone $this;
159
        $self->eventContainer = $eventContainer;
160
161
        return $self;
162
    }
163
164
    /**
165
     * Recursion depth level, null means infinite, any integer greater than or
166
     * equal to zero sets value (number of recursion levels). Zero disables
167
     * recursion. Defaults to null.
168
     *
169 3
     * @param int|null $depth
170
     *
171 3
     * @return self
172 1
     */
173 1 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...
174
    {
175
        if (null !== $depth && !(is_int($depth) && $depth >= 0)) {
176 2
            $msg = 'Recursion depth must be null (infinite) or integer >= 0!';
177 2
            throw new \InvalidArgumentException($msg);
178
        }
179 2
180
        $self = clone $this;
181
        $self->recursionDepth = $depth;
182
183
        return $self;
184
    }
185
186
    /**
187
     * Maximum number of iterations, null means infinite, any integer greater
188
     * than zero sets value. Zero is invalid because there must be at least one
189
     * iteration. Defaults to 1. Loop breaks if result of two consequent
190
     * iterations shows no change in processed text.
191
     *
192
     * @param int|null $iterations
193
     *
194
     * @return self
195
     */
196 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...
197
    {
198
        if (null !== $iterations && !(is_int($iterations) && $iterations > 0)) {
199
            $msg = 'Maximum number of iterations must be null (infinite) or integer > 0!';
200
            throw new \InvalidArgumentException($msg);
201
        }
202
203
        $self = clone $this;
204
        $self->maxIterations = $iterations;
205
206
        return $self;
207
    }
208
209
    /**
210
     * Whether shortcode content will be automatically processed and handler
211
     * already receives shortcode with processed content. If false, every
212
     * shortcode handler needs to process content on its own. Default true.
213
     *
214
     * @param bool $flag True if enabled (default), false otherwise
215
     *
216
     * @return self
217
     */
218
    public function withAutoProcessContent($flag)
219
    {
220
        if (!is_bool($flag)) {
221
            $msg = 'Auto processing flag must be a boolean value!';
222
            throw new \InvalidArgumentException($msg);
223
        }
224
225
        $self = clone $this;
226
        $self->autoProcessContent = (bool)$flag;
227
228
        return $self;
229
    }
230
}
231