File Storage

File Storage #

Saving files is a typical task in Plugins. Shopware has here many options to do this. But first why you should never fopen / file_put_contents in a random chosen directory!:

You don’t know how the hosting of the Plugin will be. The chosen folder can be read-only, rotating on any deployment, on an application cluster. Let’s discover all options and find the best fitting one for you.

Static Assets #

As Shopware Plugins are Symfony Bundles they inherit the asset functionality of Symfony. You can add your files into src/Resources/public folder, and they will be automatically copied to an external available place for you. This happens all plugin lifecycles (install, update, uninstall).

Usage of Static Assets:

{{ asset("<relative-path-to-your-file-from-public>", "@PluginName") }}
<?php

// inject using:  <argument type="service" id="assets.packages" />
$packages = $container->get('assets.packages')

$package = $packages->getPackage('asset');

$package->getUrl('<relative-path-to-your-file-from-public>');

Public File system #

The second option is to use a public file system. This is a flexible interface to interact with an unknown file system, we just use the abstraction and don’t care what is behind it.

The public file system is available in two variants. One scoped special for the extension and one normal.

The scoped variant is the recommended variant as you have a complete custom scoped file system for your plugin

See here for complete interface

This File system writes in the same folder as the global one, but always in a subfolder named like your Plugin to not have any collisions.

<?php

// our extension name is FroshTools, camel-case + .filesystem.public suffix

// inject using:  <argument type="service" id="frosh_tools.filesystem.public" />
$fs = $container->get('frosh_tools.filesystem.public')

$fs->write('file.jpg', 'data');
$fs->read('file.jpg'); // returns data

See here for complete interface

<?php

// inject using:  <argument type="service" id="shopware.filesystem.public" />
$fs = $container->get('shopware.filesystem.public')

$fs->write('file.jpg', 'data');
$fs->read('file.jpg'); // returns data

Generating links can be done in the same way using the Asset package public

In this example our Plugin name is FroshTools due to camel case its here formatted as plugins/{name}/path

{{ asset("plugins/frosh_tools/file.jpg", "public") }}
<?php

// inject using:  <argument type="service" id="assets.packages" />
$packages = $container->get('assets.packages')

$package = $packages->getPackage('public');

$package->getUrl('plugins/frosh_tools/file.jpg');
{{ asset("file.jpg", "public") }}
<?php

// inject using:  <argument type="service" id="assets.packages" />
$packages = $container->get('assets.packages')

$package = $packages->getPackage('public');

$package->getUrl('file.jpg');

Private File system #

The private file system is similar to the public file system, but as the name already said the written files are not accessible using URLs.

Similar to public file system, there is also scoped file system for your extension.

The scoped variant is the recommended variant as you have a complete custom scoped file system for your plugin

See here for complete interface

This File system writes in the same folder as the global one, but always in a subfolder named like your Plugin to not have any collisions.

<?php

// our extension name is FroshTools, camel-case + .filesystem.private suffix

// inject using:  <argument type="service" id="frosh_tools.filesystem.private" />
$fs = $container->get('frosh_tools.filesystem.private')

$fs->write('file.jpg', 'data');
$fs->read('file.jpg'); // returns data

See here for complete interface

<?php

// inject using:  <argument type="service" id="shopware.filesystem.private" />
$fs = $container->get('shopware.filesystem.private')

$fs->write('file.jpg', 'data');
$fs->read('file.jpg'); // returns data
When you use the global file system, make sure you write in a custom directory and is prefixed with your extension name.

Temporary files #

Sometimes you need in your code temporary files to, the temporary files should be always created in the system temp directory (sys_get_temp_dir). If the temporary file has to be existent between multiple requests, you should prefer to use the private file system to be compatible on cluster systems. In both cases, the code should delete the temporary file after usage.