3131use App \Models \ToolHasTag ;
3232use App \Models \ToolHasTypeCategory ;
3333use App \Models \TypeCategory ;
34+ use App \Services \DatasetService ;
35+ use App \Services \Gwdm \GwdmHandlerFactory ;
3436use ElasticClientController as ECC ;
3537
3638trait IndexElastic
@@ -43,6 +45,59 @@ trait IndexElastic
4345 private $ publications = [];
4446 private $ collections = [];
4547
48+ /**
49+ * Single named resolution point for DatasetService within this trait.
50+ *
51+ * Constructor injection isn't viable here: IndexElastic is a trait consumed
52+ * by ~20 unrelated controllers/jobs/observers, so there is no single
53+ * constructor to inject into without a much larger refactor.
54+ */
55+ private function datasetService (): DatasetService
56+ {
57+ return app (DatasetService::class);
58+ }
59+
60+ /**
61+ * Reconstruct the full GWDM envelope for a dataset's latest version.
62+ *
63+ * DatasetVersion->metadata cannot be read directly for indexing: delta rows
64+ * store an empty metadata blob, and GWDM 3.0 rows omit the `metadata` key
65+ * entirely (their data lives in dedicated SQL tables). Funnelling through
66+ * DatasetService::getReconstructedMetadataEnvelope() yields a complete
67+ * {gwdmVersion, metadata, original_metadata} envelope for every schema
68+ * version and every snapshot/delta storage shape. Validation is skipped —
69+ * data is validated at write time.
70+ *
71+ * @return array The reconstructed envelope, or [] when the dataset has no versions.
72+ */
73+ private function reconstructedLatestEnvelope (Dataset $ dataset ): array
74+ {
75+ $ version = $ dataset ->latestVersion ();
76+
77+ if (!$ version ) {
78+ return [];
79+ }
80+
81+ return $ this ->datasetService ()->getReconstructedMetadataEnvelope (
82+ $ dataset ->id ,
83+ $ version ->version ,
84+ false ,
85+ $ version ,
86+ );
87+ }
88+
89+ // Whether this envelope's GWDM version should be indexed into Elasticsearch.
90+ private function isElasticIndexable (array $ envelope ): bool
91+ {
92+ $ version = $ envelope ['gwdmVersion ' ] ?? null ;
93+
94+ if ($ version === null ) {
95+ return true ; // no version info available — preserve current behaviour
96+ }
97+
98+ return app (GwdmHandlerFactory::class)->resolve ($ version )->supportsElasticIndexing ();
99+ }
100+
46101 /**
47102 * Calls a re-indexing of Elastic search when a dataset is created, updated or added to a collection.
48103 *
@@ -71,7 +126,14 @@ public function reindexElastic(string $datasetId, bool $returnParams = false, bo
71126 // throw new \Exception("Error: DatasetVersion is missing for dataset ID=$datasetId.");
72127 }
73128
74- $ metadata = $ datasetMatch ->latestVersion ()->metadata ;
129+ $ metadata = $ this ->reconstructedLatestEnvelope ($ datasetMatch );
130+
131+ if (!$ this ->isElasticIndexable ($ metadata )) {
132+ $ this ->deleteDatasetFromElastic ($ datasetId );
133+ return null ;
134+ }
135+
136+ $ latestVersion = $ datasetMatch ->latestVersion ();
75137
76138 // inject relationships via Local functions
77139 $ materialTypes = $ this ->getMaterialTypes ($ metadata );
@@ -82,8 +144,10 @@ public function reindexElastic(string $datasetId, bool $returnParams = false, bo
82144 'abstract ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.abstract ' ], '' ),
83145 'keywords ' => $ this ->normalizeDelimitedList ($ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.keywords ' ], '' )),
84146 'description ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.description ' ], '' ),
85- 'shortTitle ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.shortTitle ' ], '' ),
86- 'title ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.title ' ], '' ),
147+ // short_title/title are populated columns on every write (see DatasetVersion);
148+ // only fall back to the envelope for legacy pre-migration rows where they're null.
149+ 'shortTitle ' => $ latestVersion ->short_title ?? $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.shortTitle ' ], '' ),
150+ 'title ' => $ latestVersion ->title ?? $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.title ' ], '' ),
87151 'populationSize ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.populationSize ' ], -1 ),
88152 'publisherName ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.publisher.name ' , 'metadata.summary.publisher.publisherName ' ], '' ),
89153 'startDate ' => $ this ->getValueByPossibleKeys ($ metadata , ['metadata.provenance.temporal.startDate ' ], null ),
@@ -288,13 +352,16 @@ public function reindexElasticDataProvider(string $teamId, bool $returnParams =
288352
289353 $ latestVersion = $ dataset ->latestVersion ();
290354 if ($ latestVersion ) {
291- $ datasetVersionIds [] = $ latestVersion ->id ;
292- $ metadata = $ latestVersion ->metadata ;
293- $ datasetTitles [] = $ metadata ['metadata ' ]['summary ' ]['shortTitle ' ];
294- $ types = explode (';,; ' , $ metadata ['metadata ' ]['summary ' ]['datasetType ' ]);
295- foreach ($ types as $ t ) {
296- if (!in_array ($ t , $ dataTypes )) {
297- $ dataTypes [] = $ t ;
355+ $ metadata = $ this ->reconstructedLatestEnvelope ($ dataset );
356+
357+ if ($ this ->isElasticIndexable ($ metadata )) {
358+ $ datasetVersionIds [] = $ latestVersion ->id ;
359+ $ datasetTitles [] = $ latestVersion ->short_title ?? $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.shortTitle ' ], '' );
360+ $ types = $ this ->normalizeDelimitedList ($ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.datasetType ' ], '' ));
361+ foreach ($ types as $ t ) {
362+ if (!in_array ($ t , $ dataTypes )) {
363+ $ dataTypes [] = $ t ;
364+ }
298365 }
299366 }
300367 }
@@ -460,12 +527,19 @@ public function indexElasticCollections(int $collectionId, bool $returnParams =
460527 $ datasetTitles = array ();
461528 $ datasetAbstracts = array ();
462529 foreach ($ datasetIds as $ d ) {
463- $ metadata = Dataset::where (['id ' => $ d ])
464- ->first ()
465- ->latestVersion ()
466- ->metadata ;
467- $ datasetTitles [] = $ metadata ['metadata ' ]['summary ' ]['shortTitle ' ];
468- $ datasetAbstracts [] = $ metadata ['metadata ' ]['summary ' ]['abstract ' ];
530+ $ datasetRow = Dataset::where (['id ' => $ d ])->first ();
531+ $ latestVersion = $ datasetRow ?->latestVersion();
532+ if (!$ latestVersion ) {
533+ continue ;
534+ }
535+
536+ $ metadata = $ this ->reconstructedLatestEnvelope ($ datasetRow );
537+ if (!$ this ->isElasticIndexable ($ metadata )) {
538+ continue ;
539+ }
540+
541+ $ datasetTitles [] = $ latestVersion ->short_title ?? $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.shortTitle ' ], '' );
542+ $ datasetAbstracts [] = $ this ->getValueByPossibleKeys ($ metadata , ['metadata.summary.abstract ' ], '' );
469543 }
470544
471545 $ keywords = array ();
@@ -535,8 +609,7 @@ private function indexElasticDataProviderColl(int $id): void
535609
536610 foreach ($ datasets as $ dataset ) {
537611 $ dataset ->setAttribute ('spatialCoverage ' , $ dataset ->allSpatialCoverages ?? []);
538- $ metadata = $ dataset ['versions ' ][0 ];
539- $ datasetTitles [] = $ metadata ['metadata ' ]['metadata ' ]['summary ' ]['shortTitle ' ];
612+ $ datasetTitles [] = $ dataset ->latestVersion ()?->short_title ?? '' ;
540613 foreach ($ dataset ['spatialCoverage ' ] as $ loc ) {
541614 if (!in_array ($ loc ['region ' ], $ locations )) {
542615 $ locations [] = $ loc ['region ' ];
@@ -598,11 +671,7 @@ public function indexElasticDur(string $id, bool $returnParams = false): null|ar
598671
599672 $ datasetTitles = array ();
600673 foreach ($ datasetIds as $ d ) {
601- $ metadata = Dataset::where (['id ' => $ d ])
602- ->first ()
603- ->latestVersion ()
604- ->metadata ;
605- $ datasetTitles [] = $ metadata ['metadata ' ]['summary ' ]['shortTitle ' ];
674+ $ datasetTitles [] = Dataset::where (['id ' => $ d ])->first ()->latestVersion ()->short_title ?? '' ;
606675 }
607676
608677 $ keywords = array ();
@@ -698,9 +767,10 @@ public function indexElasticPublication(string $id, bool $returnParams = false):
698767 ];
699768
700769 foreach ($ datasets as $ dataset ) {
701- $ metadata = Dataset::where (['id ' => $ dataset ['id ' ]])->first ()->latestVersion ()->metadata ;
702- $ latestVersionID = Dataset::where (['id ' => $ dataset ['id ' ]])->first ()->latestVersion ()->id ;
703- $ datasetTitles [] = $ metadata ['metadata ' ]['summary ' ]['shortTitle ' ];
770+ $ datasetModel = Dataset::where (['id ' => $ dataset ['id ' ]])->first ();
771+ $ latestVersion = $ datasetModel ->latestVersion ();
772+ $ latestVersionID = $ latestVersion ->id ;
773+ $ datasetTitles [] = $ latestVersion ->short_title ?? '' ;
704774
705775 // change from 'UNKNOWN' to 'USING' - temp
706776 $ linkType = PublicationHasDatasetVersion::where ([
@@ -838,8 +908,7 @@ public function indexElasticTools(int $toolId, bool $returnParams = false): null
838908 $ datasetTitles [] = '_Can be used with any dataset ' ;
839909 } else {
840910 foreach ($ datasets as $ dataset ) {
841- $ dataset_version = $ dataset ['versions ' ][0 ];
842- $ datasetTitles [] = $ dataset_version ['metadata ' ]['metadata ' ]['summary ' ]['shortTitle ' ];
911+ $ datasetTitles [] = $ dataset ->latestVersion ()?->short_title ?? '' ;
843912 }
844913 usort ($ datasetTitles , 'strcasecmp ' );
845914 }
@@ -971,7 +1040,10 @@ public function deleteDataProviderCollFromElastic(string $id)
9711040 public function getMaterialTypes (array $ metadata ): array |null
9721041 {
9731042 $ materialTypes = null ;
974- if (version_compare (Config::get ('metadata.GWDM.version ' ), "2.0 " , "< " )) {
1043+ // Check the reconstructed envelope's own gwdmVersion, not the global config
1044+ // default — a dataset's actual version can diverge from that default.
1045+ $ rowGwdmVersion = $ metadata ['gwdmVersion ' ] ?? Config::get ('metadata.GWDM.version ' );
1046+ if (version_compare ($ rowGwdmVersion , "2.0 " , "< " )) {
9751047 $ containsTissue = !empty ($ this ->getValueByPossibleKeys ($ metadata , [
9761048 'metadata.coverage.biologicalsamples ' ,
9771049 'metadata.coverage.physicalSampleAvailability ' ,
@@ -1110,16 +1182,12 @@ public function checkingDataset(int $datasetId)
11101182 $ publicationIds = array_column ($ dataset ->allActivePublications , 'id ' ) ?? [];
11111183 $ toolIds = array_column ($ dataset ->allActiveTools , 'id ' ) ?? [];
11121184
1113- $ version = $ dataset ->latestVersion ();
1114- $ withLinks = DatasetVersion::where ('id ' , $ version ['id ' ])
1115- ->with (['linkedDatasetVersions ' ])
1116- ->first ();
1117-
1118- $ dataset ->setAttribute ('versions ' , [$ withLinks ]);
1119-
1120- $ metadataSummary = $ dataset ['versions ' ][0 ]['metadata ' ]['metadata ' ]['summary ' ] ?? [];
1185+ $ metadataSummary = $ this ->reconstructedLatestEnvelope ($ dataset )['metadata ' ]['summary ' ] ?? [];
11211186
1122- $ title = $ this ->getValueByPossibleKeys ($ metadataSummary , ['title ' ], '' );
1187+ // title/short_title are populated columns on every write; only fall back
1188+ // to the reconstructed envelope for legacy pre-migration rows.
1189+ $ title = $ dataset ->latestVersion ()?->title
1190+ ?? $ this ->getValueByPossibleKeys ($ metadataSummary , ['title ' ], '' );
11231191 $ populationSize = $ this ->getValueByPossibleKeys ($ metadataSummary , ['populationSize ' ], -1 );
11241192 $ datasetType = $ this ->getValueByPossibleKeys ($ metadataSummary , ['datasetType ' ], '' );
11251193
0 commit comments