Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
91.63% |
197 / 215 |
|
71.43% |
5 / 7 |
CRAP | |
0.00% |
0 / 1 |
| ZObjectSecondaryDataUpdate | |
91.63% |
197 / 215 |
|
71.43% |
5 / 7 |
50.41 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| doUpdate | |
86.81% |
79 / 91 |
|
0.00% |
0 / 1 |
19.83 | |||
| getRelatedZObjects | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
| getRelatedZObjectsOfFunctionCall | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 | |||
| getRelatedZObjectsOfFunction | |
100.00% |
50 / 50 |
|
100.00% |
1 / 1 |
13 | |||
| getRelatedZObjectsOfType | |
100.00% |
30 / 30 |
|
100.00% |
1 / 1 |
5 | |||
| getRelatedZObjectsOfInstance | |
76.00% |
19 / 25 |
|
0.00% |
0 / 1 |
5.35 | |||
| 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 | |
| 11 | namespace MediaWiki\Extension\WikiLambda\ZObjectContent; |
| 12 | |
| 13 | use MediaWiki\Deferred\DataUpdate; |
| 14 | use MediaWiki\Extension\WikiLambda\Cache\MemcachedWrapper; |
| 15 | use MediaWiki\Extension\WikiLambda\OrchestratorRequest; |
| 16 | use MediaWiki\Extension\WikiLambda\Registry\ZLangRegistry; |
| 17 | use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry; |
| 18 | use MediaWiki\Extension\WikiLambda\ZErrorException; |
| 19 | use MediaWiki\Extension\WikiLambda\ZObjects\ZFunction; |
| 20 | use MediaWiki\Extension\WikiLambda\ZObjects\ZFunctionCall; |
| 21 | use MediaWiki\Extension\WikiLambda\ZObjects\ZObject; |
| 22 | use MediaWiki\Extension\WikiLambda\ZObjects\ZReference; |
| 23 | use MediaWiki\Extension\WikiLambda\ZObjects\ZType; |
| 24 | use MediaWiki\Extension\WikiLambda\ZObjects\ZTypedList; |
| 25 | use MediaWiki\Extension\WikiLambda\ZObjectStore; |
| 26 | use MediaWiki\Extension\WikiLambda\ZObjectUtils; |
| 27 | use MediaWiki\Logger\LoggerFactory; |
| 28 | use MediaWiki\Title\Title; |
| 29 | use Psr\Log\LoggerInterface; |
| 30 | |
| 31 | class ZObjectSecondaryDataUpdate extends DataUpdate { |
| 32 | |
| 33 | private LoggerInterface $logger; |
| 34 | |
| 35 | public const INSTANCEOFENUM_DB_KEY = 'instanceofenum'; |
| 36 | |
| 37 | /** |
| 38 | * @param Title $title |
| 39 | * @param ZObjectContent $zObject |
| 40 | * @param ZObjectStore $zObjectStore |
| 41 | * @param MemcachedWrapper $zObjectCache |
| 42 | * @param OrchestratorRequest|null $orchestrator |
| 43 | */ |
| 44 | public function __construct( |
| 45 | private readonly Title $title, |
| 46 | private readonly ZObjectContent $zObject, |
| 47 | private readonly ZObjectStore $zObjectStore, |
| 48 | private readonly MemcachedWrapper $zObjectCache, |
| 49 | private ?OrchestratorRequest $orchestrator = null |
| 50 | ) { |
| 51 | // Non-injected items |
| 52 | $this->logger = LoggerFactory::getInstance( 'WikiLambda' ); |
| 53 | } |
| 54 | |
| 55 | public function doUpdate() { |
| 56 | // Given this title, gets ZID |
| 57 | // Given this zObject, gets ZType |
| 58 | // 1. Update as needed labels and aliases in wikilambda_zobject_labels for this ZID |
| 59 | // 2. Update as needed conflicting labels in wikilambda_zobject_label_conflicts for this ZID |
| 60 | // 3. If appropriate, clear wikilambda_ztester_results for this ZID |
| 61 | // 4. Update as needed entries in wikilambda_zlanguages for this ZID |
| 62 | // 5. Update as needed related zobjects in wikilambda_zobject_join for this ZID |
| 63 | |
| 64 | $zid = $this->title->getDBkey(); |
| 65 | |
| 66 | // (T380446) If the object is not valid there's nothing useful to do, except log an error and exit. |
| 67 | if ( !$this->zObject->isValid() ) { |
| 68 | $zerror = $this->zObject->getErrors(); |
| 69 | $this->logger->error( |
| 70 | 'ZObjectSecondaryDataUpdate unable to process, error thrown', |
| 71 | [ |
| 72 | 'zid' => $zid, |
| 73 | 'message' => $zerror->getMessage() |
| 74 | ] |
| 75 | ); |
| 76 | return; |
| 77 | } |
| 78 | |
| 79 | // Object is valid, we go on! |
| 80 | |
| 81 | $labels = $this->zObject->getLabels()->getValueAsList(); |
| 82 | |
| 83 | // TODO (T357552): This should write the shortform, encoded type (e.g. `Z881(Z6)`) |
| 84 | $ztype = $this->zObject->getZType(); |
| 85 | |
| 86 | // Store the ZObject in the object cache, for faster retrieval here and (in future) in the orchestrator |
| 87 | $cacheKey = $this->zObjectCache->makeKey( ZObjectStore::ZOBJECT_CACHE_KEY_PREFIX, $zid ); |
| 88 | $this->logger->debug( |
| 89 | __METHOD__ . ' writing new ZObject value to cache "' . $zid . '": type "' . $ztype . '".', |
| 90 | [ 'instance' => $zid, 'type' => $ztype ] |
| 91 | ); |
| 92 | $cacheResult = $this->zObjectCache->set( |
| 93 | $cacheKey, |
| 94 | $this->zObject->getText(), |
| 95 | $this->zObjectCache::TTL_MONTH |
| 96 | ); |
| 97 | if ( !$cacheResult ) { |
| 98 | $this->logger->warning( __METHOD__ . ' failed to cache new ZObject "' . $zid . '".', [ 'zid' => $zid ] ); |
| 99 | } |
| 100 | if ( $this->orchestrator ) { |
| 101 | $queryZ2 = $this->zObject->getObject(); |
| 102 | $this->orchestrator->persistToCache( $queryZ2 ); |
| 103 | } |
| 104 | |
| 105 | $innerZObject = $this->zObject->getInnerZObject(); |
| 106 | |
| 107 | $returnType = null; |
| 108 | // (T262089) Save output type in labels table for function and function call |
| 109 | // Get Z_FUNCTION_RETURN_TYPE if the ZObject is a Z8 Function |
| 110 | if ( $ztype === ZTypeRegistry::Z_FUNCTION ) { |
| 111 | $returnRef = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ); |
| 112 | // Fallback, save output type as Object/Z1 to avoid NULL returning functions |
| 113 | $returnType = ZTypeRegistry::Z_OBJECT; |
| 114 | if ( ( $returnRef instanceof ZReference ) || ( $returnRef instanceof ZFunctionCall ) ) { |
| 115 | // ZReference->getZValue returns the reference Zid |
| 116 | // ZFunctionCall->getZValue returns the function call function Zid |
| 117 | $returnType = $returnRef->getZValue(); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | // Compute language codes once for Z_LANGUAGE so they can be folded into the |
| 122 | // MUL alias set up-front, and used by the wikilambda_zlanguages reconcile below. |
| 123 | $languageCodes = []; |
| 124 | if ( $ztype === ZTypeRegistry::Z_LANGUAGE ) { |
| 125 | $languageCodes[] = $innerZObject |
| 126 | ->getValueByKey( ZTypeRegistry::Z_LANGUAGE_CODE )->getZValue(); |
| 127 | $secondaryLanguagesObject = $innerZObject |
| 128 | ->getValueByKey( ZTypeRegistry::Z_LANGUAGE_SECONDARYCODES ); |
| 129 | if ( $secondaryLanguagesObject !== null ) { |
| 130 | '@phan-var ZTypedList $secondaryLanguagesObject'; |
| 131 | foreach ( $secondaryLanguagesObject->getAsArray() as $secondaryLanguage ) { |
| 132 | // $secondaryLanguage is a ZString but we want the actual string |
| 133 | $languageCodes[] = $secondaryLanguage->getZValue(); |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // Compute the desired wikilambda_zobject_function_join row, if any. |
| 139 | // Implementations and testers each point to their parent function; other |
| 140 | // types have no row in this table. |
| 141 | $expectedFunctionZid = null; |
| 142 | $expectedFunctionRefType = null; |
| 143 | if ( $ztype === ZTypeRegistry::Z_IMPLEMENTATION ) { |
| 144 | $expectedFunctionZid = $innerZObject |
| 145 | ->getValueByKey( ZTypeRegistry::Z_IMPLEMENTATION_FUNCTION )->getZValue(); |
| 146 | $expectedFunctionRefType = $ztype; |
| 147 | } elseif ( $ztype === ZTypeRegistry::Z_TESTER ) { |
| 148 | $expectedFunctionZid = $innerZObject |
| 149 | ->getValueByKey( ZTypeRegistry::Z_TESTER_FUNCTION )->getZValue(); |
| 150 | $expectedFunctionRefType = $ztype; |
| 151 | } |
| 152 | |
| 153 | $conflicts = $this->zObjectStore->findZObjectLabelConflicts( $zid, $ztype, $labels ); |
| 154 | $newLabels = array_filter( $labels, static function ( $value, $lang ) use ( $conflicts ) { |
| 155 | return !isset( $conflicts[$lang] ); |
| 156 | }, ARRAY_FILTER_USE_BOTH ); |
| 157 | |
| 158 | // (T285368) Write aliases in the labels table. |
| 159 | // (T358737) Add the zid as a fake alias under Z1360/MUL (multi-lingual value). |
| 160 | // (T343465) For Z_LANGUAGE, also add the language codes as MUL aliases. |
| 161 | $aliases = $this->zObject->getAliases()->getValueAsList(); |
| 162 | $aliases[ ZLangRegistry::MULTILINGUAL_VALUE ] = array_merge( [ $zid ], $languageCodes ); |
| 163 | |
| 164 | // (T300522) Update as needed labels, aliases, and conflicts in place: preserve |
| 165 | // wlzl_id / wlzlc_id across saves and write only the actual delta. The dominant |
| 166 | // "no labels changed" case issues zero writes to these tables. |
| 167 | $this->zObjectStore->synchroniseZObjectLabels( $zid, $ztype, $newLabels, $aliases, $returnType ); |
| 168 | $this->zObjectStore->synchroniseZObjectLabelConflicts( $zid, $conflicts ); |
| 169 | |
| 170 | // ======================================================== |
| 171 | // General reconcile actions: |
| 172 | // ======================================================== |
| 173 | // * (T362248) Reconcile function reference in wikilambda_zobject_function_join in place |
| 174 | // * Reconcile related ZObjects in wikilambda_zobject_join in place |
| 175 | // * Reconcile language-code rows in wikilambda_zlanguages in place |
| 176 | $this->zObjectStore->synchroniseZFunctionReference( |
| 177 | $zid, $expectedFunctionZid, $expectedFunctionRefType |
| 178 | ); |
| 179 | // Pass [] for non-Z_LANGUAGE saves so any stale rows from a prior Z60 incarnation |
| 180 | // (or test setup) get cleared; the no-row case is a cheap SELECT and zero writes. |
| 181 | $this->zObjectStore->synchroniseZLanguageCodes( $zid, $languageCodes ); |
| 182 | |
| 183 | // Compute the desired related-ZObject rows up front; split into two |
| 184 | // ownership scopes that the synchronise calls below honour separately: |
| 185 | // - "own" rows where wlzo_main_zid = $zid (the usual case) |
| 186 | // - "instance-of-enum" rows where wlzo_main_zid is *another* ZID but |
| 187 | // wlzo_main_type = $zid and wlzo_key = instanceofenum (only Z_TYPE |
| 188 | // saves on an enum type produce these, via getRelatedZObjectsOfType) |
| 189 | $relatedZObjects = $this->getRelatedZObjects( $zid, $ztype, $innerZObject ); |
| 190 | $ownRelatedRows = []; |
| 191 | $instanceOfEnumRelatedRows = []; |
| 192 | foreach ( $relatedZObjects as $rel ) { |
| 193 | if ( $rel->zid === $zid ) { |
| 194 | $ownRelatedRows[] = $rel; |
| 195 | } else { |
| 196 | $instanceOfEnumRelatedRows[] = $rel; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | $this->zObjectStore->synchroniseRelatedZObjects( |
| 201 | [ 'wlzo_main_zid' => $zid ], |
| 202 | $ownRelatedRows |
| 203 | ); |
| 204 | |
| 205 | // ======================================================== |
| 206 | // Type specific actions: |
| 207 | // ======================================================== |
| 208 | // * Function / Implementation / Tester: |
| 209 | // - clear test results cache |
| 210 | // * Type: |
| 211 | // - reconcile instanceofenum rows in wikilambda_zobject_join in place |
| 212 | switch ( $ztype ) { |
| 213 | case ZTypeRegistry::Z_FUNCTION: |
| 214 | // TODO (T338247): Only clear test results cache for the old revision, not the new one |
| 215 | $this->zObjectStore->deleteZFunctionFromZTesterResultsCache( $zid ); |
| 216 | break; |
| 217 | |
| 218 | case ZTypeRegistry::Z_IMPLEMENTATION: |
| 219 | // TODO (T338247): Only clear test results cache for the old revision, not the new one |
| 220 | $this->zObjectStore->deleteZImplementationFromZTesterResultsCache( $zid ); |
| 221 | break; |
| 222 | |
| 223 | case ZTypeRegistry::Z_TESTER: |
| 224 | // TODO (T338247): Only clear test results cache for the old revision, not the new one |
| 225 | $this->zObjectStore->deleteZTesterFromZTesterResultsCache( $zid ); |
| 226 | break; |
| 227 | |
| 228 | case ZTypeRegistry::Z_TYPE: |
| 229 | // Reconcile instanceofenum rows for this type. Non-enum types pass |
| 230 | // an empty desired set, so any stale rows from a prior enum status |
| 231 | // get cleared. |
| 232 | $this->zObjectStore->synchroniseRelatedZObjects( |
| 233 | [ |
| 234 | 'wlzo_main_type' => $zid, |
| 235 | 'wlzo_key' => self::INSTANCEOFENUM_DB_KEY, |
| 236 | ], |
| 237 | $instanceOfEnumRelatedRows |
| 238 | ); |
| 239 | break; |
| 240 | |
| 241 | default: |
| 242 | // No action. |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | /** |
| 247 | * Return all important relations between the given object and others |
| 248 | * to insert in the wikilambda_zobject_join table. The relations are |
| 249 | * given by the key. Currently finds relations for: |
| 250 | * * Functions/Z8 |
| 251 | * * Types/Z4 |
| 252 | * * Instances of enum types |
| 253 | * |
| 254 | * @param string $zid |
| 255 | * @param string $ztype |
| 256 | * @param ZObject $innerZObject |
| 257 | * @return array Array of rows to insert in the join table |
| 258 | */ |
| 259 | private function getRelatedZObjects( $zid, $ztype, $innerZObject ) { |
| 260 | if ( $innerZObject instanceof ZFunction ) { |
| 261 | return $this->getRelatedZObjectsOfFunction( $zid, $innerZObject ); |
| 262 | } |
| 263 | |
| 264 | if ( $innerZObject instanceof ZType ) { |
| 265 | return $this->getRelatedZObjectsOfType( $zid, $innerZObject ); |
| 266 | } |
| 267 | |
| 268 | if ( $innerZObject instanceof ZFunctionCall ) { |
| 269 | return $this->getRelatedZObjectsOfFunctionCall( $zid, $innerZObject ); |
| 270 | } |
| 271 | |
| 272 | return $this->getRelatedZObjectsOfInstance( $zid, $ztype ); |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * Return all important relations between the given function and others. |
| 277 | * Currently returns: |
| 278 | * * key:Z7K1: Function |
| 279 | * |
| 280 | * @param string $zid |
| 281 | * @param ZFunctionCall $innerZObject |
| 282 | * @return array Array of rows to insert in the join table |
| 283 | */ |
| 284 | private function getRelatedZObjectsOfFunctionCall( $zid, $innerZObject ) { |
| 285 | $relatedZObjects = []; |
| 286 | |
| 287 | // Key:Z7K1: Get function zid |
| 288 | $functionZid = $innerZObject->getZValue(); |
| 289 | if ( $functionZid ) { |
| 290 | $relatedZObjects[] = (object)[ |
| 291 | 'zid' => $zid, |
| 292 | 'type' => ZTypeRegistry::Z_FUNCTIONCALL, |
| 293 | 'key' => ZTypeRegistry::Z_FUNCTIONCALL_FUNCTION, |
| 294 | 'related_zid' => $functionZid, |
| 295 | 'related_type' => ZTypeRegistry::Z_FUNCTION |
| 296 | ]; |
| 297 | } |
| 298 | |
| 299 | return $relatedZObjects; |
| 300 | } |
| 301 | |
| 302 | /** |
| 303 | * Return all important relations between the given function and others. |
| 304 | * Currently returns: |
| 305 | * * key:Z8K1: Type of every function input |
| 306 | * * key:Z8K2: Type of the function output |
| 307 | * * key:Z8K3: Test connected to the function |
| 308 | * * key:Z8K4: Implementation connected to the function |
| 309 | * |
| 310 | * @param string $zid |
| 311 | * @param ZFunction $innerZObject |
| 312 | * @return array Array of rows to insert in the join table |
| 313 | */ |
| 314 | private function getRelatedZObjectsOfFunction( $zid, $innerZObject ) { |
| 315 | $relatedZObjects = []; |
| 316 | |
| 317 | // Key:Z8K1: Get input types |
| 318 | $inputs = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_ARGUMENTS ); |
| 319 | if ( $inputs instanceof ZTypedList ) { |
| 320 | $inputList = $inputs->getAsArray(); |
| 321 | foreach ( $inputList as $key => $input ) { |
| 322 | $inputTypeObject = $input->getValueByKey( ZTypeRegistry::Z_ARGUMENTDECLARATION_TYPE ); |
| 323 | $inputTypeString = ZObjectUtils::makeTypeFingerprint( $inputTypeObject->getSerialized() ); |
| 324 | if ( $inputTypeString !== null ) { |
| 325 | $relatedZObjects[] = (object)[ |
| 326 | 'zid' => $zid, |
| 327 | 'type' => ZTypeRegistry::Z_FUNCTION, |
| 328 | 'key' => ZTypeRegistry::Z_FUNCTION_ARGUMENTS, |
| 329 | 'related_zid' => $inputTypeString, |
| 330 | 'related_type' => ZTypeRegistry::Z_TYPE |
| 331 | ]; |
| 332 | } |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | // Key:Z8K2: Get output type |
| 337 | $outputType = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ); |
| 338 | $outputTypeString = ZObjectUtils::makeTypeFingerprint( $outputType->getSerialized() ); |
| 339 | if ( $outputTypeString !== null ) { |
| 340 | $relatedZObjects[] = (object)[ |
| 341 | 'zid' => $zid, |
| 342 | 'type' => ZTypeRegistry::Z_FUNCTION, |
| 343 | 'key' => ZTypeRegistry::Z_FUNCTION_RETURN_TYPE, |
| 344 | 'related_zid' => $outputTypeString, |
| 345 | 'related_type' => ZTypeRegistry::Z_TYPE |
| 346 | ]; |
| 347 | } |
| 348 | |
| 349 | // Key:Z8K3: Get tests |
| 350 | $tests = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_TESTERS ); |
| 351 | if ( $tests instanceof ZTypedList ) { |
| 352 | $testList = $tests->getAsArray(); |
| 353 | foreach ( $testList as $key => $test ) { |
| 354 | if ( $test instanceof ZReference && $test->isValid() ) { |
| 355 | $relatedZObjects[] = (object)[ |
| 356 | 'zid' => $zid, |
| 357 | 'type' => ZTypeRegistry::Z_FUNCTION, |
| 358 | 'key' => ZTypeRegistry::Z_FUNCTION_TESTERS, |
| 359 | 'related_zid' => $test->getZValue(), |
| 360 | 'related_type' => ZTypeRegistry::Z_TESTER |
| 361 | ]; |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | // Key:Z8K4: Get implementations |
| 367 | $implementations = $innerZObject->getValueByKey( ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS ); |
| 368 | if ( $implementations instanceof ZTypedList ) { |
| 369 | $implementationList = $implementations->getAsArray(); |
| 370 | foreach ( $implementationList as $key => $implementation ) { |
| 371 | if ( $implementation instanceof ZReference && $implementation->isValid() ) { |
| 372 | $relatedZObjects[] = (object)[ |
| 373 | 'zid' => $zid, |
| 374 | 'type' => ZTypeRegistry::Z_FUNCTION, |
| 375 | 'key' => ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS, |
| 376 | 'related_zid' => $implementation->getZValue(), |
| 377 | 'related_type' => ZTypeRegistry::Z_IMPLEMENTATION |
| 378 | ]; |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | return $relatedZObjects; |
| 384 | } |
| 385 | |
| 386 | /** |
| 387 | * Return all important relations between the given type and others. |
| 388 | * Currently returns: |
| 389 | * * key:Z4K5: Renderer function for the type |
| 390 | * * key:Z4K6: Parser function for the type |
| 391 | * |
| 392 | * @param string $zid |
| 393 | * @param ZType $innerZObject |
| 394 | * @return array Array of rows to insert in the join table |
| 395 | */ |
| 396 | private function getRelatedZObjectsOfType( $zid, $innerZObject ) { |
| 397 | $relatedZObjects = []; |
| 398 | |
| 399 | // Key:Z4K5: Get renderer function |
| 400 | $rendererFunction = $innerZObject->getRendererFunction(); |
| 401 | if ( $rendererFunction ) { |
| 402 | $relatedZObjects[] = (object)[ |
| 403 | 'zid' => $zid, |
| 404 | 'type' => ZTypeRegistry::Z_TYPE, |
| 405 | 'key' => ZTypeRegistry::Z_TYPE_RENDERER, |
| 406 | 'related_zid' => $rendererFunction, |
| 407 | 'related_type' => ZTypeRegistry::Z_FUNCTION |
| 408 | ]; |
| 409 | } |
| 410 | |
| 411 | // Key:Z4K6: Get parser function |
| 412 | $parserFunction = $innerZObject->getParserFunction(); |
| 413 | if ( $parserFunction ) { |
| 414 | $relatedZObjects[] = (object)[ |
| 415 | 'zid' => $zid, |
| 416 | 'type' => ZTypeRegistry::Z_TYPE, |
| 417 | 'key' => ZTypeRegistry::Z_TYPE_PARSER, |
| 418 | 'related_zid' => $parserFunction, |
| 419 | 'related_type' => ZTypeRegistry::Z_FUNCTION |
| 420 | ]; |
| 421 | } |
| 422 | |
| 423 | // Key:instanceofenum: Get all instances of enum type |
| 424 | if ( $innerZObject->isEnumType() ) { |
| 425 | // Gather all instances of this type, |
| 426 | // add them into the table |
| 427 | $instances = $this->zObjectStore->fetchZidsOfType( $zid ); |
| 428 | foreach ( $instances as $instance ) { |
| 429 | $relatedZObjects[] = (object)[ |
| 430 | 'zid' => $instance, |
| 431 | 'type' => $zid, |
| 432 | 'key' => self::INSTANCEOFENUM_DB_KEY, |
| 433 | 'related_zid' => $zid, |
| 434 | 'related_type' => ZTypeRegistry::Z_TYPE |
| 435 | ]; |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | return $relatedZObjects; |
| 440 | } |
| 441 | |
| 442 | /** |
| 443 | * Return all important relations between arbitrary objects. |
| 444 | * Currently returns: |
| 445 | * * key:instanceofenum: if the given object is an instance of an enum type. |
| 446 | * |
| 447 | * @param string $zid |
| 448 | * @param string $type |
| 449 | * @return array Array of rows to insert in the join table |
| 450 | */ |
| 451 | private function getRelatedZObjectsOfInstance( $zid, $type ) { |
| 452 | $relatedZObjects = []; |
| 453 | |
| 454 | $typeTitle = Title::newFromText( $type, NS_MAIN ); |
| 455 | $typeContent = $this->zObjectStore->fetchZObjectByTitle( $typeTitle ); |
| 456 | if ( !$typeContent ) { |
| 457 | // Error: type is not found, nothing we can do except log |
| 458 | $this->logger->warning( |
| 459 | __METHOD__ . ' failed to update relations for "' . $zid . '": type "' . $type . '" not found', |
| 460 | [ 'instance' => $zid, 'type' => $type ] |
| 461 | ); |
| 462 | return []; |
| 463 | } |
| 464 | |
| 465 | try { |
| 466 | $typeObject = $typeContent->getInnerZObject(); |
| 467 | } catch ( ZErrorException $e ) { |
| 468 | // Error: type is not valid, nothing we can do except log |
| 469 | $this->logger->warning( |
| 470 | __METHOD__ . ' failed to update relations for "' . $zid . '": type "' . $type . '" not valid', |
| 471 | [ 'instance' => $zid, 'type' => $type, 'responseError' => $e ] |
| 472 | ); |
| 473 | return []; |
| 474 | } |
| 475 | |
| 476 | // Key:instanceofenum: If object is an instance of an Enum type |
| 477 | if ( $typeObject instanceof ZType && $typeObject->isEnumType() ) { |
| 478 | $relatedZObjects[] = (object)[ |
| 479 | 'zid' => $zid, |
| 480 | 'type' => $type, |
| 481 | 'key' => self::INSTANCEOFENUM_DB_KEY, |
| 482 | 'related_zid' => $type, |
| 483 | 'related_type' => ZTypeRegistry::Z_TYPE |
| 484 | ]; |
| 485 | } |
| 486 | |
| 487 | return $relatedZObjects; |
| 488 | } |
| 489 | } |