diff --git a/src/Actions/InitialiseOrbitalTable.php b/src/Actions/InitialiseOrbitalTable.php index 27ffe7a..ee1ec82 100644 --- a/src/Actions/InitialiseOrbitalTable.php +++ b/src/Actions/InitialiseOrbitalTable.php @@ -5,7 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Orbit\Contracts\Orbit; +use Orbit\Support\ConfigureBlueprintFromModel; use Orbit\Support\ModelUsesSoftDeletes; +use ReflectionClass; class InitialiseOrbitalTable { @@ -13,7 +15,11 @@ public function shouldInitialise(Orbit&Model $model): bool { $schemaBuilder = $model->resolveConnection()->getSchemaBuilder(); - return $schemaBuilder->hasTable($model->getTable()); + $modelFile = (new ReflectionClass($model))->getFileName(); + $modelFileMTime = filemtime($modelFile); + $databaseMTime = filemtime(config('orbit.paths.database')); + + return ($modelFileMTime > $databaseMTime) || !$schemaBuilder->hasTable($model->getTable()); } public function migrate(Orbit&Model $model): void @@ -30,15 +36,7 @@ public function migrate(Orbit&Model $model): void $schemaBuilder->create($table, static function (Blueprint $table) use (&$blueprint, $model) { $blueprint = $table; - $model->schema($blueprint); - - if ($model->usesTimestamps()) { - $blueprint->timestamps(); - } - - if (ModelUsesSoftDeletes::check($model)) { - $blueprint->softDeletes(); - } + ConfigureBlueprintFromModel::configure($model, $blueprint); }); } } diff --git a/src/Actions/MaybeRefreshDatabaseContent.php b/src/Actions/MaybeRefreshDatabaseContent.php index 677635f..db40ecd 100644 --- a/src/Actions/MaybeRefreshDatabaseContent.php +++ b/src/Actions/MaybeRefreshDatabaseContent.php @@ -4,9 +4,13 @@ use FilesystemIterator; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Collection; use Orbit\Contracts\Driver; use Orbit\Contracts\Orbit; +use Orbit\Support\ConfigureBlueprintFromModel; +use Orbit\Support\FillMissingAttributeValues; +use Orbit\Support\FillMissingAttributeValuesFromBlueprint; use ReflectionClass; class MaybeRefreshDatabaseContent @@ -18,37 +22,43 @@ public function shouldRefresh(Orbit&Model $model): bool $highestMTime = 0; foreach (new FilesystemIterator($directory, FilesystemIterator::SKIP_DOTS) as $file) { - if ($file->getMTime() > $highestMTime) { + if ($file->getMTime() >= $highestMTime) { $highestMTime = $file->getMTime(); } } - return $highestMTime > $databaseMTime; + return $highestMTime >= $databaseMTime; } public function refresh(Orbit&Model $model, Driver $driver): void { - $databaseMTime = filemtime(config('orbit.paths.database')); + $model->query()->truncate(); $directory = config('orbit.paths.content').DIRECTORY_SEPARATOR.$model->getOrbitSource(); $iterator = new FilesystemIterator($directory, FilesystemIterator::SKIP_DOTS); $records = []; foreach ($iterator as $file) { - if ($file->getMTime() <= $databaseMTime) { - continue; - } - $contents = file_get_contents($file->getRealPath()); $records[] = $driver->parse($contents); } + $blueprint = ConfigureBlueprintFromModel::configure( + $model, + new Blueprint($model->getTable()) + ); + collect($records) ->chunk(100) - ->each(function (Collection $chunk) use ($model) { + ->each(function (Collection $chunk) use ($model, $blueprint) { // This will ensure that we don't have any collisions with existing data in the SQLite database. $model->query()->whereKey($chunk->pluck($model->getKey()))->delete(); - $model->insert($chunk->all()); + + $model->insert( + $chunk + ->map(fn (array $attributes) => FillMissingAttributeValuesFromBlueprint::fill($attributes, $blueprint)) + ->all() + ); }); } } diff --git a/src/Actions/SaveCompiledAttributesToFile.php b/src/Actions/SaveCompiledAttributesToFile.php index 8061ddf..ba3bdb5 100644 --- a/src/Actions/SaveCompiledAttributesToFile.php +++ b/src/Actions/SaveCompiledAttributesToFile.php @@ -13,8 +13,12 @@ public function execute(Orbit&Model $model, string $compiledAttributes, Driver $ { $directory = config('orbit.paths.content').DIRECTORY_SEPARATOR.$model->getOrbitSource(); $filename = "{$model->getKey()}.{$driver->extension()}"; - $fs = new Filesystem(); + + if ($model->wasChanged($model->getKey())) { + $fs->delete($directory . DIRECTORY_SEPARATOR . $model->getOriginal($model->getKeyName()) . '.' . $driver->extension()); + } + $fs->put($directory.DIRECTORY_SEPARATOR.$filename, $compiledAttributes); } } diff --git a/src/Concerns/Orbital.php b/src/Concerns/Orbital.php index 58d6c85..2c04fc7 100644 --- a/src/Concerns/Orbital.php +++ b/src/Concerns/Orbital.php @@ -46,14 +46,14 @@ public static function bootOrbital() $initialiseOrbitTable->migrate($model); } - $saveCompiledAttributesToFile = new SaveCompiledAttributesToFile(); - $maybeRefreshDatabaseContent = new MaybeRefreshDatabaseContent(); if ($maybeRefreshDatabaseContent->shouldRefresh($model)) { $maybeRefreshDatabaseContent->refresh($model, $driver); } + $saveCompiledAttributesToFile = new SaveCompiledAttributesToFile(); + static::created(function (Orbit&Model $model) use ($driver, $saveCompiledAttributesToFile) { $model->refresh(); diff --git a/src/Support/ConfigureBlueprintFromModel.php b/src/Support/ConfigureBlueprintFromModel.php new file mode 100644 index 0000000..636057e --- /dev/null +++ b/src/Support/ConfigureBlueprintFromModel.php @@ -0,0 +1,25 @@ +schema($blueprint); + + if ($model->usesTimestamps()) { + $blueprint->timestamps(); + } + + if (ModelUsesSoftDeletes::check($model)) { + $blueprint->softDeletes(); + } + + return $blueprint; + } +} diff --git a/src/Support/FillMissingAttributeValuesFromBlueprint.php b/src/Support/FillMissingAttributeValuesFromBlueprint.php new file mode 100644 index 0000000..7e78d74 --- /dev/null +++ b/src/Support/FillMissingAttributeValuesFromBlueprint.php @@ -0,0 +1,29 @@ +getColumns() as $column) { + $name = $column->name; + + if (array_key_exists($name, $attributes)) { + continue; + } + + if ($column->nullable) { + $attributes[$name] = null; + } elseif ($column->default) { + $attributes[$name] = $column->default; + } + } + + return $attributes; + } +} diff --git a/tests/Fixtures/Models/Category.php b/tests/Fixtures/Models/Category.php index c687337..2bfe94b 100644 --- a/tests/Fixtures/Models/Category.php +++ b/tests/Fixtures/Models/Category.php @@ -19,5 +19,6 @@ public function schema(Blueprint $table): void { $table->id(); $table->string('title'); + $table->longText('content')->nullable(); } } diff --git a/tests/Pest.php b/tests/Pest.php index 55a3a84..09a38cf 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -5,7 +5,7 @@ uses(Tests\TestCase::class)->in('Feature'); -beforeEach(function () { +afterEach(function () { Post::all()->each(fn (Post $post) => $post->delete()); Category::all()->each(fn (Category $category) => $category->forceDelete()); });