Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve behaviour when a site URL is not explicitly set #1726

Merged
merged 16 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/framework/src/Foundation/Kernel/Hyperlinks.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ public function asset(string $name, bool $preferQualifiedUrl = false): string
*/
public function hasSiteUrl(): bool
{
return ! blank(Config::getNullableString('hyde.url'));
$value = Config::getNullableString('hyde.url');

return ! blank($value) && $value !== 'http://localhost';
}

/**
Expand All @@ -147,6 +149,13 @@ public function url(string $path = ''): string
return rtrim(rtrim(Config::getString('hyde.url'), '/')."/$path", '/');
}

// Since v1.7.0, we return the relative path even if the base URL is not set,
// as this is more likely to be the desired behavior the user's expecting.
if (! blank($path)) {
return $path;
}

// User is trying to get the base URL, but it's not set
throw new BaseUrlNotSetException();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might consider this for deprecation

}

Expand Down
14 changes: 13 additions & 1 deletion packages/framework/tests/Feature/Foundation/HyperlinksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public function testAssetHelperResolvesPathsForNestedPages()

public function testAssetHelperReturnsQualifiedAbsoluteUriWhenRequestedAndSiteHasBaseUrl()
{
$this->assertSame('http://localhost/media/test.jpg', $this->class->asset('test.jpg', true));
config(['hyde.url' => 'https://example.org']);
$this->assertSame('https://example.org/media/test.jpg', $this->class->asset('test.jpg', true));
}

public function testAssetHelperReturnsDefaultRelativePathWhenQualifiedAbsoluteUriIsRequestedButSiteHasNoBaseUrl()
Expand All @@ -65,11 +66,22 @@ public function testAssetHelperReturnsDefaultRelativePathWhenQualifiedAbsoluteUr
$this->assertSame('media/test.jpg', $this->class->asset('test.jpg', true));
}

public function testAssetHelperReturnsDefaultRelativePathWhenQualifiedAbsoluteUriIsRequestedButSiteBaseUrlIsLocalhost()
{
$this->assertSame('media/test.jpg', $this->class->asset('test.jpg', true));
}

public function testAssetHelperReturnsInputWhenQualifiedAbsoluteUriIsRequestedButImageIsAlreadyQualified()
{
$this->assertSame('http://localhost/media/test.jpg', $this->class->asset('http://localhost/media/test.jpg', true));
}

public function testAssetHelperReturnsInputWhenQualifiedAbsoluteUriIsRequestedButImageIsAlreadyQualifiedRegardlessOfMatchingTheConfiguredUrl()
{
config(['hyde.url' => 'https://example.org']);
$this->assertSame('http://localhost/media/test.jpg', $this->class->asset('http://localhost/media/test.jpg', true));
}

public function testAssetHelperUsesConfiguredMediaDirectory()
{
Hyde::setMediaDirectory('_assets');
Expand Down
42 changes: 39 additions & 3 deletions packages/framework/tests/Feature/HelpersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,14 @@ public function testAssetFunction()
public function testAssetFunctionWithQualifiedUrl()
{
$this->assertSame(Hyde::asset('foo', true), asset('foo', true));
$this->assertSame('http://localhost/media/foo', asset('foo', true));
$this->assertSame('media/foo', asset('foo', true));
}

/** @covers ::asset */
public function testAssetFunctionWithQualifiedUrlAndSetBaseUrl()
{
$this->app['config']->set(['hyde.url' => 'https://example.com']);
$this->assertSame('https://example.com/media/foo', asset('foo', true));
}

/** @covers ::asset */
Expand All @@ -94,6 +101,13 @@ public function testAssetFunctionWithQualifiedUrlAndNoBaseUrl()
$this->assertSame('media/foo', asset('foo', true));
}

/** @covers ::asset */
public function testAssetFunctionWithQualifiedUrlAndLocalhostBaseUrl()
{
$this->app['config']->set(['hyde.url' => 'http://localhost']);
$this->assertSame('media/foo', asset('foo', true));
}

/** @covers ::asset */
public function testAssetFunctionFromNestedPage()
{
Expand Down Expand Up @@ -145,17 +159,39 @@ public function testUrlFunction()

/** @covers ::url */
public function testUrlFunctionWithBaseUrl()
{
$this->app['config']->set(['hyde.url' => 'https://example.com']);
$this->assertSame('https://example.com/foo', url('foo'));
}

/** @covers ::url */
public function testUrlFunctionWithLocalhostBaseUrl()
{
$this->app['config']->set(['hyde.url' => 'http://localhost']);
$this->assertSame('http://localhost/foo', url('foo'));
$this->assertSame('foo', url('foo'));
}

/** @covers ::url */
public function testUrlFunctionWithoutBaseUrl()
{
$this->app['config']->set(['hyde.url' => null]);
$this->assertSame('foo', url('foo'));
}

/** @covers ::url */
public function testUrlFunctionWithoutBaseUrlOrPath()
{
$this->app['config']->set(['hyde.url' => null]);
$this->expectException(\Hyde\Framework\Exceptions\BaseUrlNotSetException::class);
$this->assertNull(url());
}

/** @covers ::url */
public function testUrlFunctionWithLocalhostBaseUrlButNoPath()
{
$this->app['config']->set(['hyde.url' => 'http://localhost']);
$this->expectException(\Hyde\Framework\Exceptions\BaseUrlNotSetException::class);
$this->assertNull(url('foo'));
$this->assertNull(url());
}

/** @covers ::url */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Feature;

use Hyde\Hyde;
use Hyde\Testing\TestCase;
use Hyde\Pages\MarkdownPage;
use Hyde\Pages\MarkdownPost;
use Hyde\Pages\DocumentationPage;

/**
* High level test to ensure that sites without a base URL are handled gracefully.
*
* For example: In case a user forgot to set a base URL, we don't want their site
* to have localhost links in the compiled HTML output since that would break
* things when deployed to production. So we fall back to relative links.
*
* Some things like sitemaps and RSS feeds cannot be generated without a base URL,
* as their schemas generally do not allow relative URLs. In those cases, we
* don't generate files at all, and we don't add any links to them either.
*
* @coversNothing This test is not testing a specific class, but a general feature of the framework.
*/
class SitesWithoutBaseUrlAreHandledGracefullyTest extends TestCase
{
public static function pageClassProvider(): array
{
return [
[MarkdownPage::class],
[MarkdownPost::class],
[DocumentationPage::class],
];
}

/** @dataProvider pageClassProvider */
public function testLocalhostLinksAreNotAddedToCompiledHtmlWhenBaseUrlIsNull(string $class)
{
config(['hyde.url' => null]);

$this->assertStringNotContainsString('http://localhost', $this->getHtml($class));
}

/** @dataProvider pageClassProvider */
public function testLocalhostLinksAreNotAddedToCompiledHtmlWhenBaseUrlIsNotSet(string $class)
{
config(['hyde.url' => '']);

$this->assertStringNotContainsString('http://localhost', $this->getHtml($class));
}

/** @dataProvider pageClassProvider */
public function testLocalhostLinksAreNotAddedToCompiledHtmlWhenBaseUrlIsSetToLocalhost(string $class)
{
config(['hyde.url' => 'http://localhost']);

$this->assertStringNotContainsString('http://localhost', $this->getHtml($class));
}

/** @dataProvider pageClassProvider */
public function testSiteUrlLinksAreAddedToCompiledHtmlWhenBaseUrlIsSetToValidUrl(string $class)
{
config(['hyde.url' => 'https://example.com']);

$this->assertStringNotContainsString('http://localhost', $this->getHtml($class));
}

protected function getHtml(string $class): string
{
$page = new $class('foo');

Hyde::shareViewData($page);

return $page->compile();
}
}
97 changes: 82 additions & 15 deletions packages/framework/tests/Feature/Views/MetadataViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected function setUp(): void
{
parent::setUp();

config(['hyde.url' => 'http://localhost']);
config(['hyde.url' => 'https://example.com']);
config(['hyde.enable_cache_busting' => false]);
}

Expand Down Expand Up @@ -79,7 +79,7 @@ protected function getDefaultTags(): array
'<meta charset="utf-8">',
'<meta name="viewport" content="width=device-width, initial-scale=1">',
'<meta id="meta-color-scheme" name="color-scheme" content="light">',
'<link rel="sitemap" href="http://localhost/sitemap.xml" type="application/xml" title="Sitemap">',
'<link rel="sitemap" href="https://example.com/sitemap.xml" type="application/xml" title="Sitemap">',
'<meta name="generator" content="HydePHP v'.HydeKernel::VERSION.'">',
'<meta property="og:site_name" content="HydePHP">',
];
Expand All @@ -93,7 +93,7 @@ public function testMetadataTagsInEmptyBladePage()
$assertions = $this->assertSee('test', array_merge($this->getDefaultTags(), [
'<title>HydePHP - Test</title>',
'<link rel="stylesheet" href="media/app.css">',
'<link rel="canonical" href="http://localhost/test.html">',
'<link rel="canonical" href="https://example.com/test.html">',
'<meta name="twitter:title" content="HydePHP - Test">',
'<meta property="og:title" content="HydePHP - Test">',
]));
Expand All @@ -109,7 +109,7 @@ public function testMetadataTagsInEmptyMarkdownPage()
$assertions = $this->assertSee('test', array_merge($this->getDefaultTags(), [
'<title>HydePHP - Test</title>',
'<link rel="stylesheet" href="media/app.css">',
'<link rel="canonical" href="http://localhost/test.html">',
'<link rel="canonical" href="https://example.com/test.html">',
'<meta name="twitter:title" content="HydePHP - Test">',
'<meta property="og:title" content="HydePHP - Test">',
]));
Expand All @@ -125,7 +125,7 @@ public function testMetadataTagsInEmptyDocumentationPage()
$assertions = $this->assertSee('docs/test', array_merge($this->getDefaultTags(), [
'<title>HydePHP - Test</title>',
'<link rel="stylesheet" href="../media/app.css">',
'<link rel="canonical" href="http://localhost/docs/test.html">',
'<link rel="canonical" href="https://example.com/docs/test.html">',
'<meta name="twitter:title" content="HydePHP - Test">',
'<meta property="og:title" content="HydePHP - Test">',
]));
Expand All @@ -140,16 +140,16 @@ public function testMetadataTagsInEmptyMarkdownPost()

$assertions = $this->assertSee('posts/test', array_merge($this->getDefaultTags(), [
'<title>HydePHP - Test</title>',
'<link rel="alternate" href="http://localhost/feed.xml" type="application/rss+xml" title="HydePHP RSS Feed">',
'<link rel="alternate" href="https://example.com/feed.xml" type="application/rss+xml" title="HydePHP RSS Feed">',
'<link rel="stylesheet" href="../media/app.css">',
'<link rel="canonical" href="http://localhost/posts/test.html">',
'<link rel="canonical" href="https://example.com/posts/test.html">',
'<meta name="twitter:title" content="HydePHP - Test">',
'<meta name="url" content="http://localhost/posts/test.html">',
'<meta name="url" content="https://example.com/posts/test.html">',
'<meta property="og:title" content="HydePHP - Test">',
'<meta property="og:url" content="http://localhost/posts/test.html">',
'<meta property="og:url" content="https://example.com/posts/test.html">',
'<meta property="og:type" content="article">',
'<meta itemprop="identifier" content="test">',
'<meta itemprop="url" content="http://localhost/posts/test.html">',
'<meta itemprop="url" content="https://example.com/posts/test.html">',
]));

$this->assertAllTagsWereCovered('posts/test', $assertions);
Expand Down Expand Up @@ -177,25 +177,92 @@ public function testMetadataTagsInMarkdownPostWithFlatFrontMatter()

$assertions = $this->assertSee('posts/test', array_merge($this->getDefaultTags(), [
'<title>HydePHP - My title</title>',
'<link rel="alternate" href="http://localhost/feed.xml" type="application/rss+xml" title="HydePHP RSS Feed">',
'<link rel="alternate" href="https://example.com/feed.xml" type="application/rss+xml" title="HydePHP RSS Feed">',
'<link rel="stylesheet" href="../media/app.css">',
'<link rel="canonical" href="http://localhost/posts/test.html">',
'<link rel="canonical" href="https://example.com/posts/test.html">',
'<meta name="twitter:title" content="HydePHP - My title">',
'<meta name="description" content="My description">',
'<meta name="author" content="Mr. Hyde">',
'<meta name="keywords" content="My category">',
'<meta name="url" content="http://localhost/posts/test.html">',
'<meta name="url" content="https://example.com/posts/test.html">',
'<meta property="og:title" content="HydePHP - My title">',
'<meta property="og:url" content="http://localhost/posts/test.html">',
'<meta property="og:url" content="https://example.com/posts/test.html">',
'<meta property="og:type" content="article">',
'<meta property="og:article:published_time" content="2022-01-01T00:00:00+00:00">',
'<meta property="og:image" content="../media/image.jpg">',
'<meta itemprop="identifier" content="test">',
'<meta itemprop="url" content="http://localhost/posts/test.html">',
'<meta itemprop="url" content="https://example.com/posts/test.html">',
'<meta itemprop="url" content="../media/image.jpg">',
'<meta itemprop="contentUrl" content="../media/image.jpg">',
]));

$this->assertAllTagsWereCovered('posts/test', $assertions);
}

public function testCanonicalUrlTagsAreNotAddedWhenCanonicalUrlIsNotSet()
{
config(['hyde.url' => 'http://localhost']);

$this->file('_posts/test.md', <<<'MARKDOWN'
---
title: "My title"
description: "My description"
category: "My category"
date: "2022-01-01"
author: "Mr. Hyde"
image: image.jpg
---

## Hello World

Lorem Ipsum Dolor Amet.
MARKDOWN
);
$this->build('_posts/test.md');

$assertions = $this->assertSee('posts/test', [
'<meta charset="utf-8">',
'<meta name="viewport" content="width=device-width, initial-scale=1">',
'<meta id="meta-color-scheme" name="color-scheme" content="light">',
'<meta name="generator" content="HydePHP v'.HydeKernel::VERSION.'">',
'<meta property="og:site_name" content="HydePHP">',
'<title>HydePHP - My title</title>',
'<link rel="stylesheet" href="../media/app.css">',
'<meta name="twitter:title" content="HydePHP - My title">',
'<meta name="description" content="My description">',
'<meta name="author" content="Mr. Hyde">',
'<meta name="keywords" content="My category">',
'<meta property="og:title" content="HydePHP - My title">',
'<meta property="og:type" content="article">',
'<meta property="og:article:published_time" content="2022-01-01T00:00:00+00:00">',
'<meta property="og:image" content="../media/image.jpg">',
'<meta itemprop="identifier" content="test">',
'<meta itemprop="url" content="../media/image.jpg">',
'<meta itemprop="contentUrl" content="../media/image.jpg">',

// '<link rel="sitemap" href="http://localhost/sitemap.xml" type="application/xml" title="Sitemap">',
// '<link rel="alternate" href="http://localhost/feed.xml" type="application/rss+xml" title="HydePHP RSS Feed">',
// '<link rel="canonical" href="http://localhost/posts/test.html">',
// '<meta name="url" content="http://localhost/posts/test.html">',
// '<meta property="og:url" content="http://localhost/posts/test.html">',
// '<meta itemprop="url" content="http://localhost/posts/test.html">',
]);

$this->assertAllTagsWereCovered('posts/test', $assertions);

$dontSee = [
'<link rel="sitemap"',
'<link rel="alternate"',
'<link rel="canonical"',
'<meta name="url"',
'<meta property="og:url"',
'<meta itemprop="url" content="http',
];

$contents = file_get_contents(Hyde::path('_site/posts/test.html'));

foreach ($dontSee as $text) {
$this->assertStringNotContainsString($text, $contents);
}
}
}
Loading
Loading