Storages
There are many types of file storages supported such as regular file system, asset saved in database, S3 and so forth. It's also possible to extend this list.
To configure the storages of your solution you should configure the bundle parameter ems_common.storages (or via the environment (.env) EMS_STORAGES variable if you are using elasticms or the skeleton). This variable must contain a JSON array listing all storage services that you want ordered. I.e.:
EMS_STORAGES='[{"type":"fs","path":"./var/assets"},{"type":"fs","path":"./var/assets2"}]'All items must at least contain a type attribute. This attribute specifies the type of the storage adapter to instanciate.
The other attributes depend on the type of service chosen.
Priorities and usages
Read priorities
When the system is looking for a file, based on a hash, the system is looking to the adapters in their order in the EMS_STORAGES environment variable. You should think about this when you are defining your storage services. In terms of storage's performances and probablity to find files by sources.
Write usages
Each storage adapter can be defined with a usage attribute. This attribute can have one of the following option:
cache: refers to files generated by the storage managerconfig: refers to files generated by theems_asset_pathasset: refers to files uploaded in the admin interfacebackup: refers to files synchronized by the ems:asset:synchronize` commandexternal: refers to files handled by an external data source. I.e. the S3 admin storage from a skeleton.
So, if a want to upload an asset, it will be saved on cache, config and cache storages, And config will be saved on cache and config storages. Externals storages act like a read-only storage.
For a regular website (1 elasticms and 1 skeleton) a best practice is to defined 4 storages:
- A
configstorage for the skeleton : typically in an empty directory or in the docker images. Asconfigandcachefiles doesn't have to be persisted. - A
configstorage for the admin : typically in an empty directory or in the docker images. Asconfigandcachefiles doesn't have to be persisted. - An S3 bucket:
- with the attribute
externalin the skeleton config - with the attribute
assetin the elasticms config
- with the attribute
- A SFTP
backupin the elasticms config and schedule aems:asset:synchronize
With this configuration you won't fill you storages with useless files.
If you have a performant enough backup storage, you can just define it as asset. No need to schedule the ems:asset:synchronize commend. But a backup storage should never be configured as external (i.e. on a Skeleton).
Hot synchronize limit
An hot-synchronize-limit attribute can be specified. It's a file size attribute (10M,1G) that force synchronize missing assets (smaller than the limit) on more prioritized storage services. It's useful if you intend to use a volatile storage with high performances or if you interconnect environments or in development combine with a http storage service.
Cleaning useless assets
With the time the size of your storages can increase. For security reason, it's not possible to cleaned them from the application. But, there is a procedure.
With the EMSCoreBundle command ems:asset:clean you can remove from the database all files references that are not used by at least one revision. Typically, it cleans files that have been uploaded in a document but the or document has never been finalized, or the file has been replaced.
Now if you define a new storage you'll be able to synchronize it with ems:asset:synchronize. This command is only synchronizing the referenced files.
Finally, it's time to remove your old storage from the EMS_STORAGES config. And, if you are sure this storage isn't used by another elasticms, you can drop it.
Existing type of storages services
File system
This service can be instantiated as many as you want and will use a regular folder to save/read assets.
type(mandatory):"fs"usageDefault value:"cache"path(mandatory): Path where to save assets
Example:
[{ 'type': 'fs', 'path': '/var/lib/ems' }]Entity
This will save/read assets in the default relational database.
type(mandatory):"db"usageDefault value:"config"usageDefault value:"cache"
Example:
[{ 'type': 'db' }]HTTP
They will instantiate an HTTP service to read/save assets, typically an elasticms.
type(mandatory):"http"base-url(mandatory): The base url (with scheme, protocol, ...) of your service i.e.http://my-website.eu/adminget-url(optional): the relative url where to get asset by with a file's hash. Default value/public/file/auth-key(optional): the authentication key to use in order to save asset. If not define the service will be read only.usageDefault value:"backup",externalif theauth-keyis not defined
Example:
[{ 'type': 'http', 'base-url': 'http://my-website.eu/admin', 'auth-key': 'MY-AUTH-KEY' }]S3
The will instantiate a S3 client service to read/save assets in a S3 (or a s3-like i.e. minio) bucket. .
type(mandatory):"s3"credentials(mandatory): S3 credential objectbucket(mandatory): Name of the bucket to useusageDefault value:"cache"multipart-uploadDefault valuetruefalse: The S3 multipart upload API is not used: the uploads are resumable but slowtrue: Activate the S3 multipart upload API: the uploads are fast but not resumable
upload-folderDeprecated option
Example:
[
{
'type': 's3',
'bucket': 'mybucket',
'credentials':
{
'version': '2006-03-01',
'credentials': { 'key': 'accesskey', 'secret': 'secretkey' },
'region': 'us-east-1',
'endpoint': 'http://localhost:9000',
'use_path_style_endpoint': true
}
}
]SFTP
They will instantiate a SFTP client service to read/save assets on an SSH server. See the PHP ssh2_auth_pubkey_file function documentation.
type(mandatory):"s3".host(mandatory): Host name or IP.path(mandatory): Path to locate assets.username(mandatory): User's login.public-key-file(mandatory): Path to a public key. The public key file needs to be in OpenSSH's format. It should look something like:ssh-rsa AAAAB3NzaC1yc2EAAA....NX6sqSnHA8= rsa-key-20121110private-key-file(mandatory): Path to a private key.password-phrase(optional): Ifprivate-key-fileis encrypted, the passphrase must be provided.usageDefault value:"backup"
Example:
[
{
'type': 'sftp',
'host': 'my-server.local',
'path': '/var/lib/ems',
'username': 'user',
'public-key-file': '/home/user/.ssh/id_rsa',
'private-key-file': '/home/user/.ssh/id_rsa.pub',
'password-phrase': 'my-secret-key'
}
]Extend with a specific storage type
If you want to implement your own storage service here is a quick tutorial.
Register a Symfony service implementing the EMS\CommonBundle\Storage\Factory\StorageFactoryInterface interface. The service must be tagged with ems_common.storage.factory:
<service id="app.storage.ftp_factory" class="App\Storage\FtpFactory">
<argument type="service" id="logger" />
<tag name="`ems_common.storage.factory`" alias="ftp"/>
</service>This interface has 2 function to implement:
public function createService(array $parameters): ?StorageInterface;: This should return an instance of a class implementing theEMS\CommonBundle\Storage\Service\StorageInterfacepublic function getStorageType(): string;: this function should just return the string that you want to register as type for your storage service. I.e.ftp.
