diff --git a/docs/en/02_Developer_Guides/14_Files/01_File_Management.md b/docs/en/02_Developer_Guides/14_Files/01_File_Management.md index 2ec92a276..460d09a34 100644 --- a/docs/en/02_Developer_Guides/14_Files/01_File_Management.md +++ b/docs/en/02_Developer_Guides/14_Files/01_File_Management.md @@ -1,90 +1,98 @@ +title: File management summary: Learn how to work with File and Image records -# File Management +# File management -## Storage via database columns +## Asset admin -Asset storage is provided out of the box via a [Flysystem](http://flysystem.thephpleague.com/) backed store. -However, any class that implements the `AssetStore` interface could be substituted to provide storage backends -via other mechanisms. +Management of files within the CMS is provided via the [silverstripe/asset-admin](https://github.com/silverstripe/silverstripe-asset-admin) +module. This is a rich and user friendly interface supporting most basic file operations, as well as +control over the publishing and security of files. -Internally, files are stored as `[DBFile](api:SilverStripe\Assets\Storage\DBFile)` records on the rows of parent objects. These records are composite fields -which contain sufficient information useful to the configured asset backend in order to store, manage, and -publish files. By default this composite field behind this field stores the following details: +![asset admin](_images/asset-admin-demo.png) +## UploadField -| Field name | Description | -| ---------- | ----------- -| `Hash` | The sha1 of the file content, useful for versioning (if supported by the backend) | -| `Filename` | The internal identifier for this file, which may contain a directory path (not including assets). Multiple versions of the same file will have the same filename. | -| `Variant` | The variant for this file. If a file has multiple derived versions (such as resized files or reformatted documents) then you can point to one of the variants here. | +If you have the [silverstripe/asset-admin](https://github.com/silverstripe/silverstripe-asset-admin) +module installed then this provides a powerful component [api:SilverStripe\AssetAdmin\Forms\UploadField]. +![upload field](_images/upload-field.png) -Note that the `Hash` and `Filename` always point to the original file, if a `Variant` is specified. It is up to the -storage backend to determine how variants are managed. +You can add it to a page as below: -Note that the storage backend used will not be automatically synchronised with the database. Only files which -are loaded into the backend through the asset API will be available for use within a site. - -## Compatibility with 3.x filename paths - -If upgrading to 4.0 from earlier versions when using the default asset store, it's important to consider -how existing files will be migrated. - -Because the filesystem now uses the sha1 of file contents in order to version multiple versions under the same -filename, the default storage paths in 4.0 will not be the same as in 3. - -In order to retain existing file paths in line with framework version 3 you should set the -`\SilverStripe\Assets\Flysystem\FlysystemAssetStore.legacy_filenames` config to true. -Note that this will not allow you to utilise certain file versioning features in 4.0. - - -```yaml - - \SilverStripe\Assets\Flysystem\FlysystemAssetStore: - legacy_filenames: true -``` - -## Loading content into `DBFile` - -A file can be written to the backend from a file which exists on the local filesystem (but not necessarily -within the assets folder). - -For example, to load a temporary file into a DataObject you could use the below: ```php - use SilverStripe\ORM\DataObject; + Image::class, + ]; + + public function getCMSFields() { - private static $db = [ - 'Image' => 'DBFile' - ]; + $fields = parent::getCMSFields(); + $fields->addFieldToTab('Root.Main', UploadField::create('Banner', 'Page Banner'), 'Content'); + return $fields; } - - // Image could be assigned in other parts of the code using the below - $banner = new Banner(); - $banner->Image->setFromLocalFile($tempfile['path'], 'uploads/banner-file.jpg'); - +} ``` -When uploading a file it's normally necessary to give the file a useful name and directory, otherwise the -asset storage backend will choose one for you. +UploadField options include: -Alternatively, content can be loaded using one of the below methods: + - setIsMultiUpload() - Set to allow many files per field, or one only. + - setAllowedExtensions() - Set list of extensionse this field can accept. + - setAllowedFileCategories() - Alternatively specify allowed extensions via category instead. + - setFolderName() - Name of folder to upload into + - getValidator() - Get instance of validator to specify custom validation rules + +## File visibility + +In order to ensure that assets are made public you should check the following: + + - The "Who can view this file?" option is set to "Anyone" or "Inherit" in the asset-admin. This can be checked + via `File::canView()` or `File::$CanViewType` property. + - The file is published, or is owned by a published record. This can be checked via `File::isPublished()` + - The file exists on disk, and has not been removed. This can be checked by `File::exists()` + +## File shortcodes + +Shortcodes represent an embeded asset within a block of HTML text. For instance, this is the content +of a page with a shortcode image: + +```html +

Welcome to SilverStripe! This is the default homepage.

+

[image src="/assets/e43fb87dc0/12824172.jpeg" id="27" width="400" height="400" class="leftAlone ss-htmleditorfield-file image" title="My Image"]

+``` + +File shortcodes have the following properties: + + - canView() will not be checked for the file itself: Instead this will be inherited from the parent record + this is embedded within. + - The file is automatically "owned", meaning that publishing the page will also publish the embedded file. + +Within the CMS shortcodes can be added via either the "Insert Media" modal, or the "Link to a file" +buttons provided via the [silverstripe/asset-admin](https://github.com/silverstripe/silverstripe-asset-admin) +module. + +## Creating files in PHP + +When working with files in PHP you can upload a file into a [api:SilverStripe\Assets\File] dataobject +using one of the below methods: | Method | Description | | -------------------------- | --------------------------------------- | -| `DBFile::setFromLocalFile` | Load a local file into the asset store | -| `DBFile::setFromStream` | Will store content from a stream | -| `DBFile::setFromString` | Will store content from a binary string | +| `File::setFromLocalFile` | Load a local file into the asset store | +| `File::setFromStream` | Will store content from a stream | +| `File::setFromString` | Will store content from a binary string | -The result of these methods will be an array of data (tuple) which contains the values of the above fields -(Filename, Hash, and Variant). - -## Conflict resolution +### Upload conflict resolution When storing files, it's possible to determine the mechanism the backend should use when it encounters an existing file pattern. The conflict resolution to use can be passed into the third parameter of the @@ -97,69 +105,98 @@ above methods (after content and filename). The available constants are: | `AssetStore::CONFLICT_RENAME` | The backend will choose a new name. | | `AssetStore::CONFLICT_USE_EXISTING` | The existing file will be used | - If no conflict resolution scheme is chosen, or an unsupported one is requested, then the backend will choose one. The default asset store supports each of these. -## Getting content from a `DBFile` - -When placed into a template (e.g. `$MyFileField`) then `[DBFile](api:SilverStripe\Assets\Storage\DBFile)` will automatically generate the appropriate -template for the file mime type. For images, this will embed an image tag. For documents a download link will be presented. +## Accessing files via PHP As with storage, there are also different ways of loading the content (or properties) of the file: | Method | Description | | ------------------------ | ---------------------------------------------------------- | -| `DBFile::getStream` | Will get an output stream of the file content | -| `DBFile::getString` | Gets the binary content | -| `DBFile::getURL` | Gets the url for this resource. May or may not be absolute | -| `DBFile::getAbsoluteURL` | Gets the absolute URL to this resource | -| `DBFile::getMimeType` | Get the mime type of this file | -| `DBFile::getMetaData` | Gets other metadata from the file as an array | +| `File::getStream` | Will get an output stream of the file content | +| `File::getString` | Gets the binary content | +| `File::getURL` | Gets the url for this resource. May or may not be absolute | +| `File::getAbsoluteURL` | Gets the absolute URL to this resource | +| `File::getMimeType` | Get the mime type of this file | +| `File::getMetaData` | Gets other metadata from the file as an array | + +## Modifying files + +In order to move or rename a file you can simply update the Name property, or assign the ParentID to a new +folder. Please note that these modifications are made simply on the draft stage, and will not be copied +to live until a publish is made (either on this object, or cascading from a parent). + +When files are renamed using the ORM, all file variants are automatically renamed at the same time. + +```php +$file = File::get()->filter('Name', 'oldname.jpg')->first(); +if ($file) { + // The below will move 'oldname.jpg' and 'oldname__variant.jpg' + // to 'newname.jpg' and 'newname__variant.jpg' respectively + $file->Name = 'newname.jpg'; + $file->write(); +} +``` + +## File versioning + +File versioning is extended with the [silverstripe/versioned](https://github.com/silverstripe/silverstripe-versioned/) +module, which provides not only a separate draft and live stages for any file, but also allows a complete file +history of modifications to be tracked. + +To support this feature the [api:SilverStripe\Assets\AssetControlExtension] provides support for tracking +references to physical files, ensuring published assets are accessible, protecting non-published assets, +and archiving / deleting assets after the final reference has been deleted. + +### Configuring file ownership + +When working with files attached to other versioned dataobjects it is necessary to configure ownership +of these assets from the parent record. This ensures that whenever a Page (or other record type) +is published, all assets that are used by this record are published with it. + +For example: + +```php + Image::class, + ]; + private static $owns = ['Banner']; +} +``` + +### Avoid exclusive relationships + +Due to the shared nature of assets, it is not recommended to assign any 1-to-many (or exclusive 1-to-1) relationship +between any objects and a File. E.g. a Page has_many File, or Page belongs_to File. -As with other db field types, `DBField` can also be subclassed or extended to add additional properties -(such as SEO related fields). +Instead it is recommended to use either a Page has_one File for many-to-1 (or 1-to-1) relationships, or +Page many_many File for many-to-many relationships. -## Storage via `File` DataObject +### Unpublishing assets -Other than files stored exclusively via DBFile, files can also exist as subclasses of the `File` DataObject. +Assets can be unpublished on a case by case basis via the asset admin section. Please note that +when unpublishing an asset, this will remove this asset from all live pages which currently link to +or embed those images. -Each record has the following database fields: +### Configuring file archiving -| Field name | Description | -| ---------- | ----------- | -| `ClassName` | The class name of the file (e.g. File, Image or Folder). | -| `Name` | The 'basename' of the file, or the folder name. For example 'my-image.jpg', or 'images' for a folder. | -| `Title` | The optional, human-readable title of the file for display only (doesn't apply to folders). | -| `File` | The `[DBFile](api:SilverStripe\Assets\Storage\DBFile)` field (see above) which stores the underlying asset content. | -| `ShowInSearch` | Whether the file should be shown in search results, defaults to '1'. See ["Tutorial 4 - Site Search"](/tutorials/site_search) for enabling search. | -| `ParentID` | The ID of the parent Folder that this File/Folder is in. A ParentID of '0' indicates that this is a top level record. | -| `OwnerID` | The ID of the Member that 'owns' the File/Folder (not related to filesystem permissions). | +By default files which do not exist on either the live or draft stage (but do have a version history) +are removed from the filesystem. +In order to permanantly keep a record of all past physical files you can set the `File.keep_archived_assets` +config option to true. This will ensure that historic files can always be restored, albeit at a cost to disk +storage. -## Management through the "Files" section of the CMS - -If you have the CMS module installed, you can manage files, folders and images in the "Files" section of the CMS. Inside this section, you will see a list of files and folders like below: - -![](../../_images/assets.png) - -You can click on any file to edit it, or click on any folder to open it. To delete a file or a folder, simply click the red 'X' symbol next to it. If you click to open a folder, you can go back up one level by clicking the 'up' arrow above the folder name (highlighted below): - -![](../../_images/assets_up.png) - -Once you click to edit a file, you will see a form similar to the one below, in which you can edit the file's title, filename, owner, or even change which folder the file is located in: - -![](../../_images/assets_editform.png) - -You may also notice the 'Sync files' button (highlighted below). This button allows CMS users to 'synchronise' the database (remember, all files/folders are stored as database records) with the filesystem. This is particularly useful if someone has uploaded or removed files/folders via FTP, for example. - -![](../../_images/assets_sync.png) - -## Upload - -Files can be managed through forms in one way: - - * [FileField](api:SilverStripe\Forms\FileField): provides a simple HTML input with a type of "file". - -_NOTE_: Modules are also available to handle Files. +```yaml +SilverStripe\Assets\File: + keep_archived_assets: true +``` diff --git a/docs/en/02_Developer_Guides/14_Files/03_File_Security.md b/docs/en/02_Developer_Guides/14_Files/03_File_Security.md index a5795a7f6..e49087457 100644 --- a/docs/en/02_Developer_Guides/14_Files/03_File_Security.md +++ b/docs/en/02_Developer_Guides/14_Files/03_File_Security.md @@ -18,13 +18,11 @@ For instance, in order to write an asset to a protected location you can use the config option: - ```php - $store = singleton(AssetStore::class); - $store->setFromString('My protected content', 'Documents/Mydocument.txt', null, null, [ - 'visibility' => AssetStore::VISIBILITY_PROTECTED - ]); - +$store = singleton(AssetStore::class); +$store->setFromString('My protected content', 'Documents/Mydocument.txt', null, null, [ + 'visibility' => AssetStore::VISIBILITY_PROTECTED +]); ``` ## User access control @@ -40,16 +38,15 @@ control access to embedded assets at a template level. ```ss - - + ``` Users who are able to guess the value of $URL will not be able to access those urls without being @@ -65,21 +62,21 @@ authorised users, the following should be considered: ```php - use SilverStripe\CMS\Controllers\ContentController; +use SilverStripe\CMS\Controllers\ContentController; - class PageController extends ContentController - { - public function init() - { - parent::init(); - // Whitelist any protected files on this page for the current user - foreach($this->Files() as $file) { - if($file->canView()) { - $file->grantFile(); - } - } +class PageController extends ContentController +{ + public function init() + { + parent::init(); + + // Whitelist the protected files on this page for the current user + $file = $this->File(); + if($file->canView()) { + $file->grantFile(); } } +} ``` * If a user does not have access to a file, you can still generate the URL but suppress the default @@ -87,37 +84,35 @@ authorised users, the following should be considered: (or '0' in template as a workaround for all parameters being cast as string) - ::php - <% if not $canView %> - -
  • Access to $Title is denied
  • - <% else %> - +```php +<% if not $canView %> + +
  • Access to $Title is denied
  • +<% else %> +``` * Alternatively, if a user has already been granted access, you can explicitly revoke their access using the `revokeFile` method. - - ```php - use SilverStripe\CMS\Controllers\ContentController; +use SilverStripe\CMS\Controllers\ContentController; - class PageController extends ContentController - { - public function init() - { - parent::init(); - // Whitelist any protected files on this page for the current user - foreach($this->Files() as $file) { - if($file->canView()) { - $file->grantFile(); - } else { - // Will revoke any historical grants - $file->revokeFile(); - } - } +class PageController extends ContentController +{ + public function init() + { + parent::init(); + + // Whitelist the protected files on this page for the current user + $file = $this->File(); + if($file->canView()) { + $file->grantFile(); + } else { + // Will revoke any historical grants + $file->revokeFile(); } } +} ``` ## Controlling asset visibility @@ -133,25 +128,20 @@ public facing area. E.g. - - ```php - $object->MyFile->setFromLocalFile($tmpFile['Path'], $filename, null, null, [ - 'visibility' => AssetStore::VISIBILITY_PROTECTED - ]); - +$object->MyFile->setFromLocalFile($tmpFile['Path'], $filename, null, null, [ + 'visibility' => AssetStore::VISIBILITY_PROTECTED +]); ``` You can also adjust the visibility of any existing file to either public or protected. - - ```php - // This will make the file available only when a user calls `->grant()` - $object->SecretFile->protectFile(); - - // This file will be available to everyone with the URL - $object->PublicFile->publishFile(); +// This will make the file available only when a user calls `->grant()` +$object->SecretFile->protectFile(); + +// This file will be available to everyone with the URL +$object->PublicFile->publishFile(); ```
    @@ -177,14 +167,14 @@ Internally your folder structure would look something like: ``` - assets/ +assets/ + .htaccess + .protected/ .htaccess - .protected/ - .htaccess - a870de278b/ - NewCompanyLogo.gif - 33be1b95cb/ - OldCompanyLogo.gif + a870de278b/ + NewCompanyLogo.gif + 33be1b95cb/ + OldCompanyLogo.gif ``` The urls for these two files, however, do not reflect the physical structure directly. @@ -199,25 +189,22 @@ When the file `NewCompanyLogo.gif` is made public, the url will not change, but will be moved to `assets/a870de278b/NewCompanyLogo.gif`, and will be served directly via the web server, bypassing the need for additional PHP requests. - - ```php - $store = singleton(AssetStore::class); - $store->publish('NewCompanyLogo.gif', 'a870de278b475cb75f5d9f451439b2d378e13af1'); +$store = singleton(AssetStore::class); +$store->publish('NewCompanyLogo.gif', 'a870de278b475cb75f5d9f451439b2d378e13af1'); ``` After this the filesystem will now look like below: - ``` - assets/ +assets/ + .htaccess + .protected/ .htaccess - .protected/ - .htaccess - 33be1b95cb/ - OldCompanyLogo.gif - a870de278b/ - NewCompanyLogo.gif + 33be1b95cb/ + OldCompanyLogo.gif + a870de278b/ + NewCompanyLogo.gif ``` ## Performance considerations @@ -255,7 +242,7 @@ For instance, given your web root is in the folder `/sites/mysite/www`, you can to put protected files into `/sites/mysite/protected` with the below `.env` setting: ``` - SS_PROTECTED_ASSETS_PATH="/sites/mysite/protected" +SS_PROTECTED_ASSETS_PATH="/sites/mysite/protected" ``` ### Configuring: File types @@ -263,12 +250,12 @@ to put protected files into `/sites/mysite/protected` with the below `.env` sett In addition to configuring file locations, it's also important to ensure that you have allowed the appropriate file extensions for your instance. This can be done by setting the `File.allowed_extensions` config. -```yaml - File: - allowed_extensions: - - 7zip - - xzip +```yaml +SilverStripe\Assets\File: + allowed_extensions: + - 7zip + - xzip ```
    @@ -286,13 +273,10 @@ When a protected file is served it will also be transmitted with all headers def `SilverStripe\Filesystem\Flysystem\FlysystemAssetStore.file_response_headers` config. You can customise this with the below config: - - ```yaml - - SilverStripe\Filesystem\Flysystem\FlysystemAssetStore: - file_response_headers: - Pragma: 'no-cache' +SilverStripe\Filesystem\Flysystem\FlysystemAssetStore: + file_response_headers: + Pragma: 'no-cache' ``` ### Configuring: Archive behaviour @@ -314,29 +298,23 @@ This can be applied to DataObjects on a case by case basis by setting the `keep_ config to true on that class. Note that this feature only works with dataobjects with the `Versioned` extension. - - ```php - use SilverStripe\ORM\DataObject; - - class MyVersiondObject extends DataObject - { - /** Ensure assets are archived along with the DataObject */ - private static $keep_archived_assets = true; - /** Versioned */ - private static $extensions = ['Versioned']; - } +use SilverStripe\ORM\DataObject; +class MyVersiondObject extends DataObject +{ + /** Ensure assets are archived along with the DataObject */ + private static $keep_archived_assets = true; + /** Versioned */ + private static $extensions = ['Versioned']; +} ``` The extension can also be globally disabled by removing it at the root level: - - ```yaml - - DataObject: - AssetControl: null +SilverStripe\ORM\DataObject: + AssetControl: null ``` ### Configuring: Web server settings @@ -398,10 +376,9 @@ will need to make sure you manually configure these rules. For instance, this will allow your nginx site to serve files directly, while ensuring dynamic requests are processed via the Framework: - ``` - location ^~ /assets/ { - sendfile on; - try_files $uri index.php?$query_string; - } +location ^~ /assets/ { + sendfile on; + try_files $uri index.php?$query_string; +} ``` diff --git a/docs/en/02_Developer_Guides/14_Files/04_File_Storage.md b/docs/en/02_Developer_Guides/14_Files/04_File_Storage.md new file mode 100644 index 000000000..fc0b05b40 --- /dev/null +++ b/docs/en/02_Developer_Guides/14_Files/04_File_Storage.md @@ -0,0 +1,102 @@ +title: File storage +summary: Describes the persistence layer of files + +# File storage + +This section describes how the asset store abstraction layer stores the physical files underlying the ORM, +and explains some of the considerations. + +## Component Overview + +The assets module is composed of these major storage classes: + +* [api:SilverStripe\Assets\File]: This is the main DataObject that user code interacts with when working with files. + This class has the following subclasses: + - [api:SilverStripe\Assets\Folder]: Logical folder which holds a set of files. These can be nested. + - [api:SilverStripe\Assets\Image]: Specialisation of File representing an image which can be resized. + Note that this does not include non-resizable image files. +* [api:SilverStripe\Assets\Storage\DBFile]: This is the DB field used by the File dataobject internally for + storing references to physical files in the asset backend. +* [api:SilverStripe\Assets\Flysystem\FlysystemAssetStore]: The default backend, provided by + [Flysystem](https://flysystem.thephpleague.com/), which SilverStripe uses as an asset persistence layer. +* [api:SilverStripe\Assets\InterventionBackend]: Default image resizing mechanism, provided by + [intervention image](http://image.intervention.io/). + +These interfaces are also provided to abstract certain behaviour: + +* [api:SilverStripe\Assets\Storage\AssetContainer]: Abstract interface for a file reference. Implemented by both + File and DBFile. Declare API for reading to and writing an single file. +* [api:SilverStripe\Assets\Storage\AssetStore]: Abstract interface for the backend store for the asset system. + Implemented by FlysystemAssetStore. Declares API for reading and writing assets from and to the store. + +## Storage via database columns + +Asset storage is provided out of the box via a [Flysystem](http://flysystem.thephpleague.com/) backed store. +However, any class that implements the `AssetStore` interface could be substituted to provide storage backends +via other mechanisms. + +Internally, files are stored as [DBFile](api:SilverStripe\Assets\Storage\DBFile) records on the rows of parent objects. +These records are composite fields which contain sufficient information useful to the configured asset backend in order +to store, manage, and publish files. By default this composite field behind this field stores the following details: + + +| Field name | Description | +| ---------- | ----------- +| `Hash` | The sha1 of the file content, useful for versioning (if supported by the backend) | +| `Filename` | The internal identifier for this file, which may contain a directory path (not including assets). Multiple versions of the same file will have the same filename. | +| `Variant` | The variant for this file. If a file has multiple derived versions (such as resized files or reformatted documents) then you can point to one of the variants here. | + + +Note that the `Hash` and `Filename` always point to the original file, if a `Variant` is specified. It is up to the +storage backend to determine how variants are managed. + +Note that the storage backend used will not be automatically synchronised with the database. Only files which +are loaded into the backend through the asset API will be available for use within a site. + +## File paths and url mapping + +The hash, name, and filename are combined in order to build the physical location on disk. + +For instance, this is a typical disk content: + +``` +assets/ + Uploads/ + b63923d8d4/ + BannerHeader.jpg + BannerHeader__FitWzYwLDYwXQ.jpg +``` + +This corresponds to a file with the following properties: + +- Filename: Uploads/BannerHeader.jpg +- Hash: b63923d8d4089c9da16fbcbcdfef3e1b24806334 (trimmed to first 10 chars) +- Variant: FitWzYwLDYwXQ (corresponds to Fit[60,60]) + +The URL for this file will match the physical location on disk: +`http://www.mysite.com/assets/Uploads/b63923d8d4/BannerHeader__FitWzYwLDYwXQ.jpg`. + +For more information on how protected files are stored see the [file security](/developer_guides/files/file_security) +section. + +## Loading content into `DBFile` + +A file can be written to the backend from a file which exists on the local filesystem (but not necessarily +within the assets folder). + +For example, to load a temporary file into a DataObject you could use the below: + +```php +use SilverStripe\ORM\DataObject; + +class Banner extends DataObject +{ + private static $db = [ + 'Image' => 'DBFile' + ]; +} + +// Image could be assigned in other parts of the code using the below +$banner = new Banner(); +$banner->Image->setFromLocalFile($tempfile['path'], 'uploads/banner-file.jpg'); +``` diff --git a/docs/en/02_Developer_Guides/14_Files/04_File_Migration.md b/docs/en/02_Developer_Guides/14_Files/05_File_Migration.md similarity index 75% rename from docs/en/02_Developer_Guides/14_Files/04_File_Migration.md rename to docs/en/02_Developer_Guides/14_Files/05_File_Migration.md index d430de95a..2e6faf86f 100644 --- a/docs/en/02_Developer_Guides/14_Files/04_File_Migration.md +++ b/docs/en/02_Developer_Guides/14_Files/05_File_Migration.md @@ -1,7 +1,12 @@ +title: File migration summary: Manage migration of legacy files to the new database structure # File migration +This section describes how to upgrade existing filesystems from earlier versions of SilverStripe. + +## Running migration + Since the structure of `File` dataobjects has changed between 3.0 and 4.0, a new task `MigrateFileTask` has been added to assist in migration of legacy files. @@ -55,3 +60,20 @@ SilverStripe\Assets\FileMigrationHelper: Note that pre-existing security solutions for 3.x (such as [secure assets module](https://github.com/silverstripe/silverstripe-secureassets)) are incompatible with core file security. + +## Support existing paths + +Because the filesystem now uses the sha1 of file contents in order to version multiple versions under the same +filename, the default storage paths in 4.0 will not be the same as in 3. + +Although it is not recommended, it is possible to configure the backend to omit this SHA1 url segment, +meaning that file paths and urls will not be modified during the upgrade. + +This is done by setting this config: + +```yaml +SilverStripe\Assets\Flysystem\FlysystemAssetStore: + legacy_filenames: true +``` + +Note that this will not allow you to utilise certain file versioning features in 4.0. diff --git a/docs/en/02_Developer_Guides/14_Files/_images/asset-admin-demo.png b/docs/en/02_Developer_Guides/14_Files/_images/asset-admin-demo.png new file mode 100644 index 000000000..3fe1093e1 Binary files /dev/null and b/docs/en/02_Developer_Guides/14_Files/_images/asset-admin-demo.png differ diff --git a/docs/en/02_Developer_Guides/14_Files/_images/upload-field.png b/docs/en/02_Developer_Guides/14_Files/_images/upload-field.png new file mode 100644 index 000000000..75b548f06 Binary files /dev/null and b/docs/en/02_Developer_Guides/14_Files/_images/upload-field.png differ diff --git a/docs/en/02_Developer_Guides/14_Files/index.md b/docs/en/02_Developer_Guides/14_Files/index.md index c9d9afdbc..fc46c368c 100644 --- a/docs/en/02_Developer_Guides/14_Files/index.md +++ b/docs/en/02_Developer_Guides/14_Files/index.md @@ -2,6 +2,24 @@ title: Files summary: Upload, manage and manipulate files and images. introduction: Upload, manage and manipulate files and images. +# Files + +## Introduction + +File management and abstraction is provided by the [silverstripe/assets](https://github.com/silverstripe/silverstripe-assets). +This provides the basis for the storage of all non-static files and resources usable by a SilverStripe web application. + +By default the [api:SilverStripe\Assets\File] has these characteristics: + + - A default permission model based on folder hierarchy. + - Versioning of files, including the ability to draft modifications to files and subsequently publish them. + - Physical protection of both unpublished and secured files, allowing restricted access as needed. + - An abstract storage based on the [flysystem](https://flysystem.thephpleague.com/) library, which can be + substituted for any other backend. + - Can be embedded into any HTML field via shortcodes. + +# Read more + [CHILDREN] ## API Documentation diff --git a/docs/en/04_Changelogs/4.0.0.md b/docs/en/04_Changelogs/4.0.0.md index f095c8695..a7505fcc3 100644 --- a/docs/en/04_Changelogs/4.0.0.md +++ b/docs/en/04_Changelogs/4.0.0.md @@ -688,8 +688,25 @@ Those wishing to customise the CMS should read about how to All static files (images, javascript, stylesheets, fonts) used for the CMS and forms interfaces in `framework` and `cms` have moved locations. These assets are now placed in a `client/` subfolder, -to account for a structural change where both javascript and styles are co-located in component-specific folders. +which are also sub-folders of the modules which now reside in `vendor`. + This will affect you if you have used `Requirements::block()` on files in the `framework/` or `cms/` folder. + +In order to identify resources it is preferred to use the new module-root prefixed string form when +adding requirements. + +Usage in Requirements: + +```diff +-Requirements::css('framework/admin/css/styles.css'); ++Requirements::css('silverstripe/admin: client/dist/styles/bundle.css'); +``` + +The location of these resources is determined from the `name` field in the `composer.json` +for each module. `silverstripe/admin:` will be mapped to the folder `vendor/silverstripe/admin` +where this module is installed, based on the `vendor/silverstripe/admin/composer.json` name +matching the prefix in `Requirements::css()`. + Care should also be taken when referencing images in these folders from your own stylesheets (`url()`), or via SilverStripe templates (`` tags). @@ -697,21 +714,21 @@ or via SilverStripe templates (`` tags). failing silently, so check your `Requirements` are pointing to files that exist. ``` -framework/javascript => silverstripe-admin/client/dist/ -framework/javascript/lang => silverstripe-admin/client/lang/ -framework/images => silverstripe-admin/client/dist/images/ -framework/css => silverstripe-admin/client/dist/css/ -framework/scss => silverstripe-admin/client/src/styles/ -admin/javascript/ => silverstripe-admin/client/src/ -admin/javascript/src/ => silverstripe-admin/client/src/legacy/ (mostly) -admin/javascript/lang/ => silverstripe-admin/client/lang/ -admin/scss/ => silverstripe-admin/client/styles/legacy/ -admin/css/ => silverstripe-admin/client/dist/css/ -admin/css/screen.css => silverstripe-admin/client/dist/css/bundle.css -admin/images/ => silverstripe-admin/client/dist/images/ -admin/images/sprites/src/ => silverstripe-admin/client/src/sprites/ -admin/images/sprites/dist/ => silverstripe-admin/client/dist/sprites/ -admin/font/ => silverstripe-admin/client/dist/font/ +framework/javascript => silverstripe/admin:client/dist/ +framework/javascript/lang => silverstripe/admin:client/lang/ +framework/images => silverstripe/admin:client/dist/images/ +framework/css => silverstripe/admin:client/dist/css/ +framework/scss => silverstripe/admin:client/src/styles/ +admin/javascript/ => silverstripe/admin:client/src/ +admin/javascript/src/ => silverstripe/admin:client/src/legacy/ (mostly) +admin/javascript/lang/ => silverstripe/admin:client/lang/ +admin/scss/ => silverstripe/admin:client/styles/legacy/ +admin/css/ => silverstripe/admin:client/dist/css/ +admin/css/screen.css => silverstripe/admin:client/dist/css/bundle.css +admin/images/ => silverstripe/admin:client/dist/images/ +admin/images/sprites/src/ => silverstripe/admin:client/src/sprites/ +admin/images/sprites/dist/ => silverstripe/admin:client/dist/sprites/ +admin/font/ => silverstripe/admin:client/dist/font/ ``` Most JavaScript files in `framework/javascript` have been removed,