Passed
Pull Request — master (#51)
by Domenico
02:05
created

Pipeline::contains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * @author domenico [email protected] / [email protected]
5
 * Date: 05/11/18
6
 * Time: 14.05
7
 *
8
 */
9
10
namespace Matecat\SubFiltering\Commons;
11
12
use Matecat\SubFiltering\Enum\ConstantEnum;
13
14
/**
15
 * Class Pipeline
16
 *
17
 * Orchestrates a sequence of handler objects for segment transformation,
18
 * manages handler order, tracks transformation state, and realigns segment IDs.
19
 *
20
 * @package Matecat\SubFiltering\Commons
21
 */
22
class Pipeline {
23
24
    /**
25
     * Registered handler instances that make up the processing pipeline.
26
     *
27
     * @var AbstractHandler[]
28
     */
29
    protected array $handlers;
30
31
    /**
32
     * Tracks the current segment/internal ID number for realignment.
33
     *
34
     * @var int
35
     */
36
    protected int $id_number = -1;
37
38
    /**
39
     * The optional source string the Pipeline operates on.
40
     *
41
     * @var string|null
42
     */
43
    protected ?string $source;
44
45
    /**
46
     * The optional target string the Pipeline operates on.
47
     *
48
     * @var string|null
49
     */
50
    protected ?string $target;
51
52
    /**
53
     * A key/value map used for reference during segment processing.
54
     *
55
     * @var array
56
     */
57
    protected array $dataRefMap;
58
59
    /**
60
     * True if the processed segment contains HTML markup.
61
     *
62
     * @var bool
63
     */
64
    private bool $segmentContainsHtml = false;
65
66
    /**
67
     * Constructor.
68
     *
69
     * @param string|null $source     The source segment, if available.
70
     * @param string|null $target     The target segment, if available.
71
     * @param array       $dataRefMap Optional reference map relevant to the segment.
72
     */
73 106
    public function __construct( ?string $source = null, ?string $target = null, array $dataRefMap = [] ) {
74 106
        $this->source     = $source;
75 106
        $this->target     = $target;
76 106
        $this->dataRefMap = $dataRefMap;
77
    }
78
79
    /**
80
     * Gets and increments the next unique internal identifier for segment elements.
81
     *
82
     * @return string The generated identifier.
83
     */
84 63
    public function getNextId(): string {
85 63
        $this->id_number++;
86
87 63
        return ConstantEnum::INTERNAL_ATTR_ID_PREFIX . $this->id_number;
88
    }
89
90
    /**
91
     * Resets the internal identifier counter to its default before a new transformation.
92
     *
93
     * @return void
94
     */
95
    public function resetId(): void {
96
        $this->id_number = -1;
97
    }
98
99
    /**
100
     * Indicates whether the current segment contains HTML code.
101
     *
102
     * @return bool True if the segment contains HTML, otherwise false.
103
     */
104
    public function segmentContainsHtml(): bool {
105
        return $this->segmentContainsHtml;
106
    }
107
108
    /**
109
     * Sets the segmentContainsHtml flag for the current segment.
110
     *
111
     * @return void
112
     */
113 26
    public function setSegmentContainsHtml() {
114 26
        $this->segmentContainsHtml = true;
115
    }
116
117
    /**
118
     * Returns the configured source segment.
119
     *
120
     * @return string|null Source segment or null if not set.
121
     */
122 87
    public function getSource(): ?string {
123 87
        return $this->source;
124
    }
125
126
    /**
127
     * Returns the configured target segment.
128
     *
129
     * @return string|null Target segment or null if not set.
130
     */
131 87
    public function getTarget(): ?string {
132 87
        return $this->target;
133
    }
134
135
    /**
136
     * Returns the mapping array provided to the pipeline for external reference.
137
     *
138
     * @return array The data reference map.
139
     */
140 58
    public function getDataRefMap(): array {
141 58
        return $this->dataRefMap;
142
    }
143
144
    /**
145
     * Checks if a handler of the specified class is already registered in the pipeline.
146
     *
147
     * @param class-string<AbstractHandler> $handlerClass The handler
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
148
     */
149 5
    public function contains( string $handlerClass ): bool {
150 5
        return !empty( array_filter( $this->handlers, function ( $handler ) use ( $handlerClass ) {
151 5
            return $handlerClass == $handler->getName();
152 5
        } ) );
153
    }
154
155
    /**
156
     * Prepends a handler instance to the beginning of the pipeline.
157
     *
158
     * @param class-string<AbstractHandler> $handler Class name (FQN) of the handler to add.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
159
     *
160
     * @return $this This pipeline instance (for method chaining).
161
     */
162 1
    public function addFirst( string $handler ): Pipeline {
163 1
        $handlerInstance = $this->_register( $handler );
164 1
        array_unshift( $this->handlers, $handlerInstance );
165
166 1
        return $this;
167
    }
168
169
    /**
170
     * Inserts a handler into the pipeline before another specified handler.
171
     *
172
     * @param class-string<AbstractHandler> $before      Class name (FQN) of the handler before which the new handler will be inserted.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
173
     * @param class-string<AbstractHandler> $newPipeline Class name (FQN) of the new handler to insert.
174
     *
175
     * @return $this This pipeline instance (for method chaining).
176
     */
177 1
    public function addBefore( string $before, string $newPipeline ): Pipeline {
178 1
        $newPipelineHandler = $this->_register( $newPipeline );
179 1
        foreach ( $this->handlers as $pos => $handler ) {
180 1
            if ( $handler->getName() == $before ) {
181 1
                array_splice( $this->handlers, $pos, 0, [ $newPipelineHandler ] );
182 1
                break;
183
            }
184
        }
185
186 1
        return $this;
187
188
    }
189
190
    /**
191
     * Inserts a handler into the pipeline after another specified handler.
192
     *
193
     * @param class-string<AbstractHandler> $after       Class name (FQN) of the handler after which the new handler will be inserted.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
194
     * @param class-string<AbstractHandler> $newPipeline Class name (FQN) of the new handler to insert.
195
     *
196
     * @return $this This pipeline instance (for method chaining).
197
     */
198 3
    public function addAfter( string $after, string $newPipeline ): Pipeline {
199 3
        $newPipelineHandler = $this->_register( $newPipeline );
200 3
        foreach ( $this->handlers as $pos => $handler ) {
201 3
            if ( $handler->getName() == $after ) {
202 3
                array_splice( $this->handlers, $pos + 1, 0, [ $newPipelineHandler ] );
203 3
                break;
204
            }
205
        }
206
207 3
        return $this;
208
209
    }
210
211
    /**
212
     * Removes the specified handler class from the pipeline.
213
     *
214
     * @param class-string<AbstractHandler> $handlerToDelete Handler class name (FQN) to remove.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
215
     *
216
     * @return $this This pipeline instance (for method chaining).
217
     */
218 2
    public function remove( string $handlerToDelete ): Pipeline {
219 2
        foreach ( $this->handlers as $pos => $handler ) {
220 2
            if ( $handler->getName() == $handlerToDelete ) {
221 2
                unset( $this->handlers[ $pos ] );
222 2
                $this->handlers = array_values( $this->handlers );
223 2
                break;
224
            }
225
        }
226
227 2
        return $this;
228
    }
229
230
    /**
231
     * Appends a handler instance to the end of the pipeline.
232
     *
233
     * @param class-string<AbstractHandler> $handler Class name (FQN) of the handler to add.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractHandler> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractHandler>.
Loading history...
234
     *
235
     * @return $this This pipeline instance (for method chaining).
236
     */
237 106
    public function addLast( string $handler ): Pipeline {
238 106
        $newHandler       = $this->_register( $handler );
239 106
        $this->handlers[] = $newHandler;
240
241 106
        return $this;
242
    }
243
244
    /**
245
     * Transforms the provided segment by sequentially applying all registered handlers
246
     * and realigns IDs afterward.
247
     *
248
     * @param string $segment The input segment string to process.
249
     *
250
     * @return string The processed segment after all transformations.
251
     */
252 100
    public function transform( string $segment ): string {
253 100
        $this->id_number = -1;
254 100
        foreach ( $this->handlers as $handler ) {
255 100
            $segment = $handler->transform( $segment );
256
        }
257
258 100
        return $this->realignIDs( $segment );
259
    }
260
261
    /**
262
     * Adjusts and realigns ID tags in the provided segment string,
263
     * so IDs are sequential and formatted as required.
264
     *
265
     * @param string $segment The input string containing ID tags to realign.
266
     *
267
     * @return string The string with realigned and updated ID tags.
268
     */
269 100
    protected function realignIDs( string $segment ): string {
270 100
        if ( $this->id_number > -1 ) {
271 63
            preg_match_all( '/"__mtc_[0-9]+"/', $segment, $html, PREG_SET_ORDER );
272 63
            foreach ( $html as $pos => $tag_id ) {
273
                //replace subsequent elements excluding already encoded
274 63
                $segment = preg_replace( '/' . $tag_id[ 0 ] . '/', '"mtc_' . ( $pos + 1 ) . '"', $segment, 1 );
275
            }
276
        }
277
278 100
        return $segment;
279
    }
280
281
    /**
282
     * Instantiates a handler by class name and registers this pipeline with it.
283
     *
284
     * @template T of AbstractHandler
285
     * @param class-string<T> $handler Handler class name to instantiate.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
286
     *
287
     * @return T An instantiated handler object with the pipeline set.
288
     */
289 106
    protected function _register( string $handler ): AbstractHandler {
290 106
        $handler = new $handler();
291 106
        $handler->setPipeline( $this );
292
293 106
        return $handler;
294
    }
295
296
}