1
+ <?php
2
+
3
+ /***********
4
+ *
5
+ * Source Text Library
6
+ * https://developers.urbanmonastic.org/
7
+ *
8
+ * © Paul Prins
9
+ * https://paulprins.net https://paul.build/
10
+ *
11
+ * Licensed under MIT - For full license, view the LICENSE distributed with this source.
12
+ *
13
+ ***********/
14
+
15
+ namespace UrbanMonastics \SourceTextLibrary \Controllers ;
16
+
17
+ use UrbanMonastics \SourceTextLibrary \SourceTextLibrary as SourceTextLibrary ;
18
+
19
+ class Index{
20
+ // Manage the location, and loading of the various files from the location
21
+ protected $ VersionFolders = array (); // Which folder abbreviations do we have
22
+ protected $ PathContents = array ();
23
+ protected $ index ;
24
+
25
+ /* -- Reference to Parent -- */
26
+ private $ SourceTextLibrary ;
27
+ private $ ActiveVersion ;
28
+
29
+ function __construct ( SourceTextLibrary &$ SourceTextLibrary ){
30
+ $ this ->SourceTextLibrary = $ SourceTextLibrary ;
31
+ }
32
+
33
+
34
+ public function getIssues (){
35
+ if ( !is_array ( $ this ->index ) || !array_key_exists ( 'Issues ' , $ this ->index ) )
36
+ return array ("There is no index " );
37
+
38
+ return $ this ->index ['Issues ' ];
39
+ }
40
+
41
+
42
+ public function loadLibrary ( string $ libraryPath ){
43
+ if ( !is_string ( $ libraryPath ) || is_null ( $ libraryPath ) || !file_exists ( $ libraryPath ) ){
44
+ throw new \Exception ('loadLibrary - Supplied path is not a valid library location ' );
45
+ }
46
+
47
+ if ( is_null ( $ this ->index ) ){
48
+ $ this ->index = array ();
49
+ $ this ->index ['Version ' ] = SourceTextLibrary::version;
50
+ $ this ->index ['Sources ' ] = array ();
51
+ // ['Abbreviation'] = array('Path' => PathToSourceDirectory, 'Abbreviation', 'Title', 'Type' => null, 'SecondaryType' => null, 'Segments' => , 'Verses', '' )
52
+ $ this ->index ['SourceVersions ' ] = array ();
53
+ $ this ->index ['Issues ' ] = array (); // Just a list of issues
54
+ }
55
+
56
+
57
+ $ libraryPath = rtrim ( $ libraryPath , '/ ' ) . '/ ' ;
58
+
59
+ $ LibraryLevel = scandir ( $ libraryPath );
60
+ foreach ( $ LibraryLevel as $ TextAbbrv ){
61
+ $ TextPath = $ libraryPath . $ TextAbbrv . '/ ' ;
62
+
63
+ if ( !is_dir ( $ TextPath ) || in_array ($ TextAbbrv , array ('. ' , '.. ' , '.DS_Store ' ) ) ){
64
+ continue ;
65
+ }
66
+
67
+ // Check and ensure that this directory has a source.json file (or that one already has been indexed).
68
+ if ( !file_exists ( $ TextPath . 'source.json ' ) && !array_key_exists ( $ TextAbbrv , $ this ->index ['Sources ' ] ) ){
69
+ throw new \Exception ('loadLibrary - Directory is missing the required source.json file: ' . $ TextPath );
70
+ }
71
+
72
+
73
+ if ( file_exists ( $ TextPath . 'source.json ' ) ){
74
+ $ ThisSource = $ this ->SourceTextLibrary ->_loadJson ( $ TextPath . 'source.json ' );
75
+
76
+ if ( empty ( $ ThisSource ) ){
77
+ throw new \Exception ('loadLibrary - Malformed source file found at: \'' . $ TextPath . 'source.json \'' );
78
+ }
79
+
80
+ if ( $ TextAbbrv != $ ThisSource ['Abbreviation ' ] ){
81
+ $ this ->index ['Issues ' ][] = "Mismatched abbreviations between folder name and source.json: " . $ TextPath ;
82
+ }
83
+
84
+
85
+
86
+ $ this ->index ['Sources ' ][$ TextAbbrv ] = array ('Path ' => $ TextPath ,
87
+ 'SourcePath ' => $ TextPath . 'source.json ' ,
88
+ 'Abbreviation ' => $ TextAbbrv ,
89
+ 'Title ' => array (),
90
+ 'Type ' => null ,
91
+ 'SecondaryType ' => null ,
92
+ 'Segments ' => 'None ' ,
93
+ 'Verses ' => false ,
94
+ 'SegmentTitles ' => false ,
95
+ 'Versions ' => array (),
96
+ 'VerseCounts ' => NULL );
97
+
98
+ if ( array_key_exists ( 'Title ' , $ ThisSource ) ){
99
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Title ' ] = (array ) $ ThisSource ['Title ' ];
100
+ }else {
101
+ $ this ->index ['Issues ' ][] = "Source is missing its Title definition: " . $ TextPath . "source.json " ;
102
+ }
103
+
104
+
105
+ $ allowedSourceTypes = $ this ->SourceTextLibrary ->getAllowedSourceTypes ();
106
+ $ allowedSourceSegments = $ this ->SourceTextLibrary ->getAllowedSourceSegments ();
107
+ if ( array_key_exists ( 'Type ' , $ ThisSource ) && in_array ( $ ThisSource ['Type ' ], $ allowedSourceTypes ) ){
108
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Type ' ] = (string ) $ ThisSource ['Type ' ];
109
+ }else {
110
+ $ this ->index ['Issues ' ][] = "Source has an invalid Type definition: " . $ TextPath . "source.json " ;
111
+ }
112
+
113
+ if ( array_key_exists ( 'SecondaryType ' , $ ThisSource ) && !is_null ( $ ThisSource ['SecondaryType ' ] ) ){
114
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['SecondaryType ' ] = (string ) $ ThisSource ['SecondaryType ' ];
115
+ }
116
+
117
+ if ( array_key_exists ( 'Segments ' , $ ThisSource ) && in_array ( $ ThisSource ['Segments ' ], $ allowedSourceSegments ) ){
118
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Segments ' ] = (string ) $ ThisSource ['Segments ' ];
119
+ }else {
120
+ $ this ->index ['Issues ' ][] = "Source has an invalid Segments definition: " . $ TextPath . "source.json " ;
121
+ }
122
+
123
+
124
+ if ( array_key_exists ( 'Verses ' , $ ThisSource ) ){
125
+ if ( is_bool ( $ ThisSource ['Verses ' ] ) ){
126
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Verses ' ] = (bool ) $ ThisSource ['Verses ' ];
127
+
128
+ if ( $ ThisSource ['Verses ' ] ){
129
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ] = array ();
130
+ }
131
+ }else {
132
+ $ this ->index ['Issues ' ][] = "Source has an invalid Verses definition: " . $ TextPath . "source.json " ;
133
+ }
134
+ }
135
+
136
+ if ( array_key_exists ( 'SegmentTitles ' , $ ThisSource ) ){
137
+ if ( is_bool ( $ ThisSource ['SegmentTitles ' ] ) ){
138
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['SegmentTitles ' ] = (bool ) $ ThisSource ['SegmentTitles ' ];
139
+ }else {
140
+ $ this ->index ['Issues ' ][] = "Source has an invalid SegmentTitles definition: " . $ TextPath . "source.json " ;
141
+ }
142
+ }
143
+ }
144
+
145
+
146
+
147
+
148
+ //
149
+ //
150
+ // Lets index the version directories
151
+ $ TextLevel = scandir ( $ TextPath );
152
+ foreach ( $ TextLevel as $ VersionAbbrv ){
153
+ $ VersionPath = $ TextPath . $ VersionAbbrv . '/ ' ;
154
+ if ( !is_dir ( $ VersionPath ) || in_array ($ VersionAbbrv , array ('. ' , '.. ' , '.DS_Store ' ) ) ){
155
+ continue ;
156
+ }
157
+
158
+ if ( !$ this ->SourceTextLibrary ->checkVersion ( $ VersionAbbrv ) ){
159
+ $ Issue = "Unknown version found when scanning directories: " . $ VersionAbbrv ;
160
+ if ( !in_array ( $ Issue , $ this ->index ['Issues ' ] ) ){
161
+ $ this ->index ['Issues ' ][] = $ Issue ;
162
+ }
163
+ continue ; // This version isn't registered, so lets skip it
164
+ }
165
+
166
+
167
+ if ( !array_key_exists ($ VersionAbbrv , $ this ->index ['SourceVersions ' ] ) ){
168
+ $ this ->index ['SourceVersions ' ][$ VersionAbbrv ] = array ();
169
+ }
170
+
171
+ if ( !in_array ($ TextAbbrv , $ this ->index ['SourceVersions ' ][$ VersionAbbrv ] ) ){
172
+ $ this ->index ['SourceVersions ' ][$ VersionAbbrv ][] = $ TextAbbrv ;
173
+ }
174
+
175
+ $ this ->index ['SourceVersions ' ][$ VersionAbbrv ][] = $ TextAbbrv ;
176
+
177
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ] = array ('Path ' => $ VersionPath ,
178
+ 'Text ' => NULL ,
179
+ 'Chapters ' => NULL ,
180
+ 'Abbreviations ' => NULL );
181
+ switch ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Segments ' ] ){
182
+ case 'None ' :
183
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Text ' ] = array ();
184
+ break ;
185
+ case 'Chapters ' :
186
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Chapters ' ] = array ();
187
+ break ;
188
+ case 'Abbreviations ' :
189
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Abbreviations ' ] = array ();
190
+ break ;
191
+ }
192
+
193
+
194
+ // Sort the Array to ensure it is nicer to read
195
+ ksort ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ] );
196
+
197
+
198
+
199
+ $ VersionLevel = scandir ( $ VersionPath );
200
+ foreach ( $ VersionLevel as $ FileName ){
201
+ $ FilePath = $ VersionPath . $ FileName ;
202
+ if ( !is_file ( $ FilePath ) || in_array ( $ FileName , array ('. ' , '.. ' , '.DS_Store ' , '_template.json ' ) ) ){
203
+ continue ;
204
+ }
205
+
206
+ // Load the file contents
207
+ $ FileContents = $ this ->SourceTextLibrary ->_loadJson ( $ FilePath );
208
+ if ( !is_array ( $ FileContents ) ){
209
+ $ this ->index ['Issues ' ][] = "Text file is not valid JSON and cannot be loaded: " . $ FilePath ;
210
+ continue ;
211
+ }
212
+
213
+
214
+ //
215
+ // Lets check for some common issues
216
+ if ( !array_key_exists ( 'TextAbbreviation ' , $ FileContents ) ){
217
+ $ this ->index ['Issues ' ][] = "Text file does not have a TextAbbreviation value: " . $ FilePath ;
218
+ }else if ( $ FileContents ['TextAbbreviation ' ] !== str_replace ('.json ' , '' , $ FileName ) ){
219
+ $ this ->index ['Issues ' ][] = "Text file value for TextAbbreviation does not match the filename: ' " . $ FileContents ['TextAbbreviation ' ] . "' should match ' " . str_replace ('.json ' , '' , $ FileName ) . "': " . $ FilePath ;
220
+ }
221
+
222
+ if ( !array_key_exists ( 'SourceAbbreviation ' , $ FileContents ) ){
223
+ $ this ->index ['Issues ' ][] = "Text file does not have a SourceAbbreviation value: " . $ FilePath ;
224
+ }else if ( $ TextAbbrv !== $ FileContents ['SourceAbbreviation ' ] ){
225
+ $ this ->index ['Issues ' ][] = "Text file value for SourceAbbreviation does not match the parent directory: ' " . $ FileContents ['SourceAbbreviation ' ] . "' should match ' " . $ TextAbbrv . "': " . $ FilePath ;
226
+
227
+ }
228
+
229
+ if ( $ this ->index ['Sources ' ][$ TextAbbrv ]['SegmentTitles ' ] == false && !empty ( $ FileContents ['Title ' ] ) ){
230
+ $ this ->index ['Issues ' ][] = "Text file has a Title value when the source does not support this: " . $ FilePath ;
231
+ }
232
+ // Lets check for some common issues
233
+ //
234
+
235
+
236
+
237
+ $ TextIndex = array ('TextAbbreviation ' => $ FileContents ['TextAbbreviation ' ],
238
+ 'FilePath ' => $ FilePath ,
239
+ 'HasContent ' => false );
240
+
241
+
242
+
243
+ // Check if it is stored in Text or Verses
244
+ $ TheseVerses = NULL ;
245
+ $ TextIndex ['Verses ' ] = NULL ;
246
+ if ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Verses ' ] ){
247
+ if ( array_key_exists ('Verses ' , $ FileContents ) ){
248
+ $ TextIndex ['Verses ' ] = array ();
249
+ foreach ( $ FileContents ['Verses ' ] as $ v => $ c ){
250
+ if ( strlen ( trim ( $ c ) ) > 0 )
251
+ $ TextIndex ['Verses ' ][] = (int ) $ v ; // Only list non-empty verses
252
+ }
253
+
254
+ $ Max = 0 ;
255
+ if ( !empty ( $ TextIndex ['Verses ' ] ) ){
256
+ $ Max = max ( $ TextIndex ['Verses ' ] );
257
+ }
258
+
259
+ if ( !array_key_exists ( $ FileContents ['TextAbbreviation ' ], $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ] ) || $ Max > $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ][$ FileContents ['TextAbbreviation ' ]] ){
260
+ if ( !empty ( $ TextIndex ['Verses ' ] ) ){
261
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ][$ FileContents ['TextAbbreviation ' ]] = max ( $ TextIndex ['Verses ' ] );
262
+ }else {
263
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ][$ FileContents ['TextAbbreviation ' ]] = 0 ;
264
+ }
265
+ }
266
+
267
+ ksort ( $ this ->index ['Sources ' ][$ TextAbbrv ]['VerseCounts ' ] );
268
+ }
269
+
270
+ if ( !empty ( $ TextIndex ['Verses ' ] ) )
271
+ $ TextIndex ['HasContent ' ] = true ;
272
+ }else {
273
+ if ( !empty ( $ FileContents ['Text ' ] ) )
274
+ $ TextIndex ['HasContent ' ] = true ;
275
+ }
276
+
277
+
278
+ switch ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Segments ' ] ){
279
+ case 'None ' :
280
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Text ' ] = $ TextIndex ;
281
+ break ;
282
+
283
+ case 'Chapters ' :
284
+ $ ChapterNumber = ltrim ( str_ireplace ( array ('chapter- ' , '.json ' ), array ('' , '' ), $ FileName ), '0 ' );
285
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Chapters ' ][$ ChapterNumber ] = $ TextIndex ;
286
+
287
+ ksort ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Chapters ' ] );
288
+ break ;
289
+
290
+ case 'Abbreviations ' :
291
+ $ ThisAbbrv = str_ireplace ( '.json ' , '' , $ FileName );
292
+ $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Abbreviations ' ][$ ThisAbbrv ] = $ TextIndex ;
293
+
294
+ ksort ( $ this ->index ['Sources ' ][$ TextAbbrv ]['Versions ' ][$ VersionAbbrv ]['Abbreviations ' ] );
295
+ break ;
296
+ }
297
+ }
298
+
299
+
300
+ }
301
+ // Lets index the version directories
302
+
303
+
304
+
305
+ }
306
+
307
+
308
+ //
309
+ // Lets do some quick source checking
310
+ foreach ( $ this ->index as $ TextAbrv => $ Source ){
311
+ // if( ){
312
+ // $this->index['Issues'][] = "Text file has a Title value when the source does not support this: " . $FilePath;
313
+ // }
314
+ }
315
+
316
+
317
+
318
+ var_dump ( $ this ->index ['Issues ' ] );
319
+ return $ this ;
320
+ }
321
+
322
+ public function exportIndex (){
323
+ $ tmp = $ this ->index ;
324
+ $ tmp ['VerificationKey ' ] = md5 ( json_encode ( $ this ->index , JSON_UNESCAPED_UNICODE ) );
325
+
326
+ return $ tmp ;
327
+ }
328
+ public function importIndex ( array $ ExportedIndex ){
329
+ //
330
+ // First Check - ensure that the Version numbers match
331
+ if ( !array_key_exists ('Version ' , $ ExportedIndex ) || $ ExportedIndex ['Version ' ] != SourceTextLibrary::version ){
332
+ throw new \Exception ('Unable to import the Source Text index. The Version value does not match the library, or is missing ' );
333
+ }
334
+ // First Check - Passed
335
+ //
336
+
337
+ //
338
+ // Second Check - ensure that the MD5 Hash sum matches
339
+ if ( !array_key_exists ('VerificationKey ' , $ ExportedIndex ) ){
340
+ throw new \Exception ('Unable to import the Source Text index. The VerificationKey is missing from the index. ' );
341
+ }
342
+
343
+ $ VerificationKey = $ ExportedIndex ['VerificationKey ' ];
344
+ unset($ ExportedIndex ['VerificationKey ' ] );
345
+ if ( $ VerificationKey !== md5 ( json_encode ( $ ExportedIndex , JSON_UNESCAPED_UNICODE ) )){
346
+ throw new \Exception ('Unable to import the Source Text index. The VerificationKey does not match the supplied index. ' );
347
+ }
348
+ // Second Check - Passed
349
+ //
350
+
351
+
352
+ $ this ->index = $ ExportedIndex ;
353
+
354
+ var_dump ("It was verified " );
355
+ return true ;
356
+ }
357
+
358
+
359
+ public function clear (){
360
+
361
+ return $ this ;
362
+ }
363
+ }
0 commit comments