DataRefReplace::transform()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 2
b 0
f 0
nc 4
nop 1
dl 0
loc 18
ccs 10
cts 10
cp 1
crap 3
rs 9.9666
1
<?php
2
3
namespace Matecat\SubFiltering\Filters;
4
5
use Exception;
6
use Matecat\SubFiltering\Commons\AbstractHandler;
7
use Matecat\SubFiltering\Enum\CTypeEnum;
8
use Matecat\SubFiltering\Utils\DataRefReplacer;
9
use Matecat\XmlParser\XmlParser;
10
11
class DataRefReplace extends AbstractHandler {
12
13
    /**
14
     * @var array
15
     */
16
    private array $dataRefMap = [];
17
18
    /**
19
     * DataRefReplace constructor.
20
     */
21 57
    public function __construct() {
22 57
        parent::__construct();
23
    }
24
25
    /**
26
     * @inheritDoc
27
     */
28 57
    public function transform( string $segment ): string {
29
30 57
        if ( empty( $this->dataRefMap ) ) {
31 57
            $this->dataRefMap = $this->pipeline->getDataRefMap();
32
        }
33
34
        // dataRefMap is present only in xliff 2.0 files
35 57
        if ( empty( $this->dataRefMap ) ) {
36 45
            $segment = $this->replace_Ph_TagsWithoutDataRefCorrespondenceToMatecatPhTags( $segment );
37
38 45
            return $this->replace_Pc_TagsWithoutDataRefCorrespondenceToMatecatPhTags( $segment );
39
        }
40
41 12
        $dataRefReplacer = new DataRefReplacer( $this->dataRefMap );
42 12
        $segment         = $dataRefReplacer->replace( $segment );
43 12
        $segment         = $this->replace_Ph_TagsWithoutDataRefCorrespondenceToMatecatPhTags( $segment );
44
45 12
        return $this->replace_Pc_TagsWithoutDataRefCorrespondenceToMatecatPhTags( $segment );
46
    }
47
48
    /**
49
     * This function replace encoded ph tags (from Xliff 2.0) without any dataRef correspondence
50
     * to regular Matecat <ph> tag for UI presentation
51
     *
52
     * Example:
53
     *
54
     * We can control who sees content when with <ph id="source1" dataRef="source1"/>Visibility Constraints.
55
     *
56
     * Is transformed to:
57
     *
58
     * We can control who sees content when with &lt;ph id="mtc_ph_u_1" equiv-text="base64:PHBoIGlkPSJzb3VyY2UxIiBkYXRhUmVmPSJzb3VyY2UxIi8+"/&gt;Visibility Constraints.
59
     *
60
     * @param $segment
61
     *
62
     * @return string
63
     */
64 57
    private function replace_Ph_TagsWithoutDataRefCorrespondenceToMatecatPhTags( string $segment ): string {
65
66 57
        preg_match_all( '/<(ph .*?)>/iu', $segment, $phTags );
67
68 57
        if ( count( $phTags[ 0 ] ) === 0 ) {
69 20
            return $segment;
70
        }
71
72 37
        foreach ( $phTags[ 0 ] as $phTag ) {
73
74
            // check if phTag has not any correspondence on dataRef map
75 37
            if ( $this->isAValidPhTag( $phTag ) ) {
76 5
                $segment = preg_replace(
77 5
                        '/' . preg_quote( $phTag, '/' ) . '/',
78 5
                        '<ph id="' . $this->getPipeline()->getNextId() .
79 5
                        '" ctype="' . CTypeEnum::ORIGINAL_PH_OR_NOT_DATA_REF .
80 5
                        '" equiv-text="base64:' . base64_encode( $phTag ) .
81 5
                        '"/>',
82 5
                        $segment,
83 5
                        1 // replace ONLY ONE occurrence
84 5
                );
85
            }
86
        }
87
88 37
        return $segment;
89
    }
90
91
    /**
92
     * This function checks if a ph tag with dataRef attribute
93
     * and without equiv-text
94
     * a correspondence on dataRef map
95
     *
96
     * @param string $phTag
97
     *
98
     * @return bool
99
     */
100 37
    private function isAValidPhTag( string $phTag ): bool {
101
102
        // try not to throw exception for wrong segments with opening tags and no closing
103
        try {
104 37
            $parsed = XmlParser::parse( $phTag, true );
105 1
        } catch ( Exception $e ) {
106 1
            return false;
107
        }
108
109
        // check for matecat ctype
110 36
        $cType = isset( $parsed[ 0 ]->attributes[ 'ctype' ] ) ? $parsed[ 0 ]->attributes[ 'ctype' ] : 'not-found';
111 36
        if ( CTypeEnum::isMatecatCType( $cType ) ) {
112 34
            return false;
113
        }
114
115
        // if has equiv-text don't touch
116 6
        if ( isset( $parsed[ 0 ]->attributes[ 'equiv-text' ] ) ) {
117 1
            return false;
118
        }
119
120 5
        if ( isset( $parsed[ 0 ]->attributes[ 'dataRef' ] ) ) {
121 2
            return !array_key_exists( $parsed[ 0 ]->attributes[ 'dataRef' ], $this->dataRefMap );
122
        }
123
124 3
        return true;
125
126
    }
127
128
    /**
129
     * This function replace encoded pc tags (from Xliff 2.0) without any dataRef correspondence
130
     * to regular Matecat <ph> tag for UI presentation
131
     *
132
     * Example:
133
     *
134
     * Text &lt;ph id="source1_1" dataType="pcStart" originalData="Jmx0O3BjIGlkPSJzb3VyY2UxIiBkYXRhUmVmU3RhcnQ9InNvdXJjZTEiIGRhdGFSZWZFbmQ9InNvdXJjZTEiJmd0Ow==" dataRef="source1" equiv-text="base64:eA=="/&gt;&lt;pc id="1u" type="fmt" subType="m:u"&gt;link&lt;/pc&gt;&lt;ph id="source1_2" dataType="pcEnd" originalData="Jmx0Oy9wYyZndDs=" dataRef="source1" equiv-text="base64:eA=="/&gt;.
135
     *
136
     * is transformed to:
137
     *
138
     * Text &lt;ph id="source1_1" dataType="pcStart" originalData="Jmx0O3BjIGlkPSJzb3VyY2UxIiBkYXRhUmVmU3RhcnQ9InNvdXJjZTEiIGRhdGFSZWZFbmQ9InNvdXJjZTEiJmd0Ow==" dataRef="source1" equiv-text="base64:eA=="/&gt;&lt;ph id="mtc_u_1" equiv-text="base64:Jmx0O3BjIGlkPSIxdSIgdHlwZT0iZm10IiBzdWJUeXBlPSJtOnUiJmd0Ow=="/&gt;link&lt;ph id="mtc_u_2" equiv-text="base64:Jmx0Oy9wYyZndDs="/&gt;&lt;ph id="source1_2" dataType="pcEnd" originalData="Jmx0Oy9wYyZndDs=" dataRef="source1" equiv-text="base64:eA=="/&gt;.
139
     *
140
     * @param $segment
141
     *
142
     * @return string
143
     */
144 57
    private function replace_Pc_TagsWithoutDataRefCorrespondenceToMatecatPhTags( string $segment ): string {
145
146 57
        preg_match_all( '/<(pc .*?)>/iu', $segment, $openingPcTags );
147 57
        preg_match_all( '|<(/pc)>|iu', $segment, $closingPcTags );
148
149 57
        if ( count( $openingPcTags[ 0 ] ) === 0 ) {
150 53
            return $segment;
151
        }
152
153 4
        foreach ( $openingPcTags[ 0 ] as $openingPcTag ) {
154 4
            $segment = preg_replace(
155 4
                    '/' . preg_quote( $openingPcTag, '/' ) . '/',
156 4
                    '<ph id="' . $this->getPipeline()->getNextId() .
157 4
                    '" ctype="' . CTypeEnum::ORIGINAL_PC_OPEN_NO_DATA_REF .
158 4
                    '" equiv-text="base64:' . base64_encode( $openingPcTag ) .
159 4
                    '"/>',
160 4
                    $segment,
161 4
                    1
162 4
            );
163
        }
164
165 4
        foreach ( $closingPcTags[ 0 ] as $closingPcTag ) {
166 4
            $segment = preg_replace(
167 4
                    '/' . preg_quote( $closingPcTag, '/' ) . '/',
168 4
                    '<ph id="' . $this->getPipeline()->getNextId() .
169 4
                    '" ctype="' . CTypeEnum::ORIGINAL_PC_CLOSE_NO_DATA_REF .
170 4
                    '" equiv-text="base64:' . base64_encode( $closingPcTag ) .
171 4
                    '"/>',
172 4
                    $segment,
173 4
                    1
174 4
            );
175
        }
176
177 4
        return $segment;
178
    }
179
}