Skip to content
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"require": {
"php": "^8.1",
"statamic/cms": "^5.14"
"statamic/cms": "^5.16"
},
"require-dev": {
"doctrine/dbal": "^3.8",
Expand Down
5 changes: 5 additions & 0 deletions config/eloquent-driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,9 @@
'driver' => 'file',
'model' => \Statamic\Eloquent\Tokens\TokenModel::class,
],

'sites' => [
'driver' => 'file',
'model' => \Statamic\Eloquent\Sites\SiteModel::class,
],
];
27 changes: 27 additions & 0 deletions database/migrations/2024_07_16_100000_create_sites_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Statamic\Eloquent\Database\BaseMigration as Migration;

return new class extends Migration
{
public function up()
{
Schema::create($this->prefix('sites'), function (Blueprint $table) {
$table->id();
$table->string('handle')->unique();
$table->string('name');
$table->string('url');
$table->string('locale');
$table->string('lang');
$table->jsonb('attributes');
$table->timestamps();
});
}

public function down()
{
Schema::dropIfExists($this->prefix('sites'));
}
};
55 changes: 55 additions & 0 deletions src/Commands/ExportSites.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Statamic\Eloquent\Commands;

use Illuminate\Console\Command;
use Statamic\Console\RunsInPlease;
use Statamic\Eloquent\Sites\SiteModel;
use Statamic\Sites\Sites;

class ExportSites extends Command
{
use RunsInPlease;

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'statamic:eloquent:export-sites';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Exports eloquent sites to flat files.';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$sites = SiteModel::all()
->mapWithKeys(function ($model) {
return [
$model->handle => [
'name' => $model->name,
'lang' => $model->lang,
'locale' => $model->locale,
'url' => $model->url,
'attributes' => $model->attributes ?? [],
],
];
});

(new Sites)->setSites($sites)->save();

$this->newLine();
$this->info('Sites exported');

return 0;
}
}
41 changes: 41 additions & 0 deletions src/Commands/ImportSites.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Statamic\Eloquent\Commands;

use Illuminate\Console\Command;
use Statamic\Console\RunsInPlease;
use Statamic\Eloquent\Sites\Sites as EloquentSites;
use Statamic\Sites\Sites;

class ImportSites extends Command
{
use RunsInPlease;

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'statamic:eloquent:import-sites';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Imports file-based sites into the database.';

/**
* Execute the console command.
*/
public function handle(): int
{
$sites = (new Sites)->config();

(new EloquentSites)->setSites($sites)->save();

$this->components->info('Sites imported successfully.');

return 0;
}
}
24 changes: 23 additions & 1 deletion src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public function boot()
Commands\ExportNavs::class,
Commands\ExportRevisions::class,
Commands\ExportTaxonomies::class,
Commands\ExportSites::class,
Commands\ImportAssets::class,
Commands\ImportBlueprints::class,
Commands\ImportCollections::class,
Expand All @@ -92,6 +93,7 @@ public function boot()
Commands\ImportNavs::class,
Commands\ImportRevisions::class,
Commands\ImportTaxonomies::class,
Commands\ImportSites::class,
Commands\SyncAssets::class,
]);

Expand Down Expand Up @@ -161,6 +163,10 @@ private function publishMigrations(): void
__DIR__.'/../database/migrations/2024_03_07_100000_create_tokens_table.php' => database_path('migrations/2024_03_07_100000_create_tokens_table.php'),
], 'statamic-eloquent-token-migrations');

$this->publishes($siteMigrations = [
__DIR__.'/../database/migrations/2024_07_16_100000_create_sites_table.php' => database_path('migrations/2024_07_16_100000_create_sites_table.php'),
], 'statamic-eloquent-site-migrations');

$this->publishes(
array_merge(
$taxonomyMigrations,
Expand All @@ -177,7 +183,8 @@ private function publishMigrations(): void
$assetContainerMigrations,
$assetMigrations,
$revisionMigrations,
$tokenMigrations
$tokenMigrations,
$siteMigrations,
),
'migrations'
);
Expand Down Expand Up @@ -210,6 +217,7 @@ public function register()
$this->registerTaxonomies();
$this->registerTerms();
$this->registerTokens();
$this->registerSites();
}

private function registerAssetContainers()
Expand Down Expand Up @@ -517,6 +525,19 @@ public function registerTokens()
Statamic::repository(TokenRepositoryContract::class, TokenRepository::class);
}

public function registerSites()
{
if (config('statamic.eloquent-driver.sites.driver', 'file') != 'eloquent') {
return;
}

$this->app->bind('statamic.eloquent.sites.model', function () {
return config('statamic.eloquent-driver.sites.model');
});

$this->app->singleton(\Statamic\Sites\Sites::class, \Statamic\Eloquent\Sites\Sites::class);
}

protected function addAboutCommandInfo()
{
if (! class_exists(AboutCommand::class)) {
Expand All @@ -539,6 +560,7 @@ protected function addAboutCommandInfo()
'Taxonomies' => config('statamic.eloquent-driver.taxonomies.driver', 'file'),
'Terms' => config('statamic.eloquent-driver.terms.driver', 'file'),
'Tokens' => config('statamic.eloquent-driver.tokens.driver', 'file'),
'Sites' => config('statamic.eloquent-driver.sites.driver', 'file'),
])->map(fn ($value) => $this->applyAboutCommandFormatting($value))->all());
}

Expand Down
22 changes: 22 additions & 0 deletions src/Sites/SiteModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Statamic\Eloquent\Sites;

use Illuminate\Support\Arr;
use Statamic\Eloquent\Database\BaseModel;

class SiteModel extends BaseModel
{
protected $guarded = [];

protected $table = 'sites';

protected $casts = [
'attributes' => 'json',
];

public function getAttribute($key)
{
return Arr::get($this->getAttributeValue('attributes'), $key, parent::getAttribute($key));
}
}
40 changes: 40 additions & 0 deletions src/Sites/Sites.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Statamic\Eloquent\Sites;

class Sites extends \Statamic\Sites\Sites
{
protected function getSavedSites()
{
$sites = app('statamic.eloquent.sites.model')::all();

return $sites->isEmpty() ? $this->getFallbackConfig() : $sites->mapWithKeys(function ($model) {
return [
$model->handle => [
'name' => $model->name,
'lang' => $model->lang,
'locale' => $model->locale,
'url' => $model->url,
'attributes' => $model->attributes ?? [],
],
];
});
}

protected function saveToStore()
{
foreach ($this->config() as $handle => $config) {
app('statamic.eloquent.sites.model')::firstOrNew(['handle' => $handle])
->fill([
'name' => $config['name'] ?? '',
'lang' => $config['lang'] ?? '',
'locale' => $config['locale'] ?? '',
'url' => $config['url'] ?? '',
'attributes' => $config['attributes'] ?? [],
])
->save();
}

app('statamic.eloquent.sites.model')::whereNotIn('handle', array_keys($this->config()))->get()->each->delete();
}
}
63 changes: 63 additions & 0 deletions tests/Commands/ImportSitesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Commands;

use PHPUnit\Framework\Attributes\Test;
use Statamic\Eloquent\Sites\SiteModel;
use Statamic\Testing\Concerns\PreventsSavingStacheItemsToDisk;
use Tests\TestCase;

class ImportSitesTest extends TestCase
{
use PreventsSavingStacheItemsToDisk;

public function setUp(): void
{
parent::setUp();

$this->app->bind('statamic.eloquent.sites.model', function () {
return SiteModel::class;
});
}

#[Test]
public function it_imports_sites()
{
$this->assertCount(0, SiteModel::all());

$this->setSites([
'en' => ['name' => 'English', 'locale' => 'en_US', 'url' => 'http://test.com/'],
'fr' => ['name' => 'French', 'locale' => 'fr_FR', 'url' => 'http://fr.test.com/'],
'es' => ['name' => 'Spanish', 'locale' => 'es_ES', 'url' => 'http://test.com/es/'],
'de' => ['name' => 'German', 'locale' => 'de_DE', 'url' => 'http://test.com/de/'],
]);

\Statamic\Facades\Site::save();

$this->artisan('statamic:eloquent:import-sites')
->expectsOutputToContain('Sites imported successfully.')
->assertExitCode(0);

$this->assertCount(4, SiteModel::all());

$this->assertDatabaseHas('sites', [
'handle' => 'en',
'name' => 'English',
]);

$this->assertDatabaseHas('sites', [
'handle' => 'fr',
'name' => 'French',
]);

$this->assertDatabaseHas('sites', [
'handle' => 'de',
'name' => 'German',
]);

$this->assertDatabaseHas('sites', [
'handle' => 'es',
'name' => 'Spanish',
]);
}
}
Loading