Passed
Push — master ( 721b09...b6aafe )
by Caen
03:25 queued 13s
created

CreatesNewPageSourceFile::fileName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 10
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Framework\Actions;
6
7
use Hyde\Hyde;
8
use Hyde\Pages\BladePage;
9
use Illuminate\Support\Str;
10
use Hyde\Pages\MarkdownPage;
11
use Hyde\Pages\DocumentationPage;
12
use Hyde\Framework\Exceptions\FileConflictException;
13
use Hyde\Framework\Concerns\InteractsWithDirectories;
14
use Hyde\Framework\Exceptions\UnsupportedPageTypeException;
15
use function file_put_contents;
16
use function file_exists;
17
use function basename;
18
use function in_array;
19
use function unslash;
20
use function rtrim;
21
22
/**
23
 * Scaffold a new Markdown, Blade, or documentation page.
24
 *
25
 * @see \Hyde\Framework\Testing\Feature\Actions\CreatesNewPageSourceFileTest
26
 */
27
class CreatesNewPageSourceFile
28
{
29
    use InteractsWithDirectories;
30
31
    /** @var class-string<\Hyde\Pages\Concerns\HydePage> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<\Hyde\Pages\Concerns\HydePage> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<\Hyde\Pages\Concerns\HydePage>.
Loading history...
32
    protected string $pageClass;
33
34
    protected string $title;
35
    protected string $filename;
36
    protected string $outputPath;
37
    protected string $subDir = '';
38
    protected bool $force;
39
40
    public function __construct(string $title, string $pageClass = MarkdownPage::class, bool $force = false)
41
    {
42
        $this->validateType($pageClass);
43
        $this->pageClass = $pageClass;
44
45
        $this->title = $this->parseTitle($title);
46
        $this->filename = $this->fileName($title);
47
        $this->force = $force;
48
49
        $this->outputPath = $this->makeOutputPath($pageClass);
50
    }
51
52
    public function save(): string
53
    {
54
        $this->failIfFileCannotBeSaved($this->outputPath);
55
56
        match ($this->pageClass) {
57
            BladePage::class => $this->createBladeFile(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->createBladeFile() targeting Hyde\Framework\Actions\C...File::createBladeFile() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
58
            MarkdownPage::class => $this->createMarkdownFile(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->createMarkdownFile() targeting Hyde\Framework\Actions\C...e::createMarkdownFile() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
59
            DocumentationPage::class => $this->createDocumentationFile(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->createDocumentationFile() targeting Hyde\Framework\Actions\C...eateDocumentationFile() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
60
        };
61
62
        return $this->outputPath;
63
    }
64
65
    protected function parseTitle(string $title): string
66
    {
67
        return Str::afterLast($title, '/');
68
    }
69
70
    protected function fileName(string $title): string
71
    {
72
        // If title contains a slash, it's a subdirectory
73
        if (str_contains($title, '/')) {
74
            // So we normalize the subdirectory name
75
            $this->subDir = $this->normalizeSubdirectory($title);
76
        }
77
78
        // And return a slug made from just the title without the subdirectory
79
        return Str::slug(basename($title));
80
    }
81
82
    protected function normalizeSubdirectory(string $title): string
83
    {
84
        return unslash('/'.rtrim(Str::beforeLast($title, '/').'/', '/\\'));
85
    }
86
87
    /** @param class-string<\Hyde\Pages\Concerns\HydePage> $pageClass */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<\Hyde\Pages\Concerns\HydePage> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<\Hyde\Pages\Concerns\HydePage>.
Loading history...
88
    protected function makeOutputPath(string $pageClass): string
89
    {
90
        return Hyde::path($pageClass::sourcePath($this->formatIdentifier()));
91
    }
92
93
    protected function createBladeFile(): void
94
    {
95
        $this->needsParentDirectory($this->outputPath);
96
97
        file_put_contents($this->outputPath, Hyde::normalizeNewlines(<<<BLADE
98
            @extends('hyde::layouts.app')
99
            @section('content')
100
            @php(\$title = "$this->title")
101
            
102
            <main class="mx-auto max-w-7xl py-16 px-8">
103
                <h1 class="text-center text-3xl font-bold">$this->title</h1>
104
            </main>
105
            
106
            @endsection
107
108
            BLADE
109
        ));
110
    }
111
112
    protected function createMarkdownFile(): void
113
    {
114
        (new MarkdownPage($this->formatIdentifier(), ['title' => $this->title], "# $this->title"))->save();
115
    }
116
117
    protected function createDocumentationFile(): void
118
    {
119
        (new DocumentationPage($this->formatIdentifier(), [], "# $this->title"))->save();
120
    }
121
122
    protected function formatIdentifier(): string
123
    {
124
        return "$this->subDir/$this->filename";
125
    }
126
127
    protected function validateType(string $pageClass): void
128
    {
129
        if (! in_array($pageClass, [MarkdownPage::class, BladePage::class, DocumentationPage::class])) {
130
            throw new UnsupportedPageTypeException('The page type must be either "markdown", "blade", or "documentation"');
131
        }
132
    }
133
134
    protected function failIfFileCannotBeSaved(string $path): void
135
    {
136
        if ($this->force !== true && file_exists($path)) {
137
            throw new FileConflictException($path);
138
        }
139
    }
140
}
141