Skip to content

Commit

Permalink
NEW Use natural paths for public files to support permalinks (#223)
Browse files Browse the repository at this point in the history
* NEW Use natural paths for public files to support permalinks.
* API Define a FileResolutionStrategy, FileIDHelper and ParsedFileID API.
  • Loading branch information
maxime-rainville authored Apr 23, 2019
1 parent 7b0f1e2 commit bb0ae72
Show file tree
Hide file tree
Showing 38 changed files with 4,083 additions and 571 deletions.
8 changes: 8 additions & 0 deletions .upgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ warnings:
'SilverStripe\Assets\Image::AssetLibraryThumbnail()':
message: 'Renamed to CMSThumbnail()'
replacement: 'CMSThumbnail'
'SilverStripe\Assets\Flysystem\FlysystemAssetStore->parseFileID()':
message: 'Replaced with getDefaultFileIDHelper()->parseFileID()'
'SilverStripe\Assets\Flysystem\FlysystemAssetStore->getFileID()':
message: 'Replace with getDefaultFileIDHelper()->buildFileID()'
'SilverStripe\Assets\Flysystem\FlysystemAssetStore->getOriginalFilename()':
message: 'Replace with getDefaultFileIDHelper()->parseFileID()->getFilename()'
'SilverStripe\Assets\Flysystem\FlysystemAssetStore->getVariant()':
message: 'Replace with getDefaultFileIDHelper()->parseFileID()->getVariant()'
renameWarnings:
- File
- Image
19 changes: 19 additions & 0 deletions _config/asset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ SilverStripe\Core\Injector\Injector:
FilesystemAdapter: '%$SilverStripe\Assets\Flysystem\ProtectedAdapter'
FilesystemConfig:
visibility: private
# Define public resolution strategy
SilverStripe\Assets\FilenameParsing\FileResolutionStrategy.public:
class: SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy
properties:
ResolutionFileIDHelpers:
- '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
- '%$SilverStripe\Assets\FilenameParsing\NaturalFileIDHelper'
- '%$SilverStripe\Assets\FilenameParsing\LegacyFileIDHelper'
DefaultFileIDHelper: '%$SilverStripe\Assets\FilenameParsing\NaturalFileIDHelper'
VersionedStage: Live
# Define protected resolution strategy
SilverStripe\Assets\FilenameParsing\FileResolutionStrategy.protected:
class: SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy
properties:
DefaultFileIDHelper: '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
ResolutionFileIDHelpers:
- '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
- '%$SilverStripe\Assets\FilenameParsing\NaturalFileIDHelper'
VersionedStage: Stage
---
Name: assetscore
---
Expand Down
39 changes: 33 additions & 6 deletions src/AssetControlExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,22 @@ protected function processManipulation(AssetManipulationList $manipulations)
// When deleting from stage then check if we should archive assets
$archive = $this->owner->config()->get('keep_archived_assets');

// Publish assets
$this->publishAll($manipulations->getPublicAssets());

// Protect assets
$this->protectAll($manipulations->getProtectedAssets());

// Check deletion policy
$deletedAssets = $manipulations->getDeletedAssets();
if ($archive && $this->isVersioned()) {
// Publish assets
$this->swapAll($manipulations->getPublicAssets());
// Archived assets are kept protected
$this->protectAll($deletedAssets);
} else {
// Publish assets
$this->publishAll($manipulations->getPublicAssets());
// Otherwise remove all assets
$this->deleteAll($deletedAssets);
}

// Protect assets
$this->protectAll($manipulations->getProtectedAssets());
}

/**
Expand Down Expand Up @@ -268,6 +269,32 @@ protected function deleteAll($assets)
}
}

/**
* Move all assets in the list to the public store
*
* @param array $assets
*/
protected function swapAll($assets)
{
if (empty($assets)) {
return;
}

$store = $this->getAssetStore();

// The `swap` method was introduced in the 1.4 release. It wasn't added to the interface to avoid breaking
// custom implementations. If it's not available on our store, we fall back to a publish/protect
if (method_exists($store, 'swapPublish')) {
foreach ($assets as $asset) {
$store->swapPublish($asset['Filename'], $asset['Hash']);
}
} else {
foreach ($assets as $asset) {
$store->publish($asset['Filename'], $asset['Hash']);
}
}
}

/**
* Move all assets in the list to the public store
*
Expand Down
10 changes: 10 additions & 0 deletions src/Dev/TestAssetStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use League\Flysystem\Adapter\Local;
use League\Flysystem\AdapterInterface;
use League\Flysystem\Filesystem;
use SilverStripe\Assets\FilenameParsing\FileResolutionStrategy;
use SilverStripe\Assets\Filesystem as SSFilesystem;
use SilverStripe\Assets\Flysystem\FlysystemAssetStore;
use SilverStripe\Assets\Flysystem\ProtectedAssetAdapter;
Expand Down Expand Up @@ -76,6 +77,8 @@ public static function activate($basedir)
$backend = new TestAssetStore();
$backend->setPublicFilesystem($publicFilesystem);
$backend->setProtectedFilesystem($protectedFilesystem);
$backend->setPublicResolutionStrategy(Injector::inst()->get(FileResolutionStrategy::class . '.public'));
$backend->setProtectedResolutionStrategy(Injector::inst()->get(FileResolutionStrategy::class . '.protected'));
Injector::inst()->registerService($backend, AssetStore::class);
Injector::inst()->registerService($backend, AssetStoreRouter::class);

Expand Down Expand Up @@ -174,6 +177,11 @@ public function getOriginalFilename($fileID)
return parent::getOriginalFilename($fileID);
}

public function getFilesystemFor($fileID)
{
return parent::getFilesystemFor($fileID);
}

public function removeVariant($fileID)
{
return parent::removeVariant($fileID);
Expand All @@ -187,6 +195,8 @@ public function getDefaultConflictResolution($variant)
protected function isSeekableStream($stream)
{
if (isset(self::$seekable_override)) {
// Unset the override so we don't get stuck in an infinite loop
self::$seekable_override = null;
return self::$seekable_override;
}
return parent::isSeekableStream($stream);
Expand Down
55 changes: 55 additions & 0 deletions src/FilenameParsing/FileIDHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace SilverStripe\Assets\FilenameParsing;

/**
* Helps build and parse Filename Identifiers (ake: FileIDs) according to a predefined format.
*
* @internal This is still an evolving API. It may change in the next minor release.
*/
interface FileIDHelper
{

/**
* Map file tuple (hash, name, variant) to a filename to be used by flysystem
*
* @param string|ParsedFileID $filename Name of file or ParsedFileID object
* @param string $hash Hash of original file
* @param string $variant (if given)
* @return string Adapter specific identifier for this file/version
*/
public function buildFileID($filename, $hash = null, $variant = null);


/**
* Clean up filename to remove constructs that might clash with the underlying path format of this FileIDHelper.
*
* @param string $filename
* @return string
*/
public function cleanFilename($filename);

/**
* Get Filename, Variant and Hash from a fileID. If a FileID can not be parsed, returns `null`.
*
* @param string $fileID
* @return ParsedFileID|null
*/
public function parseFileID($fileID);

/**
* Determine if the provided fileID is a variant of `$parsedFileID`.
* @param string $fileID
* @param ParsedFileID $parsedFileID
* @return boolean
*/
public function isVariantOf($fileID, ParsedFileID $parsedFileID);

/**
* Compute the relative path where variants of the provided parsed file ID are expected to be stored.
*
* @param ParsedFileID $parsedFileID
* @return string
*/
public function lookForVariantIn(ParsedFileID $parsedFileID);
}
Loading

0 comments on commit bb0ae72

Please sign in to comment.