The filesystem service provides access to locally and remotely stored files using the Flysystem PHP package by Frank de Jonge. Based on Laravel Flysystem integration, UserFrosting integration provides simple to use drivers for working with local filesystems, Amazon S3, and Rackspace Cloud Storage. Even better, it's amazingly simple to switch between these storage options as the API remains the same for each system. You can even [add your own adapter] in your sprinkle if you need access to the many adapter supported by Flysystem.
UserFrosting uses disk to define storage location. A disk can represent a location where files can be found and saved. Each disk uses a particular storage driver that contains the necessary code to access your file using a standardized API. UserFrosting provides built-in configuration for three disks: local
, public
and s3
.
The local disk stores files in app/storage
. This is also the default disk. Those files are not publicly available which means you can't access any files located in the local disk by typing the correct URL in your browser. It's perfect for storing any kind of files you want to control. You can still access them from your controllers classes and methods and return them manually if you require so.
The public disk, on the other hand, store files directly in your project public folder, under public/files/
. This means any files saved in this disk will be publicly available. It's the perfect disk for user generated assets (think images), as they will be directly handled by the web server. For example, if you store a file named cats.jpg
in the public disk, you'll be able to access this image by typing https://localhost/files/cats.jpg
in your browser.
league/flysystem-aws-s3-v3
inside a custom Sprinkles composer.json
.The S3 disk provides an example configuration to access an Amazon S3 bucket from your app. Because of the sensitive information, we recommend storing your S3 credential in the app/.env
file. This will avoid committing your private keys to your git repo, for example.
Simply add the necessary entries to your app/.env
file if they don't already exist :
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
AWS_DEFAULT_REGION=""
AWS_BUCKET=""
AWS_URL=""
See Amazon S3 Support Page if you need help finding your access keys. The region code can be found here.
league/flysystem-rackspace
inside a custom Sprinkles composer.json
.The rackspace disk provides an example configuration to access rackspace storage solution. Because of the sensitive information, we recommend storing your rackspace credential in the app/.env
file.
RACKSPACE_USERNAME=""
RACKSPACE_KEY=""
RACKSPACE_CONTAINER=""
RACKSPACE_ENDPOINT=""
RACKSPACE_REGION=""
RACKSPACE_URL_TYPE=""
Of course, you may configure as many disks as you like, and may even have multiple disks that use the same driver.
To define a new disk, simply add the necessary configuration to your sprinkle configuration file :
'filesystems' => [
'disks' => [
'mySite' => [
'driver' => 'local',
'root' => \UserFrosting\STORAGE_DIR . "/_mySite"
]
]
],
The mySite
disk will point to the app/storage/_mySite
directory.
Note that you can also overwrite a default disk configuration values in your sprinkle the same way you do with other configuration values.
filesystems.default
configuration.The following drivers have built-in support in UserFrosting :
The filesystem service may be used to interact with any of your configured disks. For example, you may use the put method on the facade to store an avatar on the default disk. If you call methods on the Storage facade without first calling the disk method, the method call will automatically be passed to the default disk:
$this->ci->filesystem->put('avatars/1', $fileContents);
If your applications interact with multiple disks, you may use the disk method on the Storage facade to work with files on a particular disk:
$this->ci->filesystem->disk('s3')->put('avatars/1', $fileContents);
The Storage facade may also be used to interact with any of your configured disks the same way the filesystem service is :
use UserFrosting\Sprinkle\Core\Facades\Storage;
Storage::put('avatars/1', $fileContents);
You may also use the disk method on the Storage facade to work with files on a particular disk:
Storage::disk('s3')->put('avatars/1', $fileContents);
The get method may be used to retrieve the contents of a file. The raw string contents of the file will be returned by the method. Remember, all file paths should be specified relative to the "root" location configured for the disk:
$contents = $this->ci->filesystem->get('file.jpg');
The exists method may be used to determine if a file exists on the disk:
$exists = $this->ci->filesystem->disk('s3')->exists('file.jpg');
The put
method may be used to store raw file contents on a disk. You may also pass a PHP resource
to the put
method, which will use Flysystem's underlying stream support. Using streams is greatly recommended when dealing with large files:
$this->ci->filesystem->put('file.jpg', $contents);
$this->ci->filesystem->put('file.jpg', $resource);
The delete method accepts a single filename or an array of files to remove from the disk:
$this->ci->filesystem->delete('file.jpg');
$this->ci->filesystem->delete(['file1.jpg', 'file2.jpg']);
Since UserFrosting relies on Laravel implementation, see Laravel Documentation for more info on how to use the filesystem service.
UserFrosting's Flysystem integration provides drivers for several "drivers" out of the box; however, Flysystem is not limited to these and has adapters for many other storage systems. You can create a custom driver if you want to use one of these additional adapters in your UserFrosting application.
In order to set up the custom filesystem you will need a Flysystem adapter. Let's add a community maintained Google Drive adapter to your sprinkle composer.json
:
"nao-pon/flysystem-google-drive": "~1.1"
Next, you should extend the filesystem
service in your sprinkle. There you can use the filesystem service extend
method to define the custom driver:
$container->extend('filesystem', function ($filesystem, $c) {
$filesystem->extend('gdrive', function ($config, $diskConfig) {
$client = new \Google_Client();
$client->setClientId($diskConfig['clientID']);
$client->setClientSecret($diskConfig['clientSecret']);
$client->refreshToken($diskConfig['refreshToken']);
$driveRoot = $diskConfig['rootPath'] ?: '';
$service = new \Google_Service_Drive($client);
$adapter = new \Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter($service, $driveRoot);
return new \League\Flysystem\Filesystem($adapter);
});
return $filesystem;
});
The first argument of the extend
method is the name of the driver and the second is a Closure that receives the config service ($config
) and the disk configuration array ($diskConfig
). The resolver Closure must return an instance of League\Flysystem\Filesystem
.
Last thing to do is to create a disk using the gdrive
driver in your sprinkle configuration file :
'google' => [
'driver' => 'gdrive', // For help finding the client ID : https://developers.google.com/drive/api/v3/enable-sdk
'clientID' => getenv('GOOGLE_CLIENT_ID') ?: '', // [app client id].apps.googleusercontent.com
'clientSecret' => getenv('GOOGLE_CLIENT_SECRET') ?: '',
'refreshToken' => getenv('GOOGLE_REFRESH_TOKEN') ?: '',
'rootPath' => getenv('GOOGLE_ROOT_PATH') ?: ''
]
app/.env
file.