Passed
Push — master ( ad6b2a...b41ca0 )
by Caen
07:45 queued 14s
created

DataCollection::parseYamlFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Support;
6
7
use stdClass;
8
use Illuminate\Support\Str;
9
use Hyde\Facades\Filesystem;
10
use Symfony\Component\Yaml\Yaml;
11
use Illuminate\Support\Collection;
12
use Hyde\Markdown\Models\FrontMatter;
13
use Hyde\Markdown\Models\MarkdownDocument;
14
use Hyde\Framework\Actions\MarkdownFileParser;
15
use Symfony\Component\Yaml\Exception\ParseException;
16
17
use function blank;
18
use function Hyde\path_join;
19
use function Hyde\unslash;
20
use function json_decode;
21
use function json_last_error_msg;
22
23
/**
24
 * Automatically generates Laravel Collections from static data files,
25
 * such as Markdown components and YAML files using Hyde Autodiscovery.
26
 *
27
 * This class acts both as a base collection class, a factory for
28
 * creating collections, and static facade shorthand helper methods.
29
 *
30
 * The static "facade" methods are what makes this class special,
31
 * they allow you to quickly access the data collections.
32
 *
33
 * To use them retrieve a collection, call a facade method with the
34
 * name of the data collection subdirectory.
35
 *
36
 * All collections are indexed by their filename, which is relative
37
 * to the configured data collection source directory.
38
 */
39
class DataCollection extends Collection
40
{
41
    /**
42
     * The base directory for all data collections. Can be modified using a service provider.
43
     */
44
    public static string $sourceDirectory = 'resources/collections';
45
46
    /**
47
     * Get a collection of Markdown documents in the resources/collections/<$key> directory.
48
     *
49
     * Each Markdown file will be parsed into a MarkdownDocument with front matter.
50
     *
51
     * @return static<string, \Hyde\Markdown\Models\MarkdownDocument>
52
     */
53
    public static function markdown(string $name): static
54
    {
55
        return static::discover($name, 'md', static::parseMarkdownFile(...));
56
    }
57
58
    /**
59
     * Get a collection of YAML documents in the resources/collections/<$key> directory.
60
     *
61
     * Each YAML file will be parsed into a FrontMatter object.
62
     *
63
     * @return static<string, \Hyde\Markdown\Models\FrontMatter>
64
     */
65
    public static function yaml(string $name): static
66
    {
67
        return static::discover($name, ['yaml', 'yml'], static::parseYamlFile(...));
68
    }
69
70
    /**
71
     * Get a collection of JSON documents in the resources/collections/<$key> directory.
72
     *
73
     * Each JSON file will be parsed into a stdClass object, or an associative array, depending on the second parameter.
74
     *
75
     * @return static<string, \stdClass|array>
76
     */
77
    public static function json(string $name, bool $asArray = false): static
78
    {
79
        return static::discover($name, 'json', static::parseJsonFile(...), [$asArray]);
80
    }
81
82
    /**
83
     * @param  array<string>|string  $extensions
84
     * @param  callable(string): mixed  $parseUsing
85
     * @return static<string, MarkdownDocument|FrontMatter|stdClass|array>
86
     *
87
     * @throws \Hyde\Framework\Exceptions\ParseException If the file is empty or invalid.
88
     */
89
    protected static function discover(string $name, array|string $extensions, callable $parseUsing, array $extraArgs = []): static
90
    {
91
        return new static(static::findFiles($name, $extensions)->mapWithKeys(function (string $file) use ($parseUsing, $extraArgs): array {
92
            try {
93
                $parsed = $parseUsing($file, ...$extraArgs);
94
            } catch (ParseException $exception) {
95
                throw new \Hyde\Framework\Exceptions\ParseException($file, $exception);
96
            }
97
98
            return [static::makeIdentifier($file) => $parsed];
99
        }));
100
    }
101
102
    /**
103
     * @param  array<string>|string  $extensions
104
     * @return Collection<string>
105
     */
106
    protected static function findFiles(string $name, array|string $extensions): Collection
107
    {
108
        return Filesystem::findFiles(path_join(static::$sourceDirectory, $name), $extensions);
109
    }
110
111
    protected static function makeIdentifier(string $path): string
112
    {
113
        return unslash(Str::after($path, static::$sourceDirectory));
114
    }
115
116
    protected static function parseMarkdownFile(string $file): MarkdownDocument
117
    {
118
        $document = MarkdownFileParser::parse($file);
119
120
        if (blank($document->markdown()->body()) && $document->matter()->toArray() === []) {
121
            throw new ParseException('File is empty');
122
        }
123
124
        return $document;
125
    }
126
127
    protected static function parseYamlFile(string $file): FrontMatter
128
    {
129
        $content = Filesystem::getContents($file);
130
        $content = Str::between($content, '---', '---');
131
132
        if (blank($content)) {
133
            throw new ParseException('File is empty');
134
        }
135
136
        return new FrontMatter(Yaml::parse($content));
137
    }
138
139
    protected static function parseJsonFile(string $file, bool $asArray): stdClass|array
140
    {
141
        $contents = Filesystem::getContents($file);
142
143
        if (! json_validate($contents)) {
144
            throw new ParseException(json_last_error_msg());
145
        }
146
147
        return json_decode($contents, $asArray);
148
    }
149
}
150