blacksmith-8.x-1.x-dev/src/Blacksmith/EntityImporter/FieldFormatter/FileFieldFormatter.php
src/Blacksmith/EntityImporter/FieldFormatter/FileFieldFormatter.php
<?php
namespace Drupal\blacksmith\Blacksmith\EntityImporter\FieldFormatter;
use Drupal\Component\Utility\Random;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Utility\Token;
use Drupal\blacksmith\Exception\BlacksmithImportSkipField;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
/**
* Class ImageFieldFormatter.
*
* @package Drupal\blacksmith\Blacksmith\EntityImporter\FieldFormatter
*/
class FileFieldFormatter extends FieldFormatterBase implements ContainerInjectionInterface {
/**
* Drupal token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* Drupal file system service.
*
* @var \Drupal\Core\File\FileSystem
*/
protected $fileSystem;
/**
* Default file scheme.
*
* @var string
*/
protected $fileScheme;
/**
* File storage.
*
* @var \Drupal\file\FileStorage
*/
protected $fileStorage;
/**
* @var \Drupal\Component\Utility\Random
*/
protected $random;
/**
* {@inheritdoc}
*/
public function __construct($fieldDefinition, Token $token, FileSystemInterface $fileSystem, EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $configFactory) {
parent::__construct($fieldDefinition);
$this->token = $token;
$this->fileSystem = $fileSystem;
$this->fileScheme = $configFactory->get('system.file')->get('default_scheme');
$this->random = new Random();
try {
$this->fileStorage = $entityTypeManager->getStorage('file');
}
catch (PluginNotFoundException | InvalidPluginDefinitionException $exception) {
$this->logger->error($exception->getMessage());
}
}
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container, FieldDefinitionInterface $fieldDefinition = NULL) {
return new static(
$fieldDefinition,
$container->get('token'),
$container->get('file_system'),
$container->get('entity_type.manager'),
$container->get('config.factory')
);
}
/**
* {@inheritdoc}
*
* @throws \Drupal\blacksmith\Exception\BlacksmithImportSkipField
* @throws \Drupal\Core\Entity\EntityStorageException
*/
protected function formatUniqueValue($value) : array {
// Assume that a file ID is given if the value is a number.
if (is_int($value)) {
return parent::formatUniqueValue($value);
}
// Make sure that the value is always provided as an array.
if (is_string($value)) {
return $this->formatUniqueValue(['src' => $value]);
}
// Load the file from the src and save it in the file directory.
if (isset($value['src'])) {
// Fetch the file from the URL.
// @todo Find a way to get a file that is inside the repository.
$data = file_get_contents($value['src']);
if (!$data) {
throw new BlacksmithImportSkipField('Unable to get the file "' . $value['src'] . '"', NULL);
}
// Set the filename.
if (isset($value['name'])) {
$filename = trim($value['name']);
}
else {
$fileHeaders = self::parseHeaders($http_response_header);
$fileType = explode('/', $fileHeaders['Content-Type'])[1];
// @todo Do not set the name here. The saveData method will do it.
$filename = $this->random->name(16) . '.' . $fileType;
}
// Set the file directory and file path.
$directory = $value['file_directory'] ?? $this->fieldDefinition->getSetting('file_directory');
$directory = $this->token->replace($directory);
$filePath = (empty($directory)) ? "$this->fileScheme://$filename" : "$this->fileScheme://$directory/$filename";
// @todo Find a proper way to name the file.
$uri = $this->fileSystem->saveData($data, $filePath, FileSystemInterface::EXISTS_RENAME);
$file = $this->fileStorage->create([
'filename' => $filename,
'uri' => $uri,
'status' => 1,
]);
$file->save();
return [
'title' => $value['title'] ?? '',
'target_id' => $file->id(),
];
}
throw new BlacksmithImportSkipField('You need to specify the image "src"');
}
/**
* Formats the values returned in the header response.
*
* @param array $headers
* Header response from file_get_contents.
*
* @return array
* The formatted header response.
*
* @see file_get_contents()
* @see $http_response_header
*/
public static function parseHeaders(array $headers) : array {
$head = [];
foreach ($headers as $key => $value) {
$t = explode(':', $value, 2);
if (isset($t[1])) {
$head[trim($t[0])] = trim($t[1]);
}
else {
$head[] = $value;
if (preg_match("#HTTP/[\d.]+\s+([\d]+)#", $value, $out)) {
$head['response_code'] = (int) $out[1];
}
}
}
return $head;
}
}
