AbstractFilter::fromLayer1ToLayer0()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 11
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 20
ccs 12
cts 12
cp 1
crap 1
rs 9.9
1
<?php
2
3
/**
4
 * This file contains the abstract base class for all filter implementations.
5
 * It provides a foundational structure for transforming string data between different
6
 * "layers" of representation, such as raw database content, server-to-server communication
7
 * formats, and UI-ready strings.
8
 */
9
10
namespace Matecat\SubFiltering;
11
12
use Exception;
13
use Matecat\SubFiltering\Commons\Pipeline;
14
use Matecat\SubFiltering\Contracts\FeatureSetInterface;
15
use Matecat\SubFiltering\Enum\InjectableFiltersTags;
16
use Matecat\SubFiltering\Filters\EncodeToRawXML;
17
use Matecat\SubFiltering\Filters\EquivTextToBase64;
18
use Matecat\SubFiltering\Filters\LtGtEncode;
19
use Matecat\SubFiltering\Filters\MateCatCustomPHToOriginalValue;
20
use Matecat\SubFiltering\Filters\PlaceHoldXliffTags;
21
use Matecat\SubFiltering\Filters\RestoreEquivText;
22
use Matecat\SubFiltering\Filters\RestorePlaceHoldersToXLIFFLtGt;
23
use Matecat\SubFiltering\Filters\RestoreXliffTagsContent;
24
use Matecat\SubFiltering\Filters\SplitPlaceholder;
25
use Matecat\SubFiltering\Filters\StandardPHToMateCatCustomPH;
26
use Matecat\SubFiltering\Filters\StandardXEquivTextToMateCatCustomPH;
27
28
/**
29
 * Provides a blueprint for creating specific filter implementations.
30
 *
31
 * This abstract class defines the core structure and functionality for transforming
32
 * string data between different logical layers. It manages a set of features,
33
 * source/target languages, and transformation pipelines. Subclasses must implement
34
 * the specific transformation logic required for their context.
35
 *
36
 * The class uses a factory method `getInstance` to create and configure filter instances,
37
 * which are composed of a `Pipeline` of `AbstractHandler`s.
38
 */
39
abstract class AbstractFilter {
40
41
    /**
42
     * @var FeatureSetInterface
43
     * The set of features to be applied during the filtering process.
44
     */
45
    protected FeatureSetInterface $featureSet;
46
47
    /**
48
     * @var string|null
49
     * The source language of the segment.
50
     */
51
    protected ?string $source;
52
53
    /**
54
     * @var string|null
55
     * The target language of the segment.
56
     */
57
    protected ?string $target;
58
59
    /**
60
     * @var array
61
     * A map used for replacing data references within the segment.
62
     */
63
    protected array $dataRefMap = [];
64
65
    /**
66
     * @var class-string[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string[].
Loading history...
67
     * An ordered list of handler class names for the Layer 0 to Layer 1 transition.
68
     */
69
    protected array $orderedHandlersForLayer0ToLayer1Transition = [];
70
71
    /**
72
     * Factory method to create and configure a new instance of the filter.
73
     *
74
     * This method instantiates a new filter object and configures it with the provided
75
     * feature set, source/target languages, data-ref map, and a list of handlers for
76
     * the Layer 0 to Layer 1 transition.
77
     *
78
     * The handler list follows specific rules:
79
     * - An empty array (default) populates the filter with all default handlers from HandlersSorter.
80
     * - `null` clears the handler list, meaning no handlers will be used.
81
     * - A specific array of class names will be used as the handler list.
82
     *
83
     * @template T of static
84
     *
85
     * @param FeatureSetInterface $featureSet                                   The feature set to apply.
86
     * @param string|null         $source                                       The source language code (e.g., 'en-US').
87
     * @param string|null         $target                                       The target language code (e.g., 'it-IT').
88
     * @param array|null          $dataRefMap                                   A map for data-ref transformations, or null for an empty map.
89
     * @param array|null          $handlerTagNamesForLayer0ToLayer1Transition   A list of handler tag names for the Layer 0 to Layer 1 transition.
90
     *
91
     * @return T The configured instance of the filter.
92
     */
93 105
    public static function getInstance( FeatureSetInterface $featureSet, ?string $source = null, ?string $target = null, ?array $dataRefMap = [], ?array $handlerTagNamesForLayer0ToLayer1Transition = [] ): ?AbstractFilter {
94
        // Create a new instance of the specific filter class (e.g., MateCatFilter).
95 105
        $newInstance = new static();
96
97
        // Configure the instance with the provided settings via direct property access.
98 105
        $newInstance->featureSet = $featureSet;
99 105
        $newInstance->source     = $source;
100 105
        $newInstance->target     = $target;
101
        // Use the null coalescing operator to default to an empty array if $dataRefMap is null.
102 105
        $newInstance->dataRefMap = $dataRefMap ?? [];
103
104 105
        $handlerClassNamesForLayer0ToLayer1Transition = InjectableFiltersTags::classesForArrayTagNames( $handlerTagNamesForLayer0ToLayer1Transition );
105
106
        // Determine which handlers to use for the Layer 0 to Layer 1 transition.
107 105
        if ( is_array( $handlerClassNamesForLayer0ToLayer1Transition ) && empty( $handlerClassNamesForLayer0ToLayer1Transition ) ) {
108
            // If an empty array is passed, load the default set of handlers from the sorter.
109 92
            $handlerClassNamesForLayer0ToLayer1Transition = array_keys( HandlersSorter::getDefaultInjectedHandlers() );
110 13
        } elseif ( is_null( $handlerClassNamesForLayer0ToLayer1Transition ) ) {
111
            // If null is passed, use no handlers.
112 2
            $handlerClassNamesForLayer0ToLayer1Transition = [];
113
        }
114
        // Otherwise, use the custom list of handlers provided.
115
116
        // Sort the dynamic feature-based handlers.
117 105
        $sorter                                                  = new HandlersSorter( $handlerClassNamesForLayer0ToLayer1Transition );
118 105
        $newInstance->orderedHandlersForLayer0ToLayer1Transition = $sorter->getOrderedHandlersClassNames();
119
120
        // Return the fully configured filter instance.
121 105
        return $newInstance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newInstance returns the type Matecat\SubFiltering\AbstractFilter which is incompatible with the documented return type Matecat\SubFiltering\T.
Loading history...
122
    }
123
124
    /**
125
     * Transforms a segment from Layer 1 (server-to-server format) back to Layer 0 (database raw XML).
126
     *
127
     * This method defines the standard pipeline for reverting sub-filtered content,
128
     * restoring placeholders, and re-encoding XML entities to make it safe for database storage.
129
     *
130
     * @param string $segment The segment in Layer 1 format.
131
     *
132
     * @return string The transformed segment in Layer 0 format.
133
     * @throws Exception If any handler in the pipeline fails.
134
     */
135 80
    public function fromLayer1ToLayer0( string $segment ): string {
136
        // Initialize a new pipeline for this transformation.
137 80
        $channel = new Pipeline( $this->source, $this->target, $this->dataRefMap );
138
139
        // Add handlers to reverse the sub-filtering process.
140 80
        $channel->addLast( MateCatCustomPHToOriginalValue::class ); // Restore original PH values
141 80
        $channel->addLast( PlaceHoldXliffTags::class );             // Isolate XLIFF tags
142 80
        $channel->addLast( EncodeToRawXML::class );                 // Encode for raw XML storage
143 80
        $channel->addLast( LtGtEncode::class );                     // Encode '<' and '>'
144 80
        $channel->addLast( RestoreXliffTagsContent::class );        // Restore original XLIFF content
145 80
        $channel->addLast( RestorePlaceHoldersToXLIFFLtGt::class ); // Restore placeholders for '<' and '>'
146 80
        $channel->addLast( SplitPlaceholder::class );               // Handle split placeholders
147 80
        $channel->addLast( RestoreEquivText::class );               // Restore equiv-text content
148
149
        // Allow the current feature set to modify the pipeline (e.g., add or remove handlers).
150
        /** @var $channel Pipeline */
151 80
        $channel = $this->featureSet->filter( 'fromLayer1ToLayer0', $channel );
152
153
        // Process the segment through the pipeline and return the result.
154 80
        return $channel->transform( $segment );
155
    }
156
157
158
    /**
159
     * Transforms a segment from Layer 0 to Layer 1.
160
     *
161
     * This method performs the conversion of a segment from the input pre-processed stage (Layer 0)
162
     * to Layer 1, where additional processing and standardization are applied. It may use various
163
     * processing pipelines or handlers to achieve this transformation, depending on the implementation.
164
     *
165
     * @param string      $segment The input segment to be transformed from Layer 0 to Layer 1.
166
     * @param string|null $cid     An optional identifier for context or further processing specific to the segment.
167
     *
168
     * @return string The transformed segment after processing from Layer 0 to Layer 1.
169
     */
170
    public abstract function fromLayer0ToLayer1( string $segment, ?string $cid = null ): string;
171
172
    /**
173
     * Configures the pipeline for transforming content from Layer 0 to Layer 1.
174
     *
175
     * This is the default configuration method of MateCatFilter for setting up the pipeline that processes segments.
176
     * MyMemoryFilter or override this method to customize the pipeline as needed.
177
     *
178
     * This method builds the default pipeline for the Layer 0 to Layer 1 transformation.
179
     * It adds a series of standard handlers and then incorporates any custom handlers,
180
     * ensuring they are correctly ordered via `HandlersSorter`.
181
     *
182
     * @param Pipeline    $channel
183
     * @param string|null $cid
184
     */
185 91
    protected function configureFromLayer0ToLayer1Pipeline( Pipeline $channel, ?string $cid = null ): void {
0 ignored issues
show
Unused Code introduced by
The parameter $cid is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

185
    protected function configureFromLayer0ToLayer1Pipeline( Pipeline $channel, /** @scrutinizer ignore-unused */ ?string $cid = null ): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
186
187
        // Add initial handlers for standard XLIFF and placeholder normalization.
188 91
        $channel->addLast( StandardPHToMateCatCustomPH::class );
189 91
        $channel->addLast( StandardXEquivTextToMateCatCustomPH::class );
190 91
        $channel->addLast( PlaceHoldXliffTags::class );
191
192
        // Add the dynamic feature-based handlers.
193 91
        foreach ( $this->orderedHandlersForLayer0ToLayer1Transition as $handler ) {
194 90
            $channel->addLast( $handler );
195
        }
196
197
        // Add final handlers to restore XLIFF content and encode for the target layer.
198 91
        $channel->addLast( RestoreXliffTagsContent::class );
199 91
        $channel->addLast( RestorePlaceHoldersToXLIFFLtGt::class );
200 91
        $channel->addLast( EquivTextToBase64::class );
201
202
    }
203
204
}