Skip to content

Commit 797e92d

Browse files
committed
updated llms generate
Signed-off-by: bidi47 <bidi@apidemia.com>
1 parent 374c686 commit 797e92d

4 files changed

Lines changed: 111 additions & 45 deletions

File tree

‎public/md-articles/php-troubleshooting/fix-installing-pear-packages-with-php-7-2.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: "[FIX] Installing PEAR packages with PHP 7.2"
2+
title: "FIX: Installing PEAR packages with PHP 7.2"
33
description: "How to fix the 'Cannot use result of built-in function in write context' PEAR error on PHP 7.2 by patching Archive_Tar's func_get_args() call, and how to reinstall the affected packages afterward."
44
author: "Gabi DJ"
55
date_published: "2018-05-18"
@@ -8,7 +8,7 @@ category: "PHP Troubleshooting"
88
language: "en"
99
---
1010

11-
# [FIX] Installing PEAR packages with PHP 7.2
11+
# FIX: Installing PEAR packages with PHP 7.2
1212

1313
## TL;DR
1414

‎src/App/src/Fixture/articles_cleaned.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,7 @@
11691169
{
11701170
"post_title": "Zend Framework 1 End-of-Life",
11711171
"post_date": "2016-06-28 11:22:06",
1172-
"post_status": "archived",
1172+
"post_status": "published",
11731173
"author": {
11741174
"display_name": "arhimede",
11751175
"github": "arhimede"
@@ -1238,7 +1238,7 @@
12381238
{
12391239
"post_title": "Sunsetting PEAR Channel for Zend Framework 1",
12401240
"post_date": "2022-11-11 12:55:22",
1241-
"post_status": "archived",
1241+
"post_status": "published",
12421242
"author": {
12431243
"display_name": "arhimede",
12441244
"github": "arhimede"
@@ -1951,7 +1951,7 @@
19511951
]
19521952
},
19531953
{
1954-
"post_title": "[FIX] Installing PEAR packages with PHP 7.2",
1954+
"post_title": "FIX: Installing PEAR packages with PHP 7.2",
19551955
"post_date": "2018-05-18 11:19:49",
19561956
"post_status": "published",
19571957
"author": {

‎src/App/src/Service/LlmsGenerator.php‎

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use RuntimeException;
1010

1111
use function array_key_exists;
12+
use function array_merge;
1213
use function basename;
1314
use function count;
1415
use function explode;
@@ -28,16 +29,16 @@ class LlmsGenerator
2829
{
2930
/** @var list<non-empty-string> */
3031
private const CATEGORY_ORDER = [
31-
'dotkernel',
32-
'php-development',
33-
'dotkernel-api',
34-
'dotkernel3',
3532
'headless-platform',
36-
'middleware',
33+
'dotkernel-api',
3734
'architecture',
38-
'design-pattern',
3935
'how-to',
36+
'middleware',
4037
'best-practice',
38+
'design-pattern',
39+
'dotkernel3',
40+
'dotkernel',
41+
'php-development',
4142
];
4243

4344
/**
@@ -50,11 +51,28 @@ class LlmsGenerator
5051
'php-troubleshooting',
5152
'licensing',
5253
'phpstorm',
54+
'zend-framework',
55+
];
56+
57+
/**
58+
* Individual posts demoted to `## Optional`, keyed by category slug - for a single article
59+
* that doesn't warrant moving its whole category into `OPTIONAL_CATEGORIES`.
60+
*
61+
* @var array<non-empty-string, list<non-empty-string>>
62+
*/
63+
private const array OPTIONAL_POSTS = [
64+
'dotkernel' => [
65+
'commitment-to-php-new-zend-certified-engineers-zce-in-our-team',
66+
'adding-composer-support-in-your-dotkernel-project',
67+
'using-dotkernel-with-composer-dependencies',
68+
'forcing-utf8-connections-and-character-set-in-mysql',
69+
],
5370
];
5471

5572
/** @var array<non-empty-string, non-empty-string> */
5673
private const CATEGORY_BLURBS = [
57-
'dotkernel' => 'the core framework - releases, caching, sessions, auth, WURFL/device detection',
74+
'dotkernel' => 'the core framework - dot-* components (caching, logging, mail, dependency injection),'
75+
. ' Doctrine integration, and getting started with Dotkernel Light',
5876
'php-development' => 'general PHP tooling, environments, IDEs, security',
5977
'how-to' => 'practical guides - migrations, CORS, PSR-7, routing',
6078
'best-practice' => 'coding standards and database access patterns',
@@ -89,6 +107,15 @@ class LlmsGenerator
89107
*/
90108
private const string OSS_LIFECYCLE_SLUG = 'dotkernel-packages-oss-lifecycle';
91109

110+
/**
111+
* The Contact page has no `public/contact.md` counterpart to source a title/description
112+
* from, so it is hardcoded directly into `## Pages` instead.
113+
*/
114+
private const string CONTACT_TITLE = 'Contact';
115+
private const string CONTACT_PATH = 'contact/';
116+
private const string CONTACT_DESCRIPTION = 'Get in touch, report a security issue, or find where to ask a '
117+
. 'question and contribute to the project.';
118+
92119
public function __construct(
93120
private readonly PostRepository $postRepository,
94121
private readonly string $sourceDir,
@@ -108,16 +135,20 @@ public function write(): int
108135
{
109136
$postsByCategory = $this->groupPublishedPostsByCategory();
110137

111-
$sections = [];
138+
$sections = [];
139+
$optionalLines = [];
112140
foreach (self::CATEGORY_ORDER as $slug) {
113141
if (! isset($postsByCategory[$slug])) {
114142
continue;
115143
}
116-
$sections[] = $this->buildCategorySection($slug, $postsByCategory[$slug]);
144+
[$entries, $demoted] = $this->splitOptionalPosts($slug, $postsByCategory[$slug]);
145+
$optionalLines = array_merge($optionalLines, $demoted);
146+
if ($entries !== []) {
147+
$sections[] = $this->buildCategorySection($slug, $entries);
148+
}
117149
unset($postsByCategory[$slug]);
118150
}
119151

120-
$optionalLines = [];
121152
$optionalCategoryCount = 0;
122153
foreach (self::OPTIONAL_CATEGORIES as $slug) {
123154
if (! isset($postsByCategory[$slug])) {
@@ -132,7 +163,11 @@ public function write(): int
132163

133164
uasort($postsByCategory, static fn (array $a, array $b): int => count($b) - count($a));
134165
foreach ($postsByCategory as $slug => $posts) {
135-
$sections[] = $this->buildCategorySection($slug, $posts);
166+
[$entries, $demoted] = $this->splitOptionalPosts($slug, $posts);
167+
$optionalLines = array_merge($optionalLines, $demoted);
168+
if ($entries !== []) {
169+
$sections[] = $this->buildCategorySection($slug, $entries);
170+
}
136171
}
137172

138173
$written = $this->buildHeader()
@@ -174,17 +209,40 @@ private function groupPublishedPostsByCategory(): array
174209
return $byCategory;
175210
}
176211

212+
/**
213+
* @param list<array{post: Post, title: string, description: string}> $entries
214+
* @return array{0: list<array{post: Post, title: string, description: string}>, 1: list<string>}
215+
*/
216+
private function splitOptionalPosts(string $slug, array $entries): array
217+
{
218+
$optionalSlugs = self::OPTIONAL_POSTS[$slug] ?? [];
219+
if ($optionalSlugs === []) {
220+
return [$entries, []];
221+
}
222+
223+
$kept = [];
224+
$optional = [];
225+
foreach ($entries as $entry) {
226+
if (in_array($entry['post']->getSlug(), $optionalSlugs, true)) {
227+
$optional[] = $this->buildOptionalPostLink($slug, $entry);
228+
continue;
229+
}
230+
231+
$kept[] = $entry;
232+
}
233+
234+
return [$kept, $optional];
235+
}
236+
177237
/**
178238
* @param list<array{post: Post, title: string, description: string}> $entries
179239
*/
180240
private function buildCategorySection(string $slug, array $entries): string
181241
{
182242
$category = $entries[0]['post']->getCategory();
183243
$heading = sprintf(
184-
'## %s (%d post%s)',
185-
$category->getName(),
186-
count($entries),
187-
count($entries) === 1 ? '' : 's',
244+
'## %s',
245+
$category->getName()
188246
);
189247

190248
$lines = [$heading, ''];
@@ -256,7 +314,13 @@ private function buildPagesSection(): string
256314
return '';
257315
}
258316

259-
$pages = [];
317+
$pages = [
318+
[
319+
'title' => self::CONTACT_TITLE,
320+
'path' => self::CONTACT_PATH,
321+
'description' => self::CONTACT_DESCRIPTION,
322+
],
323+
];
260324
foreach (glob($this->pagesDir . '/*.md') ?: [] as $path) {
261325
$slug = basename($path, '.md');
262326
if ($slug === self::OSS_LIFECYCLE_SLUG || in_array($slug, self::DOCS_PAGES, true)) {
@@ -276,24 +340,20 @@ private function buildPagesSection(): string
276340

277341
$pages[] = [
278342
'title' => trim(explode('|', $title, 2)[0]),
279-
'slug' => $slug,
343+
'path' => $slug . '.md',
280344
'description' => $description,
281345
];
282346
}
283347

284-
if ($pages === []) {
285-
return '';
286-
}
287-
288348
usort($pages, static fn (array $a, array $b): int => strcasecmp($a['title'], $b['title']));
289349

290350
$lines = ['## Pages', ''];
291351
foreach ($pages as $page) {
292352
$lines[] = sprintf(
293-
'- [%s](%s/%s.md): %s',
353+
'- [%s](%s/%s): %s',
294354
$page['title'],
295355
$this->baseUrl,
296-
$page['slug'],
356+
$page['path'],
297357
$page['description'],
298358
);
299359
}
@@ -358,9 +418,6 @@ private function buildHeader(): string
358418
. 'by category and attributed to an author; URLs follow the pattern `/{category-slug}/{post-slug}/`. '
359419
. 'Each post also has a Markdown version at `/{category-slug}/{post-slug}.md`.';
360420

361-
$about = 'the team behind Dotkernel - how the team works, its commitment to open source and the PHP '
362-
. 'community, and how it uses AI under guardrails';
363-
364421
return "# {$this->title}\n\n"
365422
. $intro . "\n\n"
366423
. $body . "\n\n"

‎test/Unit/App/Service/LlmsGeneratorTest.php‎

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ public function testWriteOrdersCategorySectionsAccordingToTheCuratedOrder(): voi
117117
$this->createGenerator($posts)->write();
118118

119119
$output = $this->writtenOutput();
120-
$dotkernelAt = mb_strpos($output, '## Dotkernel (');
121-
$phpDevAt = mb_strpos($output, '## PHP Development (');
120+
$dotkernelAt = mb_strpos($output, '## Dotkernel');
121+
$phpDevAt = mb_strpos($output, '## PHP Development');
122122

123123
$this->assertNotFalse($dotkernelAt);
124124
$this->assertNotFalse($phpDevAt);
@@ -140,9 +140,9 @@ public function testWriteAppendsCategoriesNotInTheCuratedOrderAfterTheCuratedOne
140140
$this->createGenerator($posts)->write();
141141

142142
$output = $this->writtenOutput();
143-
$dotkernelAt = mb_strpos($output, '## Dotkernel (');
144-
$bigAt = mb_strpos($output, '## Extra Big (2 posts)');
145-
$smallAt = mb_strpos($output, '## Extra Small (1 post)');
143+
$dotkernelAt = mb_strpos($output, '## Dotkernel');
144+
$bigAt = mb_strpos($output, '## Extra Big');
145+
$smallAt = mb_strpos($output, '## Extra Small');
146146

147147
$this->assertNotFalse($dotkernelAt);
148148
$this->assertNotFalse($bigAt);
@@ -164,7 +164,7 @@ public function testWriteMovesAnOptionalCategoryPostToATrailingOptionalSectionWi
164164
$this->createGenerator($posts)->write();
165165

166166
$output = $this->writtenOutput();
167-
$dotkernelAt = mb_strpos($output, '## Dotkernel (');
167+
$dotkernelAt = mb_strpos($output, '## Dotkernel');
168168
$optionalAt = mb_strpos($output, '## Optional');
169169
$jsPostAt = mb_strpos($output, '[JS post]');
170170

@@ -254,7 +254,7 @@ public function testWriteIncludesTheBlurbLineForACuratedCategory(): void
254254
$this->createGenerator($posts)->write();
255255

256256
$this->assertStringContainsString(
257-
"## Dotkernel (1 post)\n\n*the core framework",
257+
"## Dotkernel\n\n*the core framework",
258258
$this->writtenOutput()
259259
);
260260
}
@@ -269,22 +269,24 @@ public function testWriteOmitsTheBlurbLineForAnUncuratedCategory(): void
269269
$this->createGenerator($posts)->write();
270270

271271
$this->assertStringContainsString(
272-
"## Unlisted (1 post)\n\n- [A post]",
272+
"## Unlisted\n\n- [A post]",
273273
$this->writtenOutput()
274274
);
275275
}
276276

277277
/**
278+
* Category headings no longer carry a post count, regardless of how many posts they hold.
279+
*
278280
* @throws Exception
279281
*/
280-
public function testWriteUsesSingularPostWordingForACategoryWithExactlyOnePost(): void
282+
public function testWriteCategoryHeadingHasNoPostCount(): void
281283
{
282284
$posts = [$this->createPost('A post', 'a-post', 'dotkernel', 'Dotkernel')];
283285

284286
$this->createGenerator($posts)->write();
285287

286-
$this->assertStringContainsString('## Dotkernel (1 post)', $this->writtenOutput());
287-
$this->assertStringNotContainsString('(1 posts)', $this->writtenOutput());
288+
$this->assertStringContainsString("## Dotkernel\n", $this->writtenOutput());
289+
$this->assertStringNotContainsString('## Dotkernel (', $this->writtenOutput());
288290
}
289291

290292
/**
@@ -360,13 +362,20 @@ public function testWriteOmitsThePagesSectionWhenNoPagesDirectoryIsConfigured():
360362
}
361363

362364
/**
365+
* The hardcoded Contact entry has no source file, so it still renders even when the
366+
* directory otherwise has nothing to glob - and nothing else does, in that case.
367+
*
363368
* @throws Exception
364369
*/
365-
public function testWriteOmitsThePagesSectionWhenThePagesDirectoryIsEmpty(): void
370+
public function testWritePagesSectionContainsOnlyContactWhenThePagesDirectoryIsEmpty(): void
366371
{
367372
$this->createGenerator()->write();
368373

369-
$this->assertStringNotContainsString('## Pages', $this->writtenOutput());
374+
$this->assertStringContainsString(
375+
"## Pages\n\n- [Contact](https://example.test/contact/): Get in touch, report a security issue, "
376+
. "or find where to ask a question and contribute to the project.\n\n",
377+
$this->writtenOutput()
378+
);
370379
}
371380

372381
/**
@@ -433,7 +442,7 @@ public function testWritePlacesThePagesSectionBetweenDocsAndTheFirstCategorySect
433442
$output = $this->writtenOutput();
434443
$docsAt = mb_strpos($output, '## Docs');
435444
$pagesAt = mb_strpos($output, '## Pages');
436-
$dotkernelAt = mb_strpos($output, '## Dotkernel (');
445+
$dotkernelAt = mb_strpos($output, '## Dotkernel');
437446

438447
$this->assertNotFalse($docsAt);
439448
$this->assertNotFalse($pagesAt);

0 commit comments

Comments
 (0)