Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Filter
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 4
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
 getSsmlLang
n/a
0 / 0
n/a
0 / 0
0
 insertPart
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getParts
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Wikispeech\Segment\TextFilter;
4
5/**
6 * @file
7 * @ingroup Extensions
8 * @license GPL-2.0-or-later
9 */
10
11/**
12 * Processes incoming text/plain input,
13 * possibly transforming parts of the content,
14 * and returns text/xml SSML.
15 *
16 * @since 0.1.10
17 */
18abstract class Filter {
19
20    /** @var FilterPart[] */
21    private $parts;
22
23    /**
24     * @since 0.1.10
25     * @param string $text text/plain input
26     */
27    public function __construct( string $text ) {
28        $this->parts = [ new FilterPart( $text ) ];
29    }
30
31    /**
32     * @since 0.1.10
33     * @return string|null text/xml SSML output, or null if no rules applied
34     */
35    public function process(): ?string {
36        if ( count( $this->parts ) === 1 ) {
37            if ( $this->parts[0]->getAppliedRule() === null ) {
38                // no rules applied, the output is the same as the input.
39                return null;
40            // @phan-suppress-next-line PhanPluginDuplicateIfStatements T286912
41            } else {
42                // @todo There is a bug in Wikispeech-server.
43                // It can not handle SSML with a single <sub> as the only DOM child.
44                // https://phabricator.wikimedia.org/T286912
45                return null;
46            }
47        }
48        $ssml = '<speak xml:lang="' . $this->getSsmlLang() .
49            '" version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"' .
50            ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' .
51            ' xsi:schemalocation="http://www.w3.org/2001/10/synthesis' .
52            ' http://www.w3.org/TR/speech-synthesis/synthesis.xsd">';
53        foreach ( $this->parts as $part ) {
54            // phan made me use a variable rather than just using the getter all over.
55            $alias = $part->getAlias();
56            if ( $alias === null || $alias === $part->getText() ) {
57                $ssml .= $part->getText();
58            } else {
59                $ssml .= '<sub alias="' .
60                    htmlspecialchars( $alias, ENT_XML1, 'UTF-8' ) .
61                    '">' .
62                    htmlspecialchars( $part->getText(), ENT_XML1, 'UTF-8' ) .
63                    '</sub>';
64            }
65        }
66        $ssml .= '</speak>';
67        return $ssml;
68    }
69
70    /**
71     * @since 0.1.10
72     * @return string
73     */
74    abstract public function getSsmlLang(): string;
75
76    /**
77     * @since 0.1.10
78     * @param int $position
79     * @param FilterPart $part
80     */
81    public function insertPart( int $position, FilterPart $part ) {
82        $this->parts = array_merge(
83            array_slice( $this->parts, 0, $position ),
84            [ $part ],
85            array_slice( $this->parts, $position )
86        );
87    }
88
89    /**
90     * @since 0.1.10
91     * @return FilterPart[]
92     */
93    public function getParts(): array {
94        return $this->parts;
95    }
96
97}