Skip to content

Commit

Permalink
Merge pull request #285 from hydephp/nested-pages
Browse files Browse the repository at this point in the history
Add support for nested source files hydephp/develop@15f9ee4
  • Loading branch information
github-actions committed Jul 29, 2022
1 parent 53854b5 commit bd019e0
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 73 deletions.
36 changes: 28 additions & 8 deletions src/Actions/CreatesNewPageSourceFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,30 @@ class CreatesNewPageSourceFile
public string $title;
public string $slug;
public string $outputPath;
public string $subDir = '';

public function __construct(string $title, string $type = MarkdownPage::class, public bool $force = false)
{
$this->title = $title;
$this->slug = Str::slug($title);
$this->title = $this->parseTitle($title);
$this->slug = $this->parseSlug($title);

$this->createPage($type);
}

public function parseTitle(string $title): string
{
return Str::afterLast($title, '/');
}

public function parseSlug(string $title): string
{
if (str_contains($title, '/')) {
$this->subDir = Str::beforeLast($title, '/').'/';
}

return Str::slug(basename($title));
}

public function canSaveFile(string $path): void
{
if (file_exists($path) && ! $this->force) {
Expand All @@ -41,19 +56,24 @@ public function canSaveFile(string $path): void

public function createPage(string $type): int|false
{
$subDir = $this->subDir;
if ($subDir !== '') {
$subDir = '/'.rtrim($subDir, '/\\');
}

if ($type === MarkdownPage::class) {
$this->needsDirectory(MarkdownPage::getSourceDirectory());
$this->needsDirectory(MarkdownPage::getSourceDirectory().$subDir);

return $this->createMarkdownFile();
}
if ($type === BladePage::class) {
$this->needsDirectory(BladePage::getSourceDirectory());
$this->needsDirectory(BladePage::getSourceDirectory().$subDir);

return $this->createBladeFile();
}

if ($type === DocumentationPage::class) {
$this->needsDirectory(DocumentationPage::getSourceDirectory());
$this->needsDirectory(DocumentationPage::getSourceDirectory().$subDir);

return $this->createDocumentationFile();
}
Expand All @@ -63,7 +83,7 @@ public function createPage(string $type): int|false

public function createMarkdownFile(): int|false
{
$this->outputPath = Hyde::path("_pages/$this->slug.md");
$this->outputPath = Hyde::path("_pages/$this->subDir$this->slug.md");

$this->canSaveFile($this->outputPath);

Expand All @@ -75,7 +95,7 @@ public function createMarkdownFile(): int|false

public function createBladeFile(): int|false
{
$this->outputPath = Hyde::path("_pages/$this->slug.blade.php");
$this->outputPath = Hyde::path("_pages/$this->subDir$this->slug.blade.php");

$this->canSaveFile($this->outputPath);

Expand All @@ -98,7 +118,7 @@ public function createBladeFile(): int|false

public function createDocumentationFile(): int|false
{
$this->outputPath = Hyde::path("_docs/$this->slug.md");
$this->outputPath = Hyde::path("_docs/$this->subDir$this->slug.md");

$this->canSaveFile($this->outputPath);

Expand Down
2 changes: 1 addition & 1 deletion src/Concerns/CanBeInNavigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function navigationMenuTitle(): string
return $this->title;
}

return Hyde::makeTitle($this->slug);
return Hyde::makeTitle(basename($this->slug));
}

/**
Expand Down
21 changes: 20 additions & 1 deletion src/Models/Pages/DocumentationPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,28 @@ class DocumentationPage extends AbstractMarkdownPage

public static string $parserClass = DocumentationPageParser::class;

public function __construct(array $matter = [], string $body = '', string $title = '', string $slug = '')
/**
* The sidebar category group, if any.
*/
public ?string $category;

/**
* The path to the page relative to the configured docs directory.
* Generally only needed if the page is in a subdirectory.
*/
public ?string $localPath;

public function __construct(array $matter = [], string $body = '', string $title = '', string $slug = '', ?string $category = null, ?string $localPath = null)
{
parent::__construct($matter, $body, $title, $slug);
$this->category = $category;
$this->localPath = $localPath;
}

/** @inheritDoc */
public function getSourcePath(): string
{
return is_null($this->localPath) ? parent::getSourcePath() : static::qualifyBasename($this->localPath);
}

/** @internal */
Expand Down
21 changes: 20 additions & 1 deletion src/Models/Parsers/DocumentationPageParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
use Hyde\Framework\Hyde;
use Hyde\Framework\Models\Pages\DocumentationPage;
use Hyde\Framework\Services\MarkdownFileService;
use Illuminate\Support\Str;

/**
* Parses a Markdown file in the configured docs directory into a DocumentationPage object.
*
* If the file is in a subdirectory relative to the base source directory (default _docs),
* the subdirectory name will be used as the page's category. This only works for one level,
* and the resulting file will still be put in the root of the docs output directory.
*/
class DocumentationPageParser extends AbstractPageParser
{
protected string $pageModel = DocumentationPage::class;
Expand All @@ -33,7 +41,18 @@ public function get(): DocumentationPage
matter: $this->matter,
body: $this->body,
title: $this->title,
slug: $this->slug
slug: basename($this->slug),
category: $this->getCategory(),
localPath: $this->slug
);
}

public function getCategory(): ?string
{
if (str_contains($this->slug, '/')) {
return Str::before($this->slug, '/');
}

return $this->matter['category'] ?? null;
}
}
6 changes: 6 additions & 0 deletions src/Models/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ public function getLink(): string
return Hyde::relativeLink($this->getOutputFilePath());
}

/** @todo add to contract */
public function getPermalink(): string
{
return Hyde::uriPath(Hyde::pageLink($this->getOutputFilePath()));
}

/** @inheritDoc */
public function __toString(): string
{
Expand Down
20 changes: 18 additions & 2 deletions src/Services/CollectionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,32 @@ public static function getSourceFileListForModel(string $model): array|false
return false;
}

// Scan the source directory, and directories therein, for files that match the model's file extension.

$files = [];
foreach (glob(Hyde::path($model::qualifyBasename('*'))) as $filepath) {
foreach (glob(Hyde::path($model::qualifyBasename('{*,**/*}')), GLOB_BRACE) as $filepath) {
if (! str_starts_with(basename($filepath), '_')) {
$files[] = basename($filepath, $model::getFileExtension());
$files[] = static::formatSlugForModel($model, $filepath);
}
}

return $files;
}

public static function formatSlugForModel(string $model, string $filepath): string
{
/** @var AbstractPage $model */
$slug = str_replace(Hyde::path($model::$sourceDirectory), '', $filepath);

if (str_ends_with($slug, $model::$fileExtension)) {
$slug = substr($slug, 0, -strlen($model::$fileExtension));
}

$slug = unslash($slug);

return $slug;
}

/**
* Get all the Blade files in the _pages directory.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Services/SitemapService.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function getXML(): string
public function addRoute(RouteContract $route): void
{
$urlItem = $this->xmlElement->addChild('url');
$urlItem->addChild('loc', htmlentities(Hyde::uriPath($route->getLink())));
$urlItem->addChild('loc', htmlentities($route->getPermalink()));
$urlItem->addChild('lastmod', htmlentities($this->getLastModDate($route->getSourceFilePath())));
$urlItem->addChild('changefreq', 'daily');
if (config('hyde.sitemap.dynamic_priority', true)) {
Expand Down
2 changes: 1 addition & 1 deletion src/StaticPageBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function __invoke()
view()->share('currentRoute', $this->page->getRoute());

$this->needsDirectory(static::$outputPath);
$this->needsDirectory(Hyde::getSiteOutputPath($this->page::getOutputDirectory()));
$this->needsDirectory(dirname(Hyde::getSiteOutputPath($this->page->getOutputPath())));

if ($this->page instanceof BladePage) {
return $this->save($this->compileView());
Expand Down
32 changes: 32 additions & 0 deletions tests/Feature/Actions/CreatesNewPageSourceFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ public function test_that_a_documentation_file_can_be_created_and_contains_expec
"# 682072b Test Page\n",
file_get_contents(Hyde::path('_docs/682072b-test-page.md'))
);

Hyde::unlink('_docs/682072b-test-page.md');
}

public function test_that_the_file_path_can_be_returned()
Expand All @@ -140,4 +142,34 @@ public function test_that_the_file_path_can_be_returned()
(new CreatesNewPageSourceFile('682072b Test Page', BladePage::class))->outputPath
);
}

public function test_parse_slug_returns_slug_generated_from_title()
{
$action = new CreatesNewPageSourceFile('Foo Bar');
$this->assertEquals('foo-bar', $action->parseSlug('Foo Bar'));
Hyde::unlink('_pages/foo-bar.md');
}

public function test_parse_slug_does_not_include_path_information()
{
$action = new CreatesNewPageSourceFile('Foo Bar');
$this->assertEquals('foo-bar', $action->parseSlug('/foo/bar/Foo Bar'));
Hyde::unlink('_pages/foo-bar.md');
}

public function test_parse_slug_sets_sub_dir_property_for_nested_pages()
{
$action = new CreatesNewPageSourceFile('foo');
$this->assertEquals('bar', $action->parseSlug('/foo/bar'));
$this->assertEquals('/foo/', $action->subDir);
Hyde::unlink('_pages/foo.md');
}

public function test_action_can_generate_nested_pages()
{
new CreatesNewPageSourceFile('foo/bar');
$this->assertFileExists(Hyde::path('_pages/foo/bar.md'));
Hyde::unlink('_pages/foo/bar.md');
rmdir(Hyde::path('_pages/foo'));
}
}
47 changes: 34 additions & 13 deletions tests/Feature/DocumentationPageParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@
use Hyde\Framework\Services\CollectionService;
use Hyde\Testing\TestCase;

/**
* @covers \Hyde\Framework\Models\Parsers\DocumentationPageParser
*/
class DocumentationPageParserTest extends TestCase
{
/**
* Test the Parser.
*/
public function test_can_parse_markdown_file()
{
file_put_contents(Hyde::path('_docs/test.md'), "# Title Heading \n\nMarkdown Content");
$page = (new DocumentationPageParser('test'))->get();
$this->assertInstanceOf(DocumentationPage::class, $page);
unlink(Hyde::path('_docs/test.md'));
}

public function test_can_get_collection_of_slugs()
{
$this->resetDocs();
Expand Down Expand Up @@ -55,23 +63,17 @@ public function test_parser_contains_body_text()
$this->assertEquals("# PHPUnit Test File \n Hello World!", $parser->body);
}

/**
* Test the Model.
*/
public function test_can_get_page_model_object(): DocumentationPage
public function test_can_get_page_model_object()
{
$parser = new DocumentationPageParser('phpunit-test');
$object = $parser->get();
$this->assertInstanceOf(DocumentationPage::class, $object);

return $object;
}

/**
* @depends test_can_get_page_model_object
*/
public function test_created_model_contains_expected_data(DocumentationPage $object)
public function test_created_model_contains_expected_data()
{
$parser = new DocumentationPageParser('phpunit-test');
$object = $parser->get();
$this->assertEquals('PHPUnit Test File', $object->title);
$this->assertEquals("# PHPUnit Test File \n Hello World!", $object->body);
$this->assertEquals('phpunit-test', $object->slug);
Expand All @@ -82,4 +84,23 @@ public function test_cleanup()
unlink(Hyde::path('_docs/phpunit-test.md'));
$this->assertTrue(true);
}

public function test_can_get_category_from_front_matter()
{
file_put_contents(Hyde::path('_docs/foo.md'), "---\ncategory: foo\n---\n");
$parser = new DocumentationPageParser('foo');
$this->assertEquals('foo', $parser->getCategory());
unlink(Hyde::path('_docs/foo.md'));
}

public function test_can_get_category_automatically_from_nested_page()
{
mkdir(Hyde::path('_docs/foo'));
touch(Hyde::path('_docs/foo/bar.md'));
$parser = new DocumentationPageParser('foo/bar');
$this->assertEquals('foo', $parser->getCategory());

unlink(Hyde::path('_docs/foo/bar.md'));
rmdir(Hyde::path('_docs/foo'));
}
}
7 changes: 4 additions & 3 deletions tests/Feature/Services/CollectionServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public function test_get_source_file_list_for_model_method_finds_customized_mode
DocumentationPage::class,
];

/** @var MarkdownPage $model */
foreach ($matrix as $model) {
// Setup
@mkdir(Hyde::path('foo'));
Expand All @@ -73,13 +74,13 @@ public function test_get_source_file_list_for_model_method_finds_customized_mode
// Set the source directory to a custom value
$model::$sourceDirectory = 'foo';

// Test customized
// Test customized source directory
$this->unitTestMarkdownBasedPageList($model, 'foo/foo.md');

// Set file extension to a custom value
$model::$fileExtension = 'foo';
$model::$fileExtension = '.foo';

// Test customized
// Test customized file extension
$this->unitTestMarkdownBasedPageList($model, 'foo/foo.foo', 'foo');

// Cleanup
Expand Down
Loading

0 comments on commit bd019e0

Please sign in to comment.