Skip to content Get in touch

Contact form

file storage

Entity type specific file storage for Drupal 8 Media

You may already know that Drupal 8 Media entity has a nice feature that applies to the File field type: the possibility to specify the folder where those files will be saved (that prevents from having tons of files all stacked into the public files folder).

Furthermore, that setting supports tokens, as you can see in the above example, which makes the feature even more handy.

But those of you that want to handle media entities and file storage programmatically may wonder how to take advantage of this capability.

Here is how I did.

First of all we will need the FieldConfig class, which provides the loader that will give us access to the settings:

use Drupal\field\Entity\FieldConfig; [...] $field = FieldConfig::load("media.product_datasheet.field_media_file");


Next, we get the setting we need:

$fieldSettings = $field->getSettings(); if (isset($fieldSettings['file_directory']) && $fieldSettings['file_directory'] !== '') { $fileDirectory = $fieldSettings['file_directory']; } else ...


If your directory setting is not tokenized, then you’re probably all set.

But since I mentioned that, I feel like I’m beholden to you, so here is how you can deal with a datetime token.

Let’s inject the token service:

services:   my_media_handler:     class: Drupal\...\Handler\MediaHandler     arguments: [..., '@token']

and update your class accordingly:

use Drupal\Core\Utility\Token; class MediaHandler {   /**    * Token service.    *    * @var \Drupal\Core\Utility\Token    */   protected $token; [...] /**    * Constructs a new Handler service object.    *    [...]    * @param \Drupal\Core\Utility\Token $token    * The token utility.    */   public function __construct(     [...]     Token $token   ) {     [...]     $this->token = $token;   }


Then finally you can replace the tokens:

$tokenizedDirectory = $this->token->replace($fileDirectory, ['date' => $date]);


Say what? Where can we get Drupal date?

From datetime service, of course. Let’s get that as well.


services:   my_media_handler:     class: Drupal\...\Handler\MediaHandler     arguments: [..., '@token', '@datetime.time']

and update your class:

use Drupal\Component\Datetime\Time; class MediaHandler {   /**    * Token service.    *    * @var \Drupal\Core\Utility\Token    */   protected $token;   /**    * The time service.    *    * @var \Drupal\Component\Datetime\Time    */   protected $time; [...] /**    * Constructs a new Handler service object.    *    [...]    * @param \Drupal\Core\Utility\Token $token    * The token utility.    * @param \Drupal\Component\Datetime\Time $datetime_time    * The time service.    */   public function __construct(     [...]     Token $token,     Time $datetime_time   ) {     [...]     $this->token = $token;     $this->time = $datetime_time;   }


And here you go:

$tokenizedDirectory = $this->token->replace($fileDirectory, ['date' => $this->time->getRequestTime()]);


Now we’re really done, and we can save our file:

$mediaDirectory = 'public://' . $tokenizedDirectory; $file = system_retrieve_file($url, $mediaDirectory, TRUE, FILE_EXISTS_REPLACE);


As a bonus, here is how we handle the case when the folder does not exist yet: we need the file_system service

services:   my_media_handler:     class: Drupal\...\Handler\MediaHandler     arguments: [..., '@token', '@datetime.time', '@file_system']

(I’ll leave the constructor update as an exercise; hint: use Drupal\Core\File\FileSystem;)

if (!is_dir($mediaDirectory)) {    $this->fileSystem->mkdir($mediaDirectory, NULL, TRUE); }


Almost easier to do than to explain, as it always happens once you know how to 😉

Other thoughts

More thoughts