3

How do I programmatically create a text file and write to it in the private:// folder in Drupal 8.8? I found some examples, but all of them use deprecated functions and they don't work.

Here what I have now, but i't s not creating folder and text file in it with content:

use Drupal\Core\StreamWrapper\PrivateStream;
...
...
$output = 'Test Text';
$file_save_path_stream_directory =  'private://gmt';

file_prepare_directory($file_save_path_stream_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);

$fileLocation = $file_save_path_stream_directory . '/test.txt';

$file = file_save_data($output, $fileLocation, FILE_EXISTS_REPLACE);  
2
  • What is $file after the call? Have you checked the function docs to see what that would suggest?
    – Clive
    Commented Feb 1, 2020 at 17:22
  • 1
    You want to be looking at using Filesystem. Your going to want to look at the 8.8 documentation pages for those deprecated functions, they link off to the new Filesystem methods. Commented Feb 1, 2020 at 22:29

3 Answers 3

4

This answer is tested with Drupal 9.3 and doesn't use file_save_data(), which is deprecated in 9.3 and will be removed in Drupal 10.

use Drupal\Core\File\FileSystemInterface;

...

  /**
   * Provides helpers to operate on files and stream wrappers.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * Constructs an object.
   *
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system manager.
   */
  public function __construct(FileSystemInterface $file_system) {
    $this->fileSystem = $file_system;
  }

  public function testFunction($data, $destination) {
    if (!$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
      // @todo Log an error.
      return FALSE;
    }

    $this->fileSystem->saveData($data, $destination, FileSystemInterface::EXISTS_REPLACE);

    // Create and save a new file entity.
    // @see FileRepository::createOrUpdate().
    $new_file = File::create(['uri' => $file->uri]);
    $new_file->setOwnerId(1);
    $new_file->setPermanent();
    $new_file->save();

    return $new_file;
  }

It should also be noted that in Drupal 9.3, though $data can be a file handle resource passed to fileSystem->saveData(), it is not documented and doesn't have test coverage. file_save_data() also allowed a resource data parameter. FileRepository::writeData() does not allow one, however, although that's only because it specifies string $data in the function declaration.

4
  • Undefined variable '$file', while '$data' is unused.. are they the same variable?
    – kopeboy
    Commented Oct 6, 2023 at 7:37
  • Also Argument #1 ($file_system) must be of type Drupal\Core\File\FileSystemInterface, array given
    – kopeboy
    Commented Oct 6, 2023 at 7:43
  • @kopeboy Firstly, this isn't an action. Second, this is not a complete example. You need to write your own code rather than expecting it to work with just copy and paste. $file could be a Drupal file entity. $data is whatever data you pass to the function. And if you're getting an error, it's because you're passing an array instead of a FileSystem, just like the error says. It's not a bug in my code, but in yours.
    – mbomb007
    Commented Oct 6, 2023 at 16:11
  • @kopeboy If you're writing an action plugin, fine, but you will still need to inject the FileSystem, and you'll still need to call File::create(), etc.
    – mbomb007
    Commented Oct 6, 2023 at 16:14
1

As noted, file_save_data is deprecated as of Drupal 9.3. The file.repository service is a good replacement as it will both generate the actual file in the filesystem and the File entity.

<?php
use Drupal\Core\File\FileSystemInterface;

...

/**
 * @var \Drupal\Core\File\FileSystemInterface
 */
protected $fileSystem;


public function __construct(FileSystemInterface $fileSystem) {
    $this->fileSystem = $fileSystem;
}

public function testCreation() {
    $data = 'test content';
    $path = 'private://gmt/';
    $filename = 'requests.txt';
    if (!$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
        // @todo Log an error.
        return FALSE;
    }
    
    // this will both create the actual file and the File entity. Returns the entity.
    $file = \Drupal::service('file.repository')->writeData($data, $path.$filename);

    // here's the fid to reference elsewhere
    $fid = $file->id();

 
}
0

If anyone need it, I make it work:

use Drupal\Core\File\FileSystemInterface;

...

  /**
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;


  public function __construct(FileSystemInterface $fileSystem) {
    $this->fileSystem = $fileSystem;
  }

  public function testCreation() {
    $request = 'test content';
    $path = 'private://gmt/';
    if ($this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY)) {
      /** @var \Drupal\file\FileInterface $file */
      $file = file_save_data(
        $request,
        $path . 'requests.txt'
      );
    }
  }
4
  • 3
    file_save_data() is deprecated in Drupal 9.3 and will be removed in Drupal 10.
    – mbomb007
    Commented Jan 6, 2022 at 17:38
  • way to give credit to the answerer... not.
    – eric
    Commented Feb 25, 2022 at 2:22
  • @eric Answers that are outdated and no longer work don't need more credit unless the answer is updated. Answers that remain relevant should move to the top with upvotes.
    – mbomb007
    Commented Aug 15, 2022 at 15:48
  • When putting this in an action plugin I'm getting error TypeError: Drupal\test\Plugin\Action\GenerateQrImage::__construct(): Argument #1 ($file_system) must be of type Drupal\Core\File\FileSystemInterface, array given
    – kopeboy
    Commented Oct 6, 2023 at 8:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.