Pipeline::realignIDs()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 3
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 $segmentContainsMarkup = 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 120
    public function __construct( ?string $source = null, ?string $target = null, array $dataRefMap = [] ) {
74 120
        $this->source     = $source;
75 120
        $this->target     = $target;
76 120
        $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 66
    public function getNextId(): string {
85 66
        $this->id_number++;
86
87 66
        return ConstantEnum::INTERNAL_ATTR_ID_PREFIX . $this->id_number;
88
    }
89
90
    /**
91
     * Sets the segmentContainsMarkup flag for the current segment.
92
     *
93
     * @return void
94
     */
95 27
    public function _setSegmentContainsMarkup() {
96 27
        $this->segmentContainsMarkup = true;
97
    }
98
99
    /**
100
     * Returns the configured source segment.
101
     *
102
     * @return string|null Source segment or null if not set.
103
     */
104 88
    public function getSource(): ?string {
105 88
        return $this->source;
106
    }
107
108
    /**
109
     * Returns the configured target segment.
110
     *
111
     * @return string|null Target segment or null if not set.
112
     */
113 88
    public function getTarget(): ?string {
114 88
        return $this->target;
115
    }
116
117
    /**
118
     * Returns the mapping array provided to the pipeline for external reference.
119
     *
120
     * @return array The data reference map.
121
     */
122 59
    public function getDataRefMap(): array {
123 59
        return $this->dataRefMap;
124
    }
125
126
    /**
127
     * Checks if a handler of the specified class is already registered in the pipeline.
128
     *
129
     * @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...
130
     */
131 9
    public function contains( string $handlerClass ): bool {
132 9
        return !empty( array_filter( $this->handlers, function ( $handler ) use ( $handlerClass ) {
133 9
            return $handlerClass == $handler->getName();
134 9
        } ) );
135
    }
136
137
    /**
138
     * Prepends a handler instance to the beginning of the pipeline.
139
     *
140
     * @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...
141
     *
142
     * @return $this This pipeline instance (for method chaining).
143
     */
144 1
    public function addFirst( string $handler ): Pipeline {
145 1
        $handlerInstance = $this->_register( $handler );
146 1
        array_unshift( $this->handlers, $handlerInstance );
147
148 1
        return $this;
149
    }
150
151
    /**
152
     * Inserts a handler into the pipeline before another specified handler.
153
     *
154
     * @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...
155
     * @param class-string<AbstractHandler> $newPipeline Class name (FQN) of the new handler to insert.
156
     *
157
     * @return $this This pipeline instance (for method chaining).
158
     */
159 1
    public function addBefore( string $before, string $newPipeline ): Pipeline {
160 1
        $newPipelineHandler = $this->_register( $newPipeline );
161 1
        foreach ( $this->handlers as $pos => $handler ) {
162 1
            if ( $handler->getName() == $before ) {
163 1
                array_splice( $this->handlers, $pos, 0, [ $newPipelineHandler ] );
164 1
                break;
165
            }
166
        }
167
168 1
        return $this;
169
170
    }
171
172
    /**
173
     * Inserts a handler into the pipeline after another specified handler.
174
     *
175
     * @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...
176
     * @param class-string<AbstractHandler> $newPipeline Class name (FQN) of the new handler to insert.
177
     *
178
     * @return $this This pipeline instance (for method chaining).
179
     */
180 9
    public function addAfter( string $after, string $newPipeline ): Pipeline {
181 9
        $newPipelineHandler = $this->_register( $newPipeline );
182 9
        foreach ( $this->handlers as $pos => $handler ) {
183 9
            if ( $handler->getName() == $after ) {
184 8
                array_splice( $this->handlers, $pos + 1, 0, [ $newPipelineHandler ] );
185 8
                break;
186
            }
187
        }
188
189 9
        return $this;
190
191
    }
192
193
    /**
194
     * Removes the specified handler class from the pipeline.
195
     *
196
     * @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...
197
     *
198
     * @return $this This pipeline instance (for method chaining).
199
     */
200 3
    public function remove( string $handlerToDelete ): Pipeline {
201 3
        foreach ( $this->handlers as $pos => $handler ) {
202 3
            if ( $handler->getName() == $handlerToDelete ) {
203 3
                unset( $this->handlers[ $pos ] );
204 3
                $this->handlers = array_values( $this->handlers );
205 3
                break;
206
            }
207
        }
208
209 3
        return $this;
210
    }
211
212
    /**
213
     * Appends a handler instance to the end of the pipeline.
214
     *
215
     * @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...
216
     *
217
     * @return $this This pipeline instance (for method chaining).
218
     */
219 120
    public function addLast( string $handler ): Pipeline {
220 120
        $newHandler       = $this->_register( $handler );
221 120
        $this->handlers[] = $newHandler;
222
223 120
        return $this;
224
    }
225
226
    /**
227
     * Transforms the provided segment by sequentially applying all registered handlers
228
     * and realigns IDs afterward.
229
     *
230
     * @param string $segment The input segment string to process.
231
     *
232
     * @return string The processed segment after all transformations.
233
     */
234 110
    public function transform( string $segment ): string {
235 110
        $this->id_number = -1;
236 110
        foreach ( $this->handlers as $handler ) {
237 110
            $segment = $handler->transform( $segment );
238
        }
239
240 110
        return $this->realignIDs( $segment );
241
    }
242
243
    /**
244
     * Adjusts and realigns ID tags in the provided segment string,
245
     * so IDs are sequential and formatted as required.
246
     *
247
     * @param string $segment The input string containing ID tags to realign.
248
     *
249
     * @return string The string with realigned and updated ID tags.
250
     */
251 110
    protected function realignIDs( string $segment ): string {
252 110
        if ( $this->id_number > -1 ) {
253 66
            preg_match_all( '/"__mtc_[0-9]+"/', $segment, $html, PREG_SET_ORDER );
254 66
            foreach ( $html as $pos => $tag_id ) {
255
                //replace subsequent elements excluding already encoded
256 66
                $segment = preg_replace( '/' . $tag_id[ 0 ] . '/', '"mtc_' . ( $pos + 1 ) . '"', $segment, 1 );
257
            }
258
        }
259
260 110
        return $segment;
261
    }
262
263
    /**
264
     * Instantiates a handler by class name and registers this pipeline with it.
265
     *
266
     * @template T of AbstractHandler
267
     * @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...
268
     *
269
     * @return T An instantiated handler object with the pipeline set.
270
     */
271 120
    protected function _register( string $handler ): AbstractHandler {
272 120
        $handler = new $handler();
273 120
        $handler->setPipeline( $this );
274
275 120
        return $handler;
276
    }
277
278
}