Skip to content
12 changes: 12 additions & 0 deletions config/assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,18 @@

'cache_meta' => true,

/*
|--------------------------------------------------------------------------
| Metadata as Content
|--------------------------------------------------------------------------
|
| Asset metadata will be saved as content alongside the rest of the content.
| This is useful when wanting to track metadata changes in git while using
| another storage location for assets (ie. S3).
|
*/
'meta_as_content' => false,

/*
|--------------------------------------------------------------------------
| Focal Point Editor
Expand Down
1 change: 1 addition & 0 deletions config/stache.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@

'assets' => [
'class' => Stores\AssetsStore::class,
'directory' => base_path('content/assets'),
],

'users' => [
Expand Down
54 changes: 46 additions & 8 deletions src/Assets/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
use Statamic\Facades;
use Statamic\Facades\AssetContainer as AssetContainerAPI;
use Statamic\Facades\Blink;
use Statamic\Facades\File;
use Statamic\Facades\Image;
use Statamic\Facades\Path;
use Statamic\Facades\Stache;
use Statamic\Facades\URL;
use Statamic\Facades\YAML;
use Statamic\GraphQL\ResolvesValues;
Expand Down Expand Up @@ -256,8 +258,13 @@ public function meta($key = null)
}

return $this->meta = $this->cacheStore()->rememberForever($this->metaCacheKey(), function () {
if ($contents = $this->disk()->get($path = $this->metaPath())) {
return YAML::file($path)->parse($contents);
$contents = match (config('statamic.assets.meta_as_content')) {
true => File::get($this->metaPath()),
false => $this->disk()->get($this->metaPath()),
};

if ($contents) {
return YAML::parse($contents);
}

$this->writeMeta($meta = $this->generateMeta());
Expand Down Expand Up @@ -303,13 +310,30 @@ public function generateMeta()

public function metaPath()
{
$path = dirname($this->path()).'/.meta/'.$this->basename().'.yaml';

return (string) Str::of($path)->replaceFirst('./', '')->ltrim('/');
return Str::of($this->path())
->dirname()
->finish('/') // Sometimes the dirname is just '.', so we ensure it ends with a slash
->replaceFirst('./', '')
->explode('/')
->when(
config('statamic.assets.meta_as_content'),
fn ($path) => collect([
Stache::store('assets')->directory(),
$this->container()->handle(),
])->concat($path),
fn ($path) => $path->push('.meta'),
)
->push($this->basename().'.yaml')
->filter() // Remove any empty segments
->implode('/');
}

protected function metaExists()
{
if (config('statamic.assets.meta_as_content')) {
return File::exists($this->metaPath());
}

return $this->container()->metaFiles()->contains($this->metaPath());
}

Expand All @@ -319,7 +343,12 @@ public function writeMeta($meta)

$contents = YAML::dump($meta);

$this->disk()->put($this->metaPath(), $contents);
if (config('statamic.assets.meta_as_content')) {
File::makeDirectory(dirname($this->metaPath()), 0755, true);
File::put($this->metaPath(), $contents);
} else {
$this->disk()->put($this->metaPath(), $contents);
}
}

public function metaCacheKey()
Expand Down Expand Up @@ -677,7 +706,12 @@ public function delete()
}

$this->disk()->delete($this->path());
$this->disk()->delete($this->metaPath());

if (config('statamic.assets.meta_as_content')) {
File::delete($this->metaPath());
} else {
$this->disk()->delete($this->metaPath());
}

Facades\Asset::delete($this);

Expand Down Expand Up @@ -771,7 +805,11 @@ public function move($folder, $filename = null)
$this->path($newPath);
$this->save();

$this->disk()->rename($oldMetaPath, $this->metaPath());
if (config('statamic.assets.meta_as_content')) {
File::move($oldMetaPath, $this->metaPath());
} else {
$this->disk()->rename($oldMetaPath, $this->metaPath());
}

return $this;
}
Expand Down
54 changes: 54 additions & 0 deletions tests/Assets/AssetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use Statamic\Facades;
use Statamic\Facades\Antlers;
use Statamic\Facades\File;
use Statamic\Facades\Stache;
use Statamic\Facades\YAML;
use Statamic\Fields\Blueprint;
use Statamic\Fields\Fieldtype;
Expand Down Expand Up @@ -709,6 +710,29 @@ public function it_gets_existing_meta_data()
$this->assertEquals($expected, Cache::get($asset->metaCacheKey()));
}

#[Test]
public function it_gets_existing_meta_data_as_content()
{
config()->set('statamic.assets.meta_as_content', true);
$relativePath = 'foo/test.txt';
$metaFilePath = Stache::store('assets')->directory()."/test/{$relativePath}.yaml";

Storage::fake('test');
Storage::disk('test')->put($relativePath, '');

File::makeDirectory(dirname($metaFilePath), 0755, true);
File::put($metaFilePath, YAML::dump($data = [
'data' => ['foo' => 'bar'],
'size' => 123,
]));

$container = tap(Facades\AssetContainer::make('test')->disk('test'))->save();
$asset = (new Asset)->container($container)->path($relativePath);

$this->assertEquals($metaFilePath, $asset->metaPath());
$this->assertEquals($data, $asset->meta());
}

#[Test]
public function it_properly_merges_new_unsaved_data_to_meta()
{
Expand Down Expand Up @@ -1238,6 +1262,36 @@ public function it_doesnt_lowercase_moved_files_when_configured()
], $container->assets('/', true)->map->path()->all());
}

#[Test]
public function it_can_be_moved_to_another_folder_and_renamed_when_meta_as_content()
{
config()->set('statamic.assets.meta_as_content', true);

Storage::fake('test');
$disk = Storage::disk('test');
$disk->put('old/asset.txt', 'The asset contents');

$container = tap(Facades\AssetContainer::make('test')->disk('test'))->save();
$asset = tap($container->makeAsset('old/asset.txt')->data(['foo' => 'bar']))->save();
$meta = $asset->meta();

$metaPath = Stache::store('assets')->directory().'/'.$container->handle();

$this->assertFileExists("{$metaPath}/old/asset.txt.yaml");
$this->assertEquals(YAML::dump($asset->meta()), File::get("{$metaPath}/old/asset.txt.yaml"));
$this->assertEquals(['old/asset.txt'], $container->files()->all());

$return = $asset->move('new', 'asset2');

$this->assertEquals($return, $asset);
$disk->assertMissing('old/asset.txt');
$this->assertFileDoesNotExist("{$metaPath}/old/asset.txt.yaml");
$disk->assertExists('new/asset2.txt');
$this->assertFileExists($newMetaPath = "{$metaPath}/new/asset2.txt.yaml");
$this->assertEquals(YAML::dump($meta), File::get($newMetaPath));
$this->assertEquals(['new/asset2.txt'], $container->files()->all());
}

#[Test]
public function it_renames()
{
Expand Down
1 change: 1 addition & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ protected function getEnvironmentSetUp($app)
$app['config']->set('statamic.stache.stores.globals.directory', __DIR__.'/__fixtures__/content/globals');
$app['config']->set('statamic.stache.stores.global-variables.directory', __DIR__.'/__fixtures__/content/globals');
$app['config']->set('statamic.stache.stores.asset-containers.directory', __DIR__.'/__fixtures__/content/assets');
$app['config']->set('statamic.stache.stores.assets.directory', __DIR__.'/__fixtures__/content/assets');
$app['config']->set('statamic.stache.stores.nav-trees.directory', __DIR__.'/__fixtures__/content/structures/navigation');
$app['config']->set('statamic.stache.stores.collection-trees.directory', __DIR__.'/__fixtures__/content/structures/collections');
$app['config']->set('statamic.stache.stores.form-submissions.directory', __DIR__.'/__fixtures__/content/submissions');
Expand Down