Passed
Push — master ( 32a4a2...da9bd5 )
by Caen
04:12 queued 14s
created

CreatesNewPageSourceFile::getOutputPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
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
    /** @deprecated This method may be removed as the save method now returns the path. */
66
    public function getOutputPath(): string
67
    {
68
        return $this->outputPath;
69
    }
70
71
    protected function parseTitle(string $title): string
72
    {
73
        return Str::afterLast($title, '/');
74
    }
75
76
    protected function fileName(string $title): string
77
    {
78
        // If title contains a slash, it's a subdirectory
79
        if (str_contains($title, '/')) {
80
            // So we normalize the subdirectory name
81
            $this->subDir = $this->normalizeSubdirectory($title);
82
        }
83
84
        // And return a slug made from just the title without the subdirectory
85
        return Str::slug(basename($title));
86
    }
87
88
    protected function normalizeSubdirectory(string $title): string
89
    {
90
        return unslash('/'.rtrim(Str::beforeLast($title, '/').'/', '/\\'));
91
    }
92
93
    /** @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...
94
    protected function makeOutputPath(string $pageClass): string
95
    {
96
        return Hyde::path($pageClass::sourcePath($this->formatIdentifier()));
97
    }
98
99
    protected function createBladeFile(): void
100
    {
101
        $this->needsParentDirectory($this->outputPath);
102
103
        file_put_contents($this->outputPath, Hyde::normalizeNewlines(<<<BLADE
104
            @extends('hyde::layouts.app')
105
            @section('content')
106
            @php(\$title = "$this->title")
107
            
108
            <main class="mx-auto max-w-7xl py-16 px-8">
109
                <h1 class="text-center text-3xl font-bold">$this->title</h1>
110
            </main>
111
            
112
            @endsection
113
114
            BLADE
115
        ));
116
    }
117
118
    protected function createMarkdownFile(): void
119
    {
120
        (new MarkdownPage($this->formatIdentifier(), ['title' => $this->title], "# $this->title"))->save();
121
    }
122
123
    protected function createDocumentationFile(): void
124
    {
125
        (new DocumentationPage($this->formatIdentifier(), [], "# $this->title"))->save();
126
    }
127
128
    protected function formatIdentifier(): string
129
    {
130
        return "$this->subDir/$this->filename";
131
    }
132
133
    protected function validateType(string $pageClass): void
134
    {
135
        if (! in_array($pageClass, [MarkdownPage::class, BladePage::class, DocumentationPage::class])) {
136
            throw new UnsupportedPageTypeException('The page type must be either "markdown", "blade", or "documentation"');
137
        }
138
    }
139
140
    protected function failIfFileCannotBeSaved(string $path): void
141
    {
142
        if ($this->force !== true && file_exists($path)) {
143
            throw new FileConflictException($path);
144
        }
145
    }
146
}
147