3
3
namespace App ;
4
4
5
5
use App \Models \Document ;
6
+ use App \Models \DocumentationSection ;
6
7
use Exception ;
8
+ use Illuminate \Support \Arr ;
7
9
use Illuminate \Support \Collection ;
8
10
use Illuminate \Support \Facades \Cache ;
9
11
use Illuminate \Support \Facades \Http ;
@@ -44,11 +46,6 @@ class Docs
44
46
*/
45
47
protected array $ variables = [];
46
48
47
- /**
48
- * @var string The content of the Markdown file.
49
- */
50
- protected $ content ;
51
-
52
49
/**
53
50
* @var string The file name.
54
51
*/
@@ -67,75 +64,82 @@ class Docs
67
64
*/
68
65
public function __construct (string $ version , string $ file )
69
66
{
70
- $ this ->file = $ file. '.md ' ;
67
+ $ this ->file = $ file . '.md ' ;
71
68
$ this ->version = $ version ;
72
69
$ this ->path = "/ $ version/ $ this ->file " ;
73
-
74
- $ this ->content ();
75
70
}
76
71
77
72
/**
78
- * @return array
73
+ * @return string|null
79
74
*/
80
- public function variables (): array
75
+ public function raw ()
81
76
{
82
- return $ this ->variables ;
77
+ return once (function () {
78
+ $ raw = Storage::disk ('docs ' )->get ($ this ->path );
79
+
80
+ // Abort the request if the page doesn't exist
81
+ abort_if (
82
+ $ raw === null ,
83
+ redirect (status: 300 )->route ('docs ' , ['version ' => $ this ->version , 'page ' => 'installation ' ])
84
+ );
85
+
86
+ return $ raw ;
87
+ });
83
88
}
84
89
85
90
/**
86
- * @return string|null
91
+ * @param string|null $key
92
+ *
93
+ * @return array
87
94
*/
88
- public function content ( ): ? string
95
+ public function variables ( string $ key = null ): array
89
96
{
90
- if ($ this ->content !== null ) {
91
- return $ this ->content ;
92
- }
97
+ return once (function () use ($ key ) {
93
98
94
- $ raw = Cache:: remember ( ' doc-file- ' . $ this ->path , now ()-> addMinutes ( 30 ), fn () => Storage:: disk ( ' docs ' )-> get ( $ this -> path ) );
99
+ $ variables = Str:: of ( $ this ->raw ())-> betweenFirst ( ' --- ' , ' --- ' );
95
100
96
- // Abort the request if the page doesn't exist
97
- abort_if (
98
- $ raw === null && Document::where ('file ' , $ this ->file )->exists (),
99
- redirect (status: 300 )->route ('docs ' , ['version ' => $ this ->version , 'page ' => 'installation ' ])
100
- );
101
+ try {
102
+ $ this ->variables = Yaml::parse ($ variables );
103
+ } catch (\Throwable ) {
101
104
102
- $ variables = Str::of ($ raw )
103
- ->after ('--- ' )
104
- ->before ('--- ' );
105
-
106
- try {
107
- $ this ->variables = Yaml::parse ($ variables );
108
- } catch (\Throwable ) {
109
-
110
- }
105
+ }
111
106
112
- $ this ->content = Str::of ($ raw )
113
- ->replace ('{{version}} ' , $ this ->version )
114
- ->after ('--- ' )
115
- ->after ('--- ' )
116
- ->markdown ();
107
+ return Arr::get ($ this ->variables , $ key );
108
+ });
109
+ }
117
110
118
- return $ this ->content ;
111
+ /**
112
+ * @return string|null
113
+ */
114
+ public function content (): ?string
115
+ {
116
+ return once (function () {
117
+ return Str::of ($ this ->raw ())
118
+ ->replace ('{{version}} ' , $ this ->version )
119
+ ->after ('--- ' )
120
+ ->after ('--- ' )
121
+ ->markdown ();
122
+ });
119
123
}
120
124
121
125
/**
122
126
* Get the rendered view of a documentation page.
123
127
*
124
128
* @param string $view The view name.
125
129
*
130
+ * @return \Illuminate\Contracts\View\View The rendered view of the documentation page.
126
131
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
127
132
*
128
- * @return \Illuminate\Contracts\View\View The rendered view of the documentation page.
129
133
*/
130
134
public function view (string $ view )
131
135
{
132
- $ all = collect ()->merge ($ this ->variables )->merge ([
136
+ $ data = Cache:: remember ( ' doc-file-view-data ' . $ this -> path , now ()-> addMinutes ( 30 ), fn () => collect ()->merge ($ this ->variables () )->merge ([
133
137
'docs ' => $ this ,
134
138
'content ' => $ this ->content (),
135
139
'edit ' => $ this ->getEditUrl (),
136
- ]);
140
+ ])) ;
137
141
138
- return view ($ view , $ all );
142
+ return view ($ view , $ data );
139
143
}
140
144
141
145
/**
@@ -145,8 +149,8 @@ public function view(string $view)
145
149
*/
146
150
public function getMenu (): array
147
151
{
148
- return Cache::remember ('doc-navigation- ' . $ this ->version , now ()->addHours (2 ), function () {
149
- $ page = Storage::disk ('docs ' )->get ($ this ->version . '/documentation.md ' );
152
+ return Cache::remember ('doc-navigation- ' . $ this ->version , now ()->addHours (2 ), function () {
153
+ $ page = Storage::disk ('docs ' )->get ($ this ->version . '/documentation.md ' );
150
154
151
155
$ html = Str::of ($ page )
152
156
->after ('--- ' )
@@ -191,7 +195,7 @@ public function docsToArray(string $html): array
191
195
$ menu = [];
192
196
193
197
$ crawler ->filter ('ul > li ' )->each (function (Crawler $ node ) use (&$ menu ) {
194
- $ subList = $ node ->filter ('ul > li ' )->each (fn (Crawler $ subNode ) => [
198
+ $ subList = $ node ->filter ('ul > li ' )->each (fn (Crawler $ subNode ) => [
195
199
'title ' => $ subNode ->filter ('a ' )->text (),
196
200
'href ' => url ($ subNode ->filter ('a ' )->attr ('href ' )),
197
201
]);
@@ -221,10 +225,10 @@ public static function every(string $version): Collection
221
225
$ files = Storage::disk ('docs ' )->allFiles ($ version );
222
226
223
227
return collect ($ files )
224
- ->filter (fn (string $ path ) => Str::of ($ path )->endsWith ('.md ' ))
225
- ->filter (fn (string $ path ) => ! Str::of ($ path )->endsWith (['readme.md ' , 'license.md ' ]))
226
- ->map (fn (string $ path ) => Str::of ($ path )->after ($ version. '/ ' )->before ('.md ' ))
227
- ->map (fn (string $ path ) => new static ($ version , $ path ));
228
+ ->filter (fn (string $ path ) => Str::of ($ path )->endsWith ('.md ' ))
229
+ ->filter (fn (string $ path ) => !Str::of ($ path )->endsWith (['readme.md ' , 'license.md ' ]))
230
+ ->map (fn (string $ path ) => Str::of ($ path )->after ($ version . '/ ' )->before ('.md ' ))
231
+ ->map (fn (string $ path ) => new static ($ version , $ path ));
228
232
}
229
233
230
234
/**
@@ -234,18 +238,18 @@ public static function every(string $version): Collection
234
238
*/
235
239
public function fetchBehind (): int
236
240
{
237
- throw_unless (isset ( $ this ->variables [ 'git ' ]) , new Exception ("The document {$ this ->path } is missing a Git hash " ));
241
+ throw_unless ($ this ->variables ( 'git ' ) === null , new Exception ("The document {$ this ->path } is missing a Git hash " ));
238
242
239
243
$ response = $ this ->fetchGitHubDiff ();
240
244
241
245
return $ response
242
- ->takeUntil (fn ($ commit ) => $ commit ['sha ' ] === $ this ->variables [ 'git ' ] )
246
+ ->takeUntil (fn ($ commit ) => $ commit ['sha ' ] === $ this ->variables ( 'git ' ) )
243
247
->count ();
244
248
}
245
249
246
250
public function fetchLastCommit (): string
247
251
{
248
- throw_unless (isset ( $ this ->variables [ 'git ' ]) , new Exception ("The document {$ this ->path } is missing a Git hash " ));
252
+ throw_unless ($ this ->variables ( 'git ' ) === null , new Exception ("The document {$ this ->path } is missing a Git hash " ));
249
253
250
254
$ response = $ this ->fetchGitHubDiff ();
251
255
@@ -263,7 +267,7 @@ private function fetchGitHubDiff(?string $key = null): Collection
263
267
264
268
return Cache::remember ("docs-diff- $ this ->version - $ this ->file - $ hash " ,
265
269
now ()->addHours (2 ),
266
- fn () => Http::withBasicAuth ('token ' , config ('services.github.token ' ))
270
+ fn () => Http::withBasicAuth ('token ' , config ('services.github.token ' ))
267
271
->get ("https://api.github.com/repos/laravel/docs/commits?sha= {$ this ->version }&path= {$ this ->file }" )
268
272
->collect ($ key )
269
273
);
@@ -349,7 +353,57 @@ public function update()
349
353
$ this ->getModel ()->fill ([
350
354
'behind ' => $ this ->fetchBehind (),
351
355
'last_commit ' => $ this ->fetchLastCommit (),
352
- 'current_commit ' => $ this ->variables [ 'git ' ] ,
356
+ 'current_commit ' => $ this ->variables ( 'git ' ) ,
353
357
])->save ();
358
+
359
+ $ this ->updateSections ();
360
+ }
361
+
362
+ /**
363
+ * Разбивает markdown файл на разделы по заголовкам.
364
+ *
365
+ * @return Массив разделов с заголовками и содержимым
366
+ */
367
+ public function getSections ()
368
+ {
369
+ // Разбиваем HTML содержимое на разделы по заголовкам
370
+ preg_match_all ('/<h(\d)>(.+)<\/h\d>(.*)/sU ' , $ this ->content (), $ matches , PREG_SET_ORDER );
371
+
372
+ // Массив для хранения разделов
373
+ $ sections = collect ();
374
+ $ prevEnd = 0 ;
375
+
376
+ foreach ($ matches as $ index => $ match ) {
377
+ $ sectionTitle = $ match [2 ];
378
+
379
+ // Получаем начальную и конечную позицию текущего заголовка в тексте
380
+ $ startPos = strpos ($ this ->content (), $ match [0 ], $ prevEnd );
381
+
382
+ // Получаем текст между текущим и предыдущим заголовком
383
+ if ($ index > 0 ) {
384
+ $ prevMatch = $ matches [$ index - 1 ];
385
+ $ prevEnd = strpos ($ this ->content (), $ prevMatch [0 ]) + strlen ($ prevMatch [0 ]);
386
+ $ sectionContent = substr ($ this ->content (), $ prevEnd , $ startPos - $ prevEnd );
387
+ } else {
388
+ $ sectionContent = substr ($ this ->content (), 0 , $ startPos );
389
+ }
390
+
391
+ $ sections ->push ([
392
+ 'title ' => $ sectionTitle ,
393
+ 'slug ' => Str::of ($ sectionTitle )->slug ()->toString (),
394
+ 'content ' => $ sectionContent ,
395
+ 'file ' => $ this ->file ,
396
+ 'version ' => $ this ->version ,
397
+ 'id ' => Str::uuid (),
398
+ ]);
399
+ }
400
+
401
+ return $ sections ;
402
+ }
403
+
404
+ public function updateSections ()
405
+ {
406
+ //DocumentationSection::where('file', $this->file)->where('version', $this->version)->delete();
407
+ //DocumentationSection::insert($this->getSections()->toArray());
354
408
}
355
409
}
0 commit comments