Skip to content

Commit

Permalink
sitemap validated
Browse files Browse the repository at this point in the history
  • Loading branch information
joshbruce committed Nov 9, 2021
1 parent 59a6290 commit 3121619
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
APP_ENV={production|local|test}
APP_URL={host with schema}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The content is also available in a [separate repository](https://github.com/josh
- [MAMP](https://www.mamp.info/en/mamp-pro/windows/),
- [XAMPP](https://www.apachefriends.org/download.html), or
- custom build.
3. Point the locally hosted domain to the `public` directory.
3. Point the locally hosted domain to the `site-dynamic-php` directory.

When you go to the locally hosted URL, it should throw a 500 server error. This is because you will need two things: the content folder and a `.env` file.

Expand Down
3 changes: 3 additions & 0 deletions content/public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
template: 'sitemap'
---
8 changes: 8 additions & 0 deletions src/Content/FrontMatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,12 @@ public function original(): string
}
return '';
}

public function template(): string
{
if ($this->hasMember('template')) {
return strval($this->frontMatter['template']);
}
return '';
}
}
5 changes: 5 additions & 0 deletions src/Content/Markdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ public function pageTitle(): string
return implode(' | ', $titles);
}

public function canonicalURl(): string
{
return $this->file->canonicalUrl();
}

private function fileContent(): string
{
if (strlen($this->fileContent) === 0 and $this->file->found()) {
Expand Down
41 changes: 41 additions & 0 deletions src/Documents/Sitemap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace JoshBruce\Site\Documents;

use Eightfold\XMLBuilder\Document;
use Eightfold\XMLBuilder\Element;

use JoshBruce\Site\FileSystem;
use JoshBruce\Site\File;

use JoshBruce\Site\Content\Markdown;

class Sitemap
{
public static function create(): string
{
$finder = FileSystem::finder()->name('content.md')->sortByName()
->notContains('redirect:')
->notContains('noindex:');

$markdown = [];
foreach ($finder as $file) {
$markdown[] = Markdown::for(
File::at($file->getPathname())
);
}

$urls = [];
foreach ($markdown as $m) {
$urls[] = Element::url(
Element::loc($m->canonicalUrl())
);
}

return Document::urlset(
...$urls
)->props("xmlns http://www.sitemaps.org/schemas/sitemap/0.9")->build();
}
}
18 changes: 13 additions & 5 deletions src/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

class File
{
private string $contentFileName = '/content.md';

public static function at(string $localPath): File
{
return new File($localPath);
Expand Down Expand Up @@ -66,15 +68,15 @@ public function path(bool $full = true): string

public function canGoUp(): bool
{
return $this->path(false) !== '/content.md';
return $this->path(false) !== $this->contentFileName;
}

public function up(): File
{
$parts = explode('/', $this->localPath);
$parts = array_slice($parts, 0, -2); // remove file name and one folder.
$localPath = implode('/', $parts);
return File::at($localPath . '/content.md');
return File::at($localPath . $this->contentFileName);
}

public function contents(): string
Expand All @@ -97,7 +99,8 @@ public function mimetype(): string
$extensionMap = [
'md' => 'text/html',
'css' => 'text/css',
'js' => 'text/javascript'
'js' => 'text/javascript',
'xml' => 'application/xml'
];

$parts = explode('.', $this->path());
Expand All @@ -108,12 +111,17 @@ public function mimetype(): string
return $type;
}

public function canonicalUrl(): string
{
return str_replace($this->contentFileName, '', 'https://joshbruce.com' . $this->path(false));
}

/**
* @return File[]
*/
public function children(string $filesNamed): array
{
$base = str_replace('/content.md', '', $this->path());
$base = str_replace($this->contentFileName, '', $this->path());

$files = [];
foreach (new DirectoryIterator($base) as $folder) {
Expand All @@ -134,6 +142,6 @@ public function children(string $filesNamed): array

private function contentRoot(): string
{
return FileSystem::contentRoot() . '/public';
return FileSystem::publicRoot();
}
}
38 changes: 38 additions & 0 deletions src/FileSystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@

namespace JoshBruce\Site;

use SplFileInfo;

use Symfony\Component\Finder\Finder;

class FileSystem
{
public static function publicRoot(): string
{
return FileSystem::contentRoot() . '/public';
}

public static function contentRoot(): string
{
$parts = explode('/', self::projectRoot());
Expand All @@ -24,4 +33,33 @@ public static function projectRoot(): string
$parts = array_slice($parts, 0, -1);
return implode('/', $parts);
}

public static function finder(): Finder
{
$finder = new Finder();
return $finder->ignoreVCS(false)
->ignoreUnreadableDirs()
->ignoreDotFiles(false)
->ignoreVCSIgnored(true)
->files()
->filter(fn($f) => self::isPublished($f))
->in(self::publicRoot());
}

private static function isPublished(SplFileInfo $finderFile): bool
{
return ! self::isDraft($finderFile);
}

private static function isDraft(SplFileInfo $finderFile): bool
{
$filePath = (string) $finderFile;
$relativePath = self::relativePath($filePath);
return str_contains($relativePath, '_');
}

private static function relativePath(string $path): string
{
return str_replace(self::contentRoot(), '', $path);
}
}
18 changes: 18 additions & 0 deletions src/HttpRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ public function isFile(): bool
return str_contains($this->possibleFileName(), '.');
}

public function isSitemap(): bool
{
return $this->isFile() and $this->possibleFileName() === 'sitemap.xml';
}

public function isNotSitemap(): bool
{
return ! $this->isSitemap();
}

public function localFile(): File
{
return File::at(localPath: $this->localPath());
Expand All @@ -82,6 +92,14 @@ private function localPath(): string
$relativePath = $this->uriPath();
if (empty($possibleFileName)) {
$relativePath = $this->uriPath() . '/content.md';

// } elseif (str_contains($relativePath, '.xml')) {
// $relativePath = str_replace('.xml', '.md', $relativePath);

}

if (! str_starts_with($relativePath, '/')) {
$relativePath = "/{$relativePath}";
}

$root = FileSystem::contentRoot();
Expand Down
22 changes: 19 additions & 3 deletions src/HttpResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

use JoshBruce\Site\PageComponents\Navigation;

use JoshBruce\Site\Documents\Sitemap;

class HttpResponse
{
private ResponseInterface $psrResponse;
Expand Down Expand Up @@ -69,7 +71,11 @@ public function headers(): array
public function body(): string
{
$localFile = $this->request->localFile();
if ($this->statusCode() === 200 and $localFile->isNotMarkdown()) {
if (
$this->statusCode() === 200 and
$localFile->isNotMarkdown() and
$this->request->isNotSitemap($localFile)
) {
return $localFile->path();

} elseif ($this->statusCode() === 404) {
Expand All @@ -82,15 +88,22 @@ public function body(): string

}

$html = '';
$template = '';
$pageTitle = '';
$html = '';
if ($localFile->isMarkdown()) {
$markdown = Markdown::for(file: $localFile);
$template = $markdown->frontMatter()->template();
$pageTitle = $markdown->pageTitle();
$html = $markdown->html();

}

if ($this->request->isSitemap()) {
return Sitemap::create();

}

return Document::create(
$pageTitle
)->head(
Expand Down Expand Up @@ -153,7 +166,10 @@ public function psrResponse(): ResponseInterface
$psr17Factory = new PsrFactory();
$body = $this->body();
$stream = $psr17Factory->createStream($body);
if ($this->request->isFile()) {
if (
$this->request->isFile() and
$this->request->isNotSitemap()
) {
$stream = $psr17Factory->createStreamFromFile($body);
}

Expand Down
20 changes: 19 additions & 1 deletion src/ServerGlobals.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ private function __construct()
{
}


public function appEnvIsNot(string $value): bool
{
return $this->appEnv() !== $value;
Expand All @@ -26,6 +25,20 @@ public function isMissingAppEnv(): bool
return ! $this->hasAppEnv();
}

public function isMissingAppUrl(): bool
{
return ! $this->hasAppUrl();
}

public function appUrl(): string
{
if ($this->hasAppUrl()) {
$globals = $this->globals();
return strval($globals['APP_URL']);
}
return '';
}

private function appEnv(): string
{
if ($this->hasAppEnv()) {
Expand All @@ -40,6 +53,11 @@ private function hasAppEnv(): bool
return array_key_exists('APP_ENV', $this->globals());
}

private function hasAppUrl(): bool
{
return array_key_exists('APP_URL', $this->globals());
}

/**
* @return array<string, int|string>
*/
Expand Down
34 changes: 34 additions & 0 deletions tests/FileTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

use JoshBruce\Site\File;

use JoshBruce\Site\FileSystem;

test('can generate canonical URL', function() {
expect(
File::at(FileSystem::publicRoot() . '/content.md')->canonicalUrl()
)->toBe(
'https://joshbruce.com'
);

expect(
File::at(FileSystem::publicRoot())->canonicalUrl()
)->toBe(
'https://joshbruce.com'
);

expect(
File::at(FileSystem::publicRoot() . '/web-development')->canonicalUrl()
)->toBe(
'https://joshbruce.com/web-development'
);

expect(
File::at(FileSystem::publicRoot() . '/web-development/content.md')
->canonicalUrl()
)->toBe(
'https://joshbruce.com/web-development'
);
})->group('file');
2 changes: 1 addition & 1 deletion tests/IndexTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@
'Okay to fail in local.'
)->toBeFalse();
}
})->group('index', 'focus');
})->group('index');
Loading

0 comments on commit 3121619

Please sign in to comment.