1616use  eZ \Publish \SPI \Persistence \Content \Language \Handler  as  LanguageHandler ;
1717use  eZ \Publish \SPI \Persistence \Content \Relation ;
1818use  eZ \Publish \SPI \Persistence \Content \Relation \CreateStruct  as  RelationCreateStruct ;
19+ use  eZ \Publish \SPI \Persistence \Content \Type \Handler  as  ContentTypeHandler ;
1920use  eZ \Publish \SPI \Persistence \Content \VersionInfo ;
21+ use  Ibexa \Contracts \Core \Event \Mapper \ResolveMissingFieldEvent ;
22+ use  Symfony \Contracts \EventDispatcher \EventDispatcherInterface ;
2023
2124/** 
2225 * Mapper for Content Handler. 
2326 * 
2427 * Performs mapping of Content objects. 
28+  * 
29+  * @phpstan-type TVersionedLanguageFieldDefinitionsMap array< 
30+  *     int, array< 
31+  *         int, array< 
32+  *             string, array< 
33+  *                 int, \eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition, 
34+  *             > 
35+  *         > 
36+  *     > 
37+  * > 
38+  * @phpstan-type TVersionedFieldMap array< 
39+  *     int, array< 
40+  *         int, array< 
41+  *             int, \eZ\Publish\SPI\Persistence\Content\Field, 
42+  *         > 
43+  *     > 
44+  * > 
45+  * @phpstan-type TVersionedNameMap array< 
46+  *     int, array< 
47+  *         int, array< 
48+  *             string, array<int, string> 
49+  *         > 
50+  *     > 
51+  * > 
52+  * @phpstan-type TContentInfoMap array<int, \eZ\Publish\SPI\Persistence\Content\ContentInfo> 
53+  * @phpstan-type TVersionInfoMap array< 
54+  *     int, array< 
55+  *         int, \eZ\Publish\SPI\Persistence\Content\VersionInfo, 
56+  *     > 
57+  * > 
2558 */ 
2659class  Mapper
2760{
@@ -40,15 +73,25 @@ class Mapper
4073    protected  $ languageHandler
4174
4275    /** 
43-      * Creates a new mapper. 
44-      * 
45-      * @param \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry $converterRegistry 
46-      * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $languageHandler 
76+      * @var \eZ\Publish\SPI\Persistence\Content\Type\Handler 
4777     */ 
48-     public  function  __construct (Registry $ converterRegistryLanguageHandler $ languageHandler
49-     {
78+     private  $ contentTypeHandler
79+ 
80+     /** 
81+      * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface 
82+      */ 
83+     private  $ eventDispatcher
84+ 
85+     public  function  __construct (
86+         Registry $ converterRegistry
87+         LanguageHandler $ languageHandler
88+         ContentTypeHandler $ contentTypeHandler
89+         EventDispatcherInterface $ eventDispatcher
90+     ) {
5091        $ this converterRegistry  = $ converterRegistry
5192        $ this languageHandler  = $ languageHandler
93+         $ this contentTypeHandler  = $ contentTypeHandler
94+         $ this eventDispatcher  = $ eventDispatcher
5295    }
5396
5497    /** 
@@ -174,66 +217,166 @@ public function convertToStorageValue(Field $field)
174217     * 
175218     *      "$tableName_$columnName" 
176219     * 
177-      * @param array $rows 
178-      * @param array $nameRows 
220+      * @param array<array<string, scalar>> $rows 
221+      * @param array<array<string, scalar>> $nameRows 
222+      * @param string $prefix 
179223     * 
180224     * @return \eZ\Publish\SPI\Persistence\Content[] 
225+      * 
226+      * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException 
181227     */ 
182-     public  function  extractContentFromRows (array  $ rowsarray  $ nameRows$ prefix'ezcontentobject_ ' )
183-     {
228+     public  function  extractContentFromRows (
229+         array  $ rows
230+         array  $ nameRows
231+         string  $ prefix'ezcontentobject_ ' 
232+     ): array  {
184233        $ versionedNameData
234+ 
185235        foreach  ($ nameRowsas  $ row
186-             $ contentIdint )$ row'ezcontentobject_name_contentobject_id ' ];
187-             $ versionNoint )$ row'ezcontentobject_name_content_version ' ];
188-             $ versionedNameData$ contentId$ versionNo$ row'ezcontentobject_name_content_translation ' ]] = $ row'ezcontentobject_name_name ' ];
236+             $ contentIdint )$ row"{$ prefixname_contentobject_id " ];
237+             $ versionNoint )$ row"{$ prefixname_content_version " ];
238+             $ languageCode$ row"{$ prefixname_content_translation " ];
239+             $ versionedNameData$ contentId$ versionNo$ languageCode$ row"{$ prefixname_name " ];
189240        }
190241
191242        $ contentInfos
192243        $ versionInfos
193244        $ fields
194245
246+         $ fieldDefinitions$ this loadCachedVersionFieldDefinitionsPerLanguage (
247+             $ rows
248+             $ prefix
249+         );
250+ 
195251        foreach  ($ rowsas  $ row
196252            $ contentIdint )$ row"{$ prefixid " ];
253+             $ versionIdint )$ row"{$ prefixversion_id " ];
254+ 
197255            if  (!isset ($ contentInfos$ contentId
198256                $ contentInfos$ contentId$ this extractContentInfoFromRow ($ row$ prefix
199257            }
258+ 
200259            if  (!isset ($ versionInfos$ contentId
201260                $ versionInfos$ contentId
202261            }
203262
204-             $ versionIdint )$ row'ezcontentobject_version_id ' ];
205263            if  (!isset ($ versionInfos$ contentId$ versionId
206264                $ versionInfos$ contentId$ versionId$ this extractVersionInfoFromRow ($ row
207265            }
208266
209-             $ fieldIdint )$ row'ezcontentobject_attribute_id ' ];
210-             if  (!isset ($ fields$ contentId$ versionId$ fieldId
267+             $ fieldIdint )$ row"{$ prefixattribute_id " ];
268+             $ fieldDefinitionIdint )$ row"{$ prefixattribute_contentclassattribute_id " ];
269+             $ languageCode$ row"{$ prefixattribute_language_code " ];
270+ 
271+             if  (!isset ($ fields$ contentId$ versionId$ fieldId
272+                 && isset ($ fieldDefinitions$ contentId$ versionId$ languageCode$ fieldDefinitionId
273+             ) {
211274                $ fields$ contentId$ versionId$ fieldId$ this extractFieldFromRow ($ row
275+                 unset($ fieldDefinitions$ contentId$ versionId$ languageCode$ fieldDefinitionId
212276            }
213277        }
214278
279+         return  $ this buildContentObjects (
280+             $ contentInfos
281+             $ versionInfos
282+             $ fields
283+             $ fieldDefinitions
284+             $ versionedNameData
285+         );
286+     }
287+ 
288+     /** 
289+      * @phpstan-param TContentInfoMap $contentInfos 
290+      * @phpstan-param TVersionInfoMap $versionInfos 
291+      * @phpstan-param TVersionedFieldMap $fields 
292+      * @phpstan-param TVersionedLanguageFieldDefinitionsMap $missingFieldDefinitions 
293+      * @phpstan-param TVersionedNameMap $versionedNames 
294+      * 
295+      * @return \eZ\Publish\SPI\Persistence\Content[] 
296+      */ 
297+     private  function  buildContentObjects (
298+         array  $ contentInfos
299+         array  $ versionInfos
300+         array  $ fields
301+         array  $ missingFieldDefinitions
302+         array  $ versionedNames
303+     ): array  {
215304        $ results
305+ 
216306        foreach  ($ contentInfosas  $ contentId$ contentInfo
217307            foreach  ($ versionInfos$ contentIdas  $ versionId$ versionInfo
218308                // Fallback to just main language name if versioned name data is missing 
219-                 if  (isset ($ versionedNameData$ contentId$ versionInfoversionNo ])) {
220-                     $ names$ versionedNameData$ contentId$ versionInfoversionNo ];
221-                 } else  {
222-                     $ names$ contentInfomainLanguageCode  => $ contentInfoname ];
223-                 }
309+                 $ names$ versionedNames$ contentId$ versionInfoversionNo ]
310+                     ?? [$ contentInfomainLanguageCode  => $ contentInfoname ];
224311
225312                $ contentnew  Content ();
226313                $ contentversionInfo  = $ versionInfo
227314                $ contentversionInfo ->names  = $ names
228315                $ contentversionInfo ->contentInfo  = $ contentInfo
229316                $ contentfields  = array_values ($ fields$ contentId$ versionId
317+ 
318+                 $ missingVersionFieldDefinitions$ missingFieldDefinitions$ contentId$ versionId
319+                 foreach  ($ missingVersionFieldDefinitionsas  $ languageCode$ versionFieldDefinitions
320+                     foreach  ($ versionFieldDefinitionsas  $ fieldDefinition
321+                         $ event$ this eventDispatcher ->dispatch (
322+                             new  ResolveMissingFieldEvent (
323+                                 $ content
324+                                 $ fieldDefinition
325+                                 $ languageCode
326+                             )
327+                         );
328+ 
329+                         $ field$ eventgetField ();
330+                         if  ($ fieldnull ) {
331+                             $ contentfields [] = $ field
332+                         }
333+                     }
334+                 }
335+ 
230336                $ results$ content
231337            }
232338        }
233339
234340        return  $ results
235341    }
236342
343+     /** 
344+      * @phpstan-return TVersionedLanguageFieldDefinitionsMap 
345+      * 
346+      * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException 
347+      */ 
348+     private  function  loadCachedVersionFieldDefinitionsPerLanguage (
349+         array  $ rows
350+         string  $ prefix
351+     ): array  {
352+         $ fieldDefinitions
353+         $ contentTypes
354+         $ allLanguages$ this loadAllLanguagesWithIdKey ();
355+ 
356+         foreach  ($ rowsas  $ row
357+             $ contentIdint )$ row"{$ prefixid " ];
358+             $ versionIdint )$ row"{$ prefixversion_id " ];
359+             $ contentTypeIdint )$ row"{$ prefixcontentclass_id " ];
360+             $ languageMaskint )$ row"{$ prefixversion_language_mask " ];
361+ 
362+             if  (isset ($ fieldDefinitions$ contentId$ versionId
363+                 continue ;
364+             }
365+ 
366+             $ languageCodes$ this extractLanguageCodesFromMask ($ languageMask$ allLanguages
367+             $ contentTypes$ contentTypeId$ contentTypes$ contentTypeId$ this contentTypeHandler ->load ($ contentTypeId
368+             $ contentType$ contentTypes$ contentTypeId
369+             foreach  ($ contentTypefieldDefinitions  as  $ fieldDefinition
370+                 foreach  ($ languageCodesas  $ languageCode
371+                     $ id$ fieldDefinitionid ;
372+                     $ fieldDefinitions$ contentId$ versionId$ languageCode$ id$ fieldDefinition
373+                 }
374+             }
375+         }
376+ 
377+         return  $ fieldDefinitions
378+     }
379+ 
237380    /** 
238381     * Extracts a ContentInfo object from $row. 
239382     * 
@@ -251,7 +394,6 @@ public function extractContentInfoFromRow(array $row, $prefix = '', $treePrefix
251394        $ contentInfocontentTypeId  = (int )$ row"{$ prefixcontentclass_id " ];
252395        $ contentInfosectionId  = (int )$ row"{$ prefixsection_id " ];
253396        $ contentInfocurrentVersionNo  = (int )$ row"{$ prefixcurrent_version " ];
254-         $ contentInfoisPublished  = ($ row"{$ prefixstatus " ] == ContentInfo::STATUS_PUBLISHED );
255397        $ contentInfoownerId  = (int )$ row"{$ prefixowner_id " ];
256398        $ contentInfopublicationDate  = (int )$ row"{$ prefixpublished " ];
257399        $ contentInfomodificationDate  = (int )$ row"{$ prefixmodified " ];
0 commit comments