statamic / eloquent-driver

Provides support for storing your Statamic data in a database, rather than flat files.
https://statamic.dev/tips/storing-content-in-a-database
MIT License
108 stars 78 forks source link

Corrects issue with importing/exporting Blueprints on Windows #351

Closed JohnathonKoster closed 2 months ago

JohnathonKoster commented 2 months ago

This PR fixes #350. This issue is ultimately caused by this line:

https://github.com/statamic/eloquent-driver/blob/master/src/Commands/ImportBlueprints.php#L132

On Windows, we can get a path with \ directory separators. When we replace / with . in the blueprint's namespace, on Windows you can end up with a namespace in the database that looks something like:

C:.apachewsl.testblueprintcrash.resources.blueprints.assets

When exporting, this will result in a duplicated path (since we replace the . with /, and then append that to the blueprints directory).

This PR fixes that by normalizing the blueprint path before importing.

Exporting Existing Blueprints w/ Impacted Namespaces

This PR allows for this by extending Core's Blueprint to adjust the namespace if it starts with the mangled resource directory. This will allow users who already have data imported on a Windows system to be able to export that data using the existing command:

php please eloquent:export-blueprints

Correcting Blueprint Namespaces

For Windows users who already have impacted Blueprint namespaces and would like to fix their namespaces and continue using the Eloquent driver, they can execute this:

<?php

use Statamic\Eloquent\Fields\BlueprintModel;

$blueprintPath = str(resource_path('blueprints'))
    ->replace('\\', '/')
    ->replace('/', '.')
    ->value();

BlueprintModel::all()->each(function (BlueprintModel $blueprint) use ($blueprintPath) {
    if (! str_starts_with($blueprint->namespace, $blueprintPath)) {
        return;
    }

    $blueprint->namespace = str($blueprint->namespace)
        ->after($blueprintPath)
        ->substr(1)
        ->value();

    if ($blueprint->namespace === '') {
        $blueprint->namespace = null;
    }

    $blueprint->saveQuietly();
});

Important Note: Users who update to this PR, who do not update their existing blueprint namespaces and then re-import them will end up with extra records in their blueprints table (one record with the mangled namespace, and one record with the correct namespace).

ryanmitchell commented 2 months ago

Looks good to me at this point.