Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.13% covered (warning)
72.13%
44 / 61
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZObjectSecondaryDataUpdate
72.13% covered (warning)
72.13%
44 / 61
50.00% covered (danger)
50.00%
1 / 2
26.81
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doUpdate
71.19% covered (warning)
71.19%
42 / 59
0.00% covered (danger)
0.00%
0 / 1
25.75
1<?php
2/**
3 * WikiLambda ZObject secondary data updater for when ZObjects are edited
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda;
12
13use Content;
14use MediaWiki\Deferred\DataUpdate;
15use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
16use MediaWiki\Extension\WikiLambda\ZObjects\ZReference;
17use MediaWiki\Title\Title;
18
19class ZObjectSecondaryDataUpdate extends DataUpdate {
20
21    private Title $title;
22    private ZObjectContent $zObject;
23
24    /**
25     * @param Title $title
26     * @param Content $zObject
27     */
28    public function __construct( Title $title, $zObject ) {
29        $this->title = $title;
30        $this->zObject = $zObject;
31    }
32
33    public function doUpdate() {
34        // Given this title, gets ZID
35        // Given this zObject, gets ZType
36        // 1. Delete labels from wikilambda_zobject_labels for this ZID
37        // 2. Delete labels from wikilambda_zobject_label_conflicts for this ZID
38        // 3. Gets labels from this zObject (Z2K3 of the ZObjectContent)
39        // 4. Finds conflicting labels, e.g. existing labels from other ZIDs that have same language-value
40        // 5. Saves conflicting labels in wikilambda_zobject_label_conflicts and
41        // 6. Saves non-conflicting labels in wikilambda_zobject_labels
42        // 7. If appropriate, clear wikilambda_ztester_results for this ZID
43        // 8. If appropriate, add entry to wikilambda_zlanguages for this ZID
44
45        // TODO (T300522): Only re-write the labels if they've changed.
46        // TODO (T300522): Use a single fancy upsert to remove/update/insert instead?
47
48        $zid = $this->title->getDBkey();
49
50        $zObjectStore = WikiLambdaServices::getZObjectStore();
51
52        // Delete all labels: primary ones and aliases
53        $zObjectStore->deleteZObjectLabelsByZid( $zid );
54        $zObjectStore->deleteZObjectLabelConflictsByZid( $zid );
55
56        // Delete language entries, if appropriate
57        $zObjectStore->deleteZLanguageFromLanguagesCache( $zid );
58
59        $labels = $this->zObject->getLabels()->getValueAsList();
60
61        // TODO (T357552): This should write the shortform, encoded type (e.g. `Z881(Z6)`)
62        $ztype = $this->zObject->getZType();
63
64        $innerZObject = $this->zObject->getInnerZObject();
65
66        // (T262089) Save output type in labels table for function and function call
67        $returnType = null;
68        // Get Z_FUNCTION_RETURN_TYPE if the ZObject is a Z8 Function
69        if ( $ztype === ZTypeRegistry::Z_FUNCTION ) {
70            $returnRef = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_RETURN_TYPE );
71            if ( $returnRef instanceof ZReference ) {
72                $returnType = $returnRef->getZValue();
73            }
74        }
75        // Get saved Z_FUNCTION_RETURN_TYPE of the Z_FUNCTIONCALL_FUNCTION if it's a Z7
76        if ( $ztype === ZTypeRegistry::Z_FUNCTIONCALL ) {
77            $functionRef = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTIONCALL_FUNCTION );
78            if ( $functionRef instanceof ZReference ) {
79                $returnType = $zObjectStore->fetchZFunctionReturnType( $functionRef->getZValue() );
80            }
81        }
82
83        $conflicts = $zObjectStore->findZObjectLabelConflicts( $zid, $ztype, $labels );
84        $newLabels = array_filter( $labels, static function ( $value, $lang ) use ( $conflicts ) {
85            return !isset( $conflicts[$lang] );
86        }, ARRAY_FILTER_USE_BOTH );
87
88        $zObjectStore->insertZObjectLabels( $zid, $ztype, $newLabels, $returnType );
89        $zObjectStore->insertZObjectLabelConflicts( $zid, $conflicts );
90
91        // (T285368) Write aliases in the labels table
92        $aliases = $this->zObject->getAliases()->getValueAsList();
93        if ( count( $aliases ) > 0 ) {
94            $zObjectStore->insertZObjectAliases( $zid, $ztype, $aliases, $returnType );
95        }
96
97        // Save function information in function table, if appropriate
98        // TODO (T362248): Have insertZFunctionReference do an update, and only delete if changing the type/target?
99        $zObjectStore->deleteZFunctionReference( $zid );
100        switch ( $ztype ) {
101            case ZTypeRegistry::Z_IMPLEMENTATION:
102                $zFunction = $innerZObject->getValueByKey( ZTypeRegistry::Z_IMPLEMENTATION_FUNCTION );
103                break;
104
105            case ZTypeRegistry::Z_TESTER:
106                $zFunction = $innerZObject->getValueByKey( ZTypeRegistry::Z_TESTER_FUNCTION );
107                break;
108
109            default:
110                $zFunction = null;
111                break;
112        }
113
114        if ( $zFunction && $zFunction->getZValue() ) {
115            $zObjectStore->insertZFunctionReference( $zid, $zFunction->getZValue(), $ztype );
116        }
117
118        // If appropriate, clear wikilambda_ztester_results for this ZID
119        // TODO (T338247): Only do this for the old revision not the new one.
120        switch ( $ztype ) {
121            case ZTypeRegistry::Z_FUNCTION:
122                $zObjectStore->deleteZFunctionFromZTesterResultsCache( $zid );
123                break;
124
125            case ZTypeRegistry::Z_IMPLEMENTATION:
126                $zObjectStore->deleteZImplementationFromZTesterResultsCache( $zid );
127                break;
128
129            case ZTypeRegistry::Z_TESTER:
130                $zObjectStore->deleteZTesterFromZTesterResultsCache( $zid );
131                break;
132
133            default:
134                // No action.
135        }
136
137        // If appropriate, add entry to wikilambda_zlanguages for this ZID
138        if ( $ztype === ZTypeRegistry::Z_LANGUAGE ) {
139            // Clear old values, if any
140            $zObjectStore->deleteZLanguageFromLanguagesCache( $zid );
141
142            // Set primary language code
143            $targetLanguage = $innerZObject->getValueByKey( ZTypeRegistry::Z_LANGUAGE_CODE )->getZValue();
144            $languageCodes = [ $targetLanguage ];
145            $zObjectStore->insertZLanguageToLanguagesCache( $zid, $targetLanguage );
146
147            // Set secondary language codes, if any
148            $secondaryLanguagesObject = $innerZObject->getValueByKey( ZTypeRegistry::Z_LANGUAGE_SECONDARYCODES );
149            if ( $secondaryLanguagesObject !== null ) {
150                '@phan-var \MediaWiki\Extension\WikiLambda\ZObjects\ZTypedList $secondaryLanguagesObject';
151                $secondaryLanguages = $secondaryLanguagesObject->getAsArray();
152
153                foreach ( $secondaryLanguages as $key => $secondaryLanguage ) {
154                    // $secondaryLanguage is a ZString but we want the actual string
155                    $secondaryLanguageString = $secondaryLanguage->getZValue();
156                    $languageCodes[] = $secondaryLanguageString;
157                    $zObjectStore->insertZLanguageToLanguagesCache( $zid, $secondaryLanguageString );
158                }
159            }
160
161            // (T343465) Add the language codes as fake aliases under Z1360/MUL (multi-lingual value)
162            $zObjectStore->insertZObjectAliases(
163                $zid,
164                $ztype,
165                [ 'Z1360' => $languageCodes ],
166                $returnType
167            );
168        }
169    }
170}