Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.56% covered (warning)
75.56%
68 / 90
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
JCTabularContent
75.56% covered (warning)
75.56%
68 / 90
50.00% covered (danger)
50.00%
2 / 4
37.65
0.00% covered (danger)
0.00%
0 / 1
 createDefaultView
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWikitextForTransclusion
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 validateContent
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
1 / 1
14
 localizeData
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3namespace JsonConfig;
4
5use MediaWiki\Language\Language;
6
7class JCTabularContent extends JCDataContent {
8
9    protected function createDefaultView() {
10        return new JCTabularContentView();
11    }
12
13    /**
14     * Returns wiki-table representation of the tabular data
15     *
16     * @return string|bool The raw text, or false if the conversion failed.
17     */
18    public function getWikitextForTransclusion() {
19        $toWiki = static function ( $value ) {
20            if ( is_object( $value ) ) {
21                global $wgLang;
22                $value = JCUtils::pickLocalizedString( $value, $wgLang );
23            }
24            if ( preg_match( '/^[ .\pL\pN]*$/i', $value ) ) {
25                // Optimization: spaces, letters, numbers, and dots are returned without <nowiki>
26                return $value;
27            }
28            return '<nowiki>' . htmlspecialchars( $value ) . '</nowiki>';
29        };
30
31        $data = $this->getData();
32        $result = "{| class='wikitable sortable'\n";
33
34        // Create header
35        $result .= '!' . implode( "!!",
36            array_map(
37                static function ( $field ) use ( $toWiki ) {
38                    return $toWiki( $field->title ? : $field->name );
39                },
40                $data->schema->fields
41            )
42        ) . "\n";
43
44        // Create table content
45        foreach ( $data->data as $row ) {
46            $result .= "|-\n|" . implode( '||', array_map( $toWiki, $row ) ) . "\n";
47        }
48
49        $result .= "\n|}\n";
50
51        return $result;
52    }
53
54    /**
55     * Derived classes must implement this method to perform custom validation
56     * using the check(...) calls.
57     *
58     * This should be kept compatible with mw.JsonConfig.JsonEditDialog validation
59     */
60    public function validateContent() {
61        parent::validateContent();
62
63        $validators = [ JCValidators::isList() ];
64        $typeValidators = [];
65        $fieldsPath = [ 'schema', 'fields' ];
66        if ( $this->test( 'schema', JCValidators::isDictionary() ) &&
67            $this->test( $fieldsPath, JCValidators::isList() ) &&
68            $this->testEach( $fieldsPath, JCValidators::isDictionary() )
69        ) {
70            $hasError = false;
71            $allHeaders = [];
72            $fieldCount = count( $this->getField( $fieldsPath )->getValue() );
73            for ( $idx = 0; $idx < $fieldCount; $idx++ ) {
74                $header = false;
75                $hasError = !$this->test( [ 'schema', 'fields', $idx, 'name' ],
76                    JCValidators::isHeaderString( $allHeaders ),
77                    static function ( JCValue $jcv ) use ( &$header ) {
78                        $header = $jcv->getValue();
79                        return true;
80                    } ) || $hasError;
81                $hasError = !$this->test( [ 'schema', 'fields', $idx, 'type' ],
82                    JCValidators::validateDataType( $typeValidators ) ) || $hasError;
83                if ( $header ) {
84                    $hasError = !$this->testOptional( [ 'schema', 'fields', $idx, 'title' ],
85                        static function () use ( $header ) {
86                            return (object)[ 'en' => $header ];
87                        }, JCValidators::isLocalizedString() ) || $hasError;
88                }
89            }
90            $countValidator = JCValidators::checkListSize( $fieldCount, 'schema/fields' );
91            $validators[] = $countValidator;
92
93            if ( !$hasError ) {
94                $this->testEach( $fieldsPath, JCValidators::noExtraValues() );
95            }
96        }
97        $this->test( 'schema', JCValidators::noExtraValues() );
98
99        if ( !$this->thorough() ) {
100            // We are not doing any modifications to the data, so no need to validate it
101            return;
102        }
103
104        $this->test( 'data', JCValidators::isList() );
105        $this->test( [], JCValidators::noExtraValues() );
106        $this->testEach( 'data', $validators );
107        if ( $typeValidators ) {
108            /** @noinspection PhpUnusedParameterInspection */
109            $this->testEach( 'data', function ( JCValue $v, array $path ) use ( $typeValidators ) {
110                $isOk = true;
111                $lastIdx = count( $path );
112                foreach ( array_keys( $typeValidators ) as $k ) {
113                    $path[$lastIdx] = $k;
114                    $isOk = $this->test( $path, $typeValidators[$k] ) && $isOk;
115                }
116                return $isOk;
117            } );
118        }
119    }
120
121    /**
122     * Resolve any override-specific localizations, and add it to $result
123     * @param \stdClass $result
124     * @param Language $lang
125     */
126    protected function localizeData( $result, Language $lang ) {
127        parent::localizeData( $result, $lang );
128
129        $data = $this->getData();
130        $localize = static function ( $value ) use ( $lang ) {
131            return JCUtils::pickLocalizedString( $value, $lang );
132        };
133
134        $isLocalized = [];
135        $result->schema = (object)[];
136        $result->schema->fields = [];
137        foreach ( $data->schema->fields as $ind => $fld ) {
138            if ( $fld->type === 'localized' ) {
139                $isLocalized[] = $ind;
140            }
141            $result->schema->fields[] = (object)[
142                'name' => $fld->name,
143                'type' => $fld->type,
144                'title' => property_exists( $fld, 'title' ) ? $localize( $fld->title ) : $fld->name
145            ];
146        }
147
148        if ( !$isLocalized ) {
149            // There are no localized strings in the data, optimize
150            $result->data = $data->data;
151        } else {
152            $result->data = array_map( static function ( $row ) use ( $localize, $isLocalized ) {
153                foreach ( $isLocalized as $ind ) {
154                    if ( $row[$ind] !== null ) {
155                        $row[$ind] = $localize( $row[$ind] );
156                    }
157                }
158                return $row;
159            }, $data->data );
160        }
161    }
162}