Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ryangjchandler committed Oct 2, 2023
1 parent 2dc260f commit 62648be
Show file tree
Hide file tree
Showing 18 changed files with 272 additions and 57 deletions.
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Todo

* [ ] Model database initialisation.
* [ ] Create new file for new models.
* [x] Model database initialisation.
* [x] Create new file for new models.
* [ ] Update file when updating a model.
* [ ] Delete file when deleting a model.
* [ ] Add support for soft deletes.
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"laravel/pint": "^1.13",
"laravel/scout": "^9.4",
"nunomaduro/larastan": "^2.0",
"orchestra/testbench": "^8.0",
"orchestra/testbench": "^8.12",
"pestphp/pest": "^2.20",
"pestphp/pest-plugin-laravel": "^2.2",
"phpstan/extension-installer": "^1.1",
Expand All @@ -48,7 +48,7 @@
},
"autoload-dev": {
"psr-4": {
"Orbit\\Tests\\": "tests/"
"Tests\\": "tests/"
}
},
"minimum-stability": "dev",
Expand Down
10 changes: 10 additions & 0 deletions config/orbit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

return [

'paths' => [
'database' => base_path('framework/cache/orbit/database.sqlite'),
'content' => base_path('content'),
],

];
39 changes: 39 additions & 0 deletions src/Actions/InitialiseOrbitalTable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Orbit\Actions;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Orbit\Contracts\Orbit;

class InitialiseOrbitalTable
{
public function hasTable(Orbit & Model $model): bool
{
$schemaBuilder = $model->resolveConnection()->getSchemaBuilder();

return $schemaBuilder->hasTable($model->getTable());
}

public function migrate(Orbit & Model $model): void
{
$table = $model->getTable();
$schemaBuilder = $model->resolveConnection()->getSchemaBuilder();

if ($schemaBuilder->hasTable($table)) {
$schemaBuilder->drop($table);
}

$blueprint = null;

$schemaBuilder->create($table, static function (Blueprint $table) use (&$blueprint, $model) {
$blueprint = $table;

$model->schema($blueprint);

if ($model->usesTimestamps()) {
$blueprint->timestamps();
}
});
}
}
26 changes: 26 additions & 0 deletions src/Actions/MaybeCreateOrbitDirectories.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Orbit\Actions;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Filesystem\Filesystem;
use Orbit\Contracts\Orbit;

class MaybeCreateOrbitDirectories
{
public function execute(Orbit & Model $model)
{
$fs = new Filesystem();

$fs->ensureDirectoryExists(config('orbit.paths.content'));
$fs->ensureDirectoryExists(dirname(config('orbit.paths.database')));

if (! $fs->exists(config('orbit.paths.database'))) {
$fs->put(config('orbit.paths.database'), '');
}

$modelDirectory = config('orbit.paths.content') . DIRECTORY_SEPARATOR . $model->getTable();

$fs->ensureDirectoryExists($modelDirectory);
}
}
20 changes: 20 additions & 0 deletions src/Actions/SaveCompiledAttributesToFile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Orbit\Actions;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Filesystem\Filesystem;
use Orbit\Contracts\Driver;
use Orbit\Contracts\Orbit;

class SaveCompiledAttributesToFile
{
public function execute(Orbit & Model $model, string $compiledAttributes, Driver $driver): void
{
$directory = config('orbit.paths.content') . DIRECTORY_SEPARATOR . $model->getTable();
$filename = "{$model->getKey()}.{$driver->extension()}";

$fs = new Filesystem();
$fs->put($directory . DIRECTORY_SEPARATOR . $filename, $compiledAttributes);
}
}
71 changes: 71 additions & 0 deletions src/Concerns/Orbital.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Orbit\Concerns;

use Illuminate\Database\Eloquent\Model;
use Orbit\Actions\InitialiseOrbitalTable;
use Orbit\Actions\MaybeCreateOrbitDirectories;
use Orbit\Actions\SaveCompiledAttributesToFile;
use Orbit\Contracts\Driver;
use Orbit\Contracts\Orbit;
use Orbit\Drivers\Markdown;
use Orbit\Exceptions\InvalidDriverException;
use Orbit\Support\ModelAttributeFormatter;

/**
* @mixin \Illuminate\Database\Eloquent\Model
* @mixin \Orbit\Contracts\Orbit
*/
trait Orbital
{
public static function bootOrbital()
{
$model = new static();
$maybeCreateOrbitDirectories = new MaybeCreateOrbitDirectories();
$maybeCreateOrbitDirectories->execute($model);

$driver = $model->getOrbitDriver();

if (!class_exists($driver)) {
throw InvalidDriverException::make($driver);
}

$driver = app($driver);

if (!$driver instanceof Driver) {
throw InvalidDriverException::make($driver::class);
}

$initialiseOrbitTable = new InitialiseOrbitalTable();

if (! $initialiseOrbitTable->hasTable($model)) {
$initialiseOrbitTable->migrate($model);
}

$saveCompiledAttributesToFile = new SaveCompiledAttributesToFile();

static::created(function (Orbit & Model $model) use ($driver, $saveCompiledAttributesToFile) {
$model->refresh();

$attributes = ModelAttributeFormatter::format($model, $model->getAttributes());
$compiledAttributes = $driver->compile($attributes);

$saveCompiledAttributesToFile->execute($model, $compiledAttributes, $driver);
});
}

public static function resolveConnection($connection = null)
{
return static::$resolver->connection('orbit');
}

public function getConnectionName()
{
return 'orbit';
}

public function getOrbitDriver(): string
{
return Markdown::class;
}
}
5 changes: 5 additions & 0 deletions src/Contracts/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ public function parse(string $fileContents): array;
* Use the given array of attributes to generate the contents of a file.
*/
public function compile(array $attributes): string;

/**
* Specify the file extension used by this driver.
*/
public function extension(): string;
}
4 changes: 2 additions & 2 deletions src/Contracts/Orbital.php → src/Contracts/Orbit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

use Illuminate\Database\Schema\Blueprint;

interface Orbital
interface Orbit
{
/**
* Define the structure of your Orbital model.
*/
public static function schema(Blueprint $table): void;
public function schema(Blueprint $table): void;

/**
* Declare which driver the Orbital should use.
Expand Down
5 changes: 5 additions & 0 deletions src/Drivers/Markdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ public function compile(array $attributes): string

return sprintf("---\n%s\n---\n\n%s", Yaml::dump($attributes), $content);
}

public function extension(): string
{
return 'md';
}
}
13 changes: 13 additions & 0 deletions src/Exceptions/InvalidDriverException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Orbit\Exceptions;

use Exception;

class InvalidDriverException extends Exception
{
public static function make(string $driver): static
{
return new static("Driver {$driver} is invalid or does not implements the \\Orbit\\Contracts\\Driver interface.");

Check failure on line 11 in src/Exceptions/InvalidDriverException.php

View workflow job for this annotation

GitHub Actions / phpstan

Unsafe usage of new static().
}
}
13 changes: 6 additions & 7 deletions src/OrbitServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Config\Repository;
use Illuminate\Filesystem\Filesystem;
use Orbit\Actions\MaybeCreateOrbitDirectories;
use Spatie\LaravelPackageTools\Commands\InstallCommand;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
Expand All @@ -17,14 +18,12 @@ public function configurePackage(Package $package): void
->hasInstallCommand(function (InstallCommand $command) {
$command
->startWith(function () {
$fs = new Filesystem();

$fs->ensureDirectoryExists(base_path('content'));
$fs->ensureDirectoryExists(storage_path('framework/cache/orbit'));
$fs->ensureDirectoryExists(storage_path('framework/cache/orbit/database.sqlite'));
$maybeCreateOrbitDirectories = new MaybeCreateOrbitDirectories();
$maybeCreateOrbitDirectories->execute();

Check failure on line 22 in src/OrbitServiceProvider.php

View workflow job for this annotation

GitHub Actions / phpstan

Method Orbit\Actions\MaybeCreateOrbitDirectories::execute() invoked with 0 parameters, 1 required.
})
->askToStarRepoOnGitHub('ryangjchandler/orbit');
});
})
->hasConfigFile();
}

public function packageRegistered()
Expand All @@ -33,7 +32,7 @@ public function packageRegistered()

$config->set('database.connections.orbit', [
'driver' => 'sqlite',
'database' => base_path('framework/cache/orbit/database.sqlite'),
'database' => $config->get('orbit.paths.database'),
'foreign_key_constraints' => false,
]);
}
Expand Down
26 changes: 26 additions & 0 deletions src/Support/ModelAttributeFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Orbit\Support;

use BackedEnum;
use Illuminate\Database\Eloquent\Model;
use Orbit\Contracts\Orbit;

class ModelAttributeFormatter
{
public static function format(Orbit & Model $model, array $attributes): array
{
$formatted = [];

foreach ($attributes as $key => $value) {
$value = $model->{$key};

$formatted[$key] = match (true) {
$value instanceof BackedEnum => $value->value,
default => $value,
};
}

return $formatted;
}
}
2 changes: 2 additions & 0 deletions testbench.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
providers:
- Orbit\OrbitServiceProvider
17 changes: 17 additions & 0 deletions tests/Feature/Orbital/CreateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

use Tests\Fixtures\Models\Post;

it('creates a new file when a model is created', function () {
$post = Post::create([
'title' => 'Example Post',
]);

expect(base_path("content/posts/{$post->id}.md"))
->toBeFile()
->and(file_get_contents(base_path("content/posts/{$post->id}.md")))
->toContain(<<<MD
id: $post->id
title: 'Example Post'
MD);
});
22 changes: 22 additions & 0 deletions tests/Fixtures/Models/Post.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Tests\Fixtures\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Orbit\Concerns\Orbital;
use Orbit\Contracts\Orbit;

class Post extends Model implements Orbit
{
use Orbital;

protected $guarded = [];

public function schema(Blueprint $table): void
{
$table->id();
$table->string('title');
$table->longText('content')->nullable();
}
}
Loading

0 comments on commit 62648be

Please sign in to comment.