Passed
Push — master ( c6a496...f5104b )
by Domenico
03:00
created

Xliff20::tagClose()   D

Complexity

Conditions 18
Paths 50

Size

Total Lines 122
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 52
c 1
b 0
f 0
nc 50
nop 2
dl 0
loc 122
rs 4.8666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * @author hashashiyyin [email protected] / [email protected]
5
 * Date: 02/08/24
6
 * Time: 17:51
7
 *
8
 */
9
10
namespace Matecat\XliffParser\XliffReplacer;
11
12
use Matecat\XliffParser\Utils\Strings;
13
14
class Xliff20 extends AbstractXliffReplacer {
15
16
    /**
17
     * @var int
18
     */
19
    private int $mdaGroupCounter = 0;
20
    /**
21
     * @var bool
22
     */
23
    protected bool $unitContainsMda = false;   // check if <unit> already contains a <mda:metadata> (forXliff v 2.*)
24
25
    /**
26
     * @var string
27
     */
28
    protected string $alternativeMatchesTag = 'mtc:matches';
29
30
    /**
31
     * @var string
32
     */
33
    protected string $tuTagName = 'unit';
34
35
    /**
36
     * @var string
37
     */
38
    protected string $namespace = "matecat";       // Custom namespace
39
40
    /**
41
     * @var array
42
     */
43
    protected array $nodesToBuffer = [
44
            'source',
45
            'mda:metadata',
46
            'memsource:additionalTagData',
47
            'originalData',
48
            'note'
49
    ];
50
51
    /**
52
     * @inheritDoc
53
     */
54
    protected function tagOpen( $parser, string $name, array $attr ) {
55
56
        $this->handleOpenUnit( $name, $attr );
57
58
        if ( 'mda:metadata' === $name ) {
59
            $this->unitContainsMda = true;
60
        }
61
62
        $this->trySetAltTrans( $name );;
63
        $this->checkSetInTarget( $name );
64
65
        // open buffer
66
        $this->setInBuffer( $name );
67
68
        // check if we are inside a <target>, obviously this happen only if there are targets inside the trans-unit
69
        // <target> must be stripped to be replaced, so this check avoids <target> reconstruction
70
        if ( !$this->inTarget ) {
71
72
            $tag = '';
73
74
            //
75
            // ============================================
76
            // only for Xliff 2.*
77
            // ============================================
78
            //
79
            // In xliff v2 we MUST add <mda:metadata> BEFORE <notes>/<originalData>/<segment>/<ignorable>
80
            //
81
            // As documentation says, <unit> contains:
82
            //
83
            // - elements from other namespaces, OPTIONAL
84
            // - Zero or one <notes> elements followed by
85
            // - Zero or one <originalData> element followed by
86
            // - One or more <segment> or <ignorable> elements in any order.
87
            //
88
            // For more info please refer to:
89
            //
90
            // http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html#unit
91
            //
92
            if ( in_array( $name, [ 'notes', 'originalData', 'segment', 'ignorable' ] ) &&
93
                    $this->unitContainsMda === false &&
94
                    !empty( $this->transUnits[ $this->currentTransUnitId ] ) &&
95
                    !$this->hasWrittenCounts
96
            ) {
97
                // we need to update counts here
98
                $this->updateCounts();
99
                $this->hasWrittenCounts = true;
100
                $tag                    .= $this->getWordCountGroupForXliffV2();
101
                $this->unitContainsMda  = true;
102
            }
103
104
            // construct tag
105
            $tag .= "<$name ";
106
107
            foreach ( $attr as $k => $v ) {
108
                //normal tag flux, put attributes in it but skip for translation state and set the right value for the attribute
109
                if ( $k != 'state' ) {
110
                    $tag .= "$k=\"$v\" ";
111
                }
112
            }
113
114
            $seg = $this->getCurrentSegment();
115
116
            if ( $name === $this->tuTagName && !empty( $seg ) && isset( $seg[ 'sid' ] ) ) {
117
118
                // add `matecat:segment-id` to xliff v.2*
119
                if ( strpos( $tag, 'matecat:segment-id' ) === false ) {
120
                    $tag .= "matecat:segment-id=\"{$seg[ 'sid' ]}\" ";
121
                }
122
123
            }
124
125
            // replace state for xliff v2
126
            if ( 'segment' === $name ) { // add state to segment in Xliff v2
127
                [ $stateProp, ] = StatusToStateAttribute::getState( $this->xliffVersion, $seg[ 'status' ] );
128
                $tag .= $stateProp;
129
            }
130
131
            $tag = $this->handleOpenXliffTag( $name, $attr, $tag );
132
133
            $this->checkForSelfClosedTagAndFlush( $parser, $tag );
134
135
        }
136
137
    }
138
139
    /**
140
     * @param string $name
141
     * @param array  $attr
142
     * @param string $tag
143
     *
144
     * @return string
145
     */
146
    protected function handleOpenXliffTag( string $name, array $attr, string $tag ): string {
147
        $tag = parent::handleOpenXliffTag( $name, $attr, $tag );
148
        // add oasis xliff 20 namespace
149
        if ( $name === 'xliff' && !array_key_exists( 'xmlns:mda', $attr ) ) {
150
            $tag .= 'xmlns:mda="urn:oasis:names:tc:xliff:metadata:2.0"';
151
        }
152
153
        return $tag;
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    protected function tagClose( $parser, string $name ) {
160
        $tag = '';
161
162
        /**
163
         * if is a tag within <target> or
164
         * if it is an empty tag, do not add closing tag because we have already closed it in
165
         *
166
         * self::tagOpen method
167
         */
168
        if ( !$this->isEmpty ) {
169
170
            if ( !$this->inTarget ) {
171
                $tag = "</$name>";
172
            }
173
174
            if ( 'target' == $name && !$this->inAltTrans ) {
175
176
                if ( isset( $this->transUnits[ $this->currentTransUnitId ] ) ) {
177
178
                    $seg = $this->getCurrentSegment();
179
180
                    // update counts
181
                    if ( !$this->hasWrittenCounts && !empty( $seg ) ) {
182
                        $this->updateSegmentCounts( $seg );
183
                    }
184
185
                    // delete translations so the prepareSegment
186
                    // will put source content in target tag
187
                    if ( $this->sourceInTarget ) {
188
                        $seg[ 'translation' ] = '';
189
                        $this->resetCounts();
190
                    }
191
192
                    // append $translation
193
                    $translation = $this->prepareTranslation( $seg );
194
195
                    //append translation
196
                    $tag = "<target>$translation</target>";
197
198
                }
199
200
                // signal we are leaving a target
201
                $this->targetWasWritten = true;
202
                $this->inTarget         = false;
203
                $this->postProcAndFlush( $this->outputFP, $tag, true );
204
205
            } elseif ( in_array( $name, $this->nodesToBuffer ) ) { // we are closing a critical CDATA section
206
207
                $this->bufferIsActive = false;
208
209
                // only for Xliff 2.*
210
                // write here <mda:metaGroup> and <mda:meta> if already present in the <unit>
211
                if ( 'mda:metadata' === $name && $this->unitContainsMda && !$this->hasWrittenCounts ) {
212
213
                    // we need to update counts here
214
                    $this->updateCounts();
215
                    $this->hasWrittenCounts = true;
216
217
                    $tag = $this->CDATABuffer;
218
                    $tag .= $this->getWordCountGroupForXliffV2( false );
219
                    $tag .= "    </mda:metadata>";
220
221
                } else {
222
                    $tag = $this->CDATABuffer . "</$name>";
223
                }
224
225
                $this->CDATABuffer = "";
226
227
                //flush to the pointer
228
                $this->postProcAndFlush( $this->outputFP, $tag );
229
230
            } elseif ( 'segment' === $name ) {
231
232
                // only for Xliff 2.*
233
                // if segment has no <target> add it BEFORE </segment>
234
                if ( !$this->targetWasWritten ) {
235
236
                    $seg = $this->getCurrentSegment();
237
238
                    if ( isset( $seg[ 'translation' ] ) ) {
239
240
                        $translation = $this->prepareTranslation( $seg );
241
                        // replace the tag
242
                        $tag = "<target>$translation</target>";
243
244
                        $tag .= '</segment>';
245
246
                    }
247
248
                }
249
250
                // update segmentPositionInTu
251
                $this->segmentInUnitPosition++;
252
253
                $this->postProcAndFlush( $this->outputFP, $tag );
254
255
                // we are leaving <segment>, reset $segmentHasTarget
256
                $this->targetWasWritten = false;
257
258
            } elseif ( $this->bufferIsActive ) { // this is a tag ( <g | <mrk ) inside a seg or seg-source tag
259
                $this->CDATABuffer .= "</$name>";
260
                // Do NOT Flush
261
            } else { //generic tag closure do Nothing
262
                // flush to pointer
263
                $this->postProcAndFlush( $this->outputFP, $tag );
264
            }
265
        } else {
266
            //ok, nothing to be done; reset flag for next coming tag
267
            $this->isEmpty = false;
268
        }
269
270
        // try to signal that we are leaving a target
271
        $this->tryUnsetAltTrans( $name );
272
273
        // check if we are leaving a <trans-unit> (xliff v1.*) or <unit> (xliff v2.*)
274
        if ( $this->tuTagName === $name ) {
275
            $this->currentTransUnitIsTranslatable = null;
276
            $this->inTU                           = false;
277
            $this->unitContainsMda                = false;
278
            $this->hasWrittenCounts               = false;
279
280
            $this->resetCounts();
281
        }
282
    }
283
284
    /**
285
     * Update counts
286
     */
287
    private function updateCounts() {
288
289
        $seg = $this->getCurrentSegment();
290
        if ( !empty( $seg ) ) {
291
            $this->updateSegmentCounts( $seg );
292
        }
293
294
    }
295
296
    /**
297
     * @param bool $withMetadataTag
298
     *
299
     * @return string
300
     */
301
    private function getWordCountGroupForXliffV2( bool $withMetadataTag = true ): string {
302
303
        $this->mdaGroupCounter++;
304
        $segments_count_array = $this->counts[ 'segments_count_array' ];
305
306
        $tag = '';
307
308
        if ( $withMetadataTag === true ) {
309
            $tag .= '<mda:metadata>';
310
        }
311
312
        $index = 0;
313
        foreach ( $segments_count_array as $segments_count_item ) {
314
315
            $id = 'word_count_tu.' . $this->currentTransUnitId . '.' . $index;
316
            $index++;
317
318
            $tag .= "    <mda:metaGroup id=\"" . $id . "\" category=\"row_xml_attribute\">
319
                                <mda:meta type=\"x-matecat-raw\">" . $segments_count_item[ 'raw_word_count' ] . "</mda:meta>
320
                                <mda:meta type=\"x-matecat-weighted\">" . $segments_count_item[ 'eq_word_count' ] . "</mda:meta>
321
                            </mda:metaGroup>";
322
        }
323
324
        if ( $withMetadataTag === true ) {
325
            $tag .= '</mda:metadata>';
326
        }
327
328
        return $tag;
329
330
    }
331
332
    /**
333
     * prepare segment tagging for xliff insertion
334
     *
335
     * @param array $seg
336
     *
337
     * @return string
338
     */
339
    protected function prepareTranslation( array $seg ): string {
340
341
        $segment     = Strings::removeDangerousChars( $seg [ 'segment' ] );
342
        $translation = Strings::removeDangerousChars( $seg [ 'translation' ] );
343
        $dataRefMap  = ( isset( $seg[ 'data_ref_map' ] ) ) ? Strings::jsonToArray( $seg[ 'data_ref_map' ] ) : [];
344
345
        if ( $seg [ 'translation' ] == '' ) {
346
            $translation = $segment;
347
        } else {
348
            if ( $this->callback instanceof XliffReplacerCallbackInterface ) {
349
                $error = ( !empty( $seg[ 'error' ] ) ) ? $seg[ 'error' ] : null;
350
                if ( $this->callback->thereAreErrors( $seg[ 'sid' ], $segment, $translation, $dataRefMap, $error ) ) {
351
                    $translation = '|||UNTRANSLATED_CONTENT_START|||' . $segment . '|||UNTRANSLATED_CONTENT_END|||';
352
                }
353
            }
354
        }
355
356
        return $translation;
357
358
    }
359
360
}