Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save justinlevi/86f04a4609b92a875ea6f62a97afa255 to your computer and use it in GitHub Desktop.
Save justinlevi/86f04a4609b92a875ea6f62a97afa255 to your computer and use it in GitHub Desktop.
<?php
namespace Drupal\store_graph_upload\Plugin\Deriver;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
/**
* Derives EntityFileFieldUpload scalar for each file field instance.
*/
class EntityFileFieldUploadDeriver extends DeriverBase implements ContainerDeriverInterface {
/**
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $fieldManager;
/**
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $bundleInfo;
/**
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
*/
protected $fieldTypeManager;
/**
* @var \Drupal\Core\Theme\ThemeManagerInterface
*/
protected $themeManager;
/**
* EntityFileFieldUploadDeriver constructor.
*
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
*/
public function __construct(
EntityFieldManagerInterface $field_manager,
EntityTypeManagerInterface $entity_manager,
EntityTypeBundleInfoInterface $bundle_info,
FieldTypePluginManagerInterface $field_type_manager,
ThemeManagerInterface $theme_manager
) {
$this->fieldManager = $field_manager;
$this->entityTypeManager = $entity_manager;
$this->bundleInfo = $bundle_info;
$this->fieldTypeManager = $field_type_manager;
$this->themeManager = $theme_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $basePluginId) {
return new static(
$container->get('entity_field.manager'),
$container->get('entity_type.manager'),
$container->get('entity_type.bundle.info'),
$container->get('plugin.manager.field.field_type'),
$container->get('theme.manager')
);
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($basePluginDefinition) {
$this->derivatives = [];
foreach (store_graph_exposed_content_entities() AS $entity_type_id) {
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
$bundle_entity_type_id = $entity_type->getBundleEntityType();
$bundles = empty($bundle_entity_type_id) ? [$entity_type_id] : array_keys($this->bundleInfo->getBundleInfo($entity_type_id));
foreach ($bundles AS $bundle) {
$fields = $this->fieldManager->getFieldDefinitions($entity_type_id, $bundle);
foreach ($fields AS $field) {
if (in_array($field->getType(), ['file', 'image'])) {
$key = $entity_type_id . ':' . $bundle . ':' . $field->getName();
if ($field->getFieldStorageDefinition()->isBaseField()) {
$key = $entity_type_id . ':' . $field->getName();
$bundle = $entity_type_id;
}
if (!isset($this->derivatives[$key])) {
$this->derivatives[$key] = $this->buildDefinition($entity_type_id, $bundle, $field) + $basePluginDefinition;
}
}
}
}
}
return parent::getDerivativeDefinitions($basePluginDefinition);
}
/**
* Helper method to create definition of derivative from provided values.
*
* @param string $entity_type_id
* @param string $bundle
* @param \Drupal\Core\Field\FieldDefinitionInterface $field
*
* @return array
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
protected function buildDefinition(string $entity_type_id, string $bundle, FieldDefinitionInterface $field): array {
/** @var \Drupal\file\Plugin\Field\FieldType\FileItem $item */
$item = $this->fieldTypeManager->createInstance(
$field->getType(),
[
'field_definition' => $field,
'name' => $field->getName(),
'parent' => NULL
]
);
$description = $this->themeManager->render('file_upload_help', [
'description' => store_graph_untranslated_string($field->getDescription()),
'upload_validators' => $item->getUploadValidators(),
'cardinality' => $field->getFieldStorageDefinition()->getCardinality()
]);
return [
'name' => store_graph_upload_get_file_field_upload_input_name($entity_type_id, $bundle, $field->getName()),
'description' => store_graph_parse_description($description),
'file_upload_validators' => $item->getUploadValidators(),
'file_upload_destination' => $item->getUploadLocation()
];
}
}
<?php
namespace Drupal\store_graph_upload\Plugin\GraphQL\Scalars;
/**
* @GraphQLScalar(
* id = "entity_file_field_upload",
* name = "EntityFileFieldUpload",
* data_type = "id",
* deriver = "\Drupal\store_graph_upload\Plugin\Deriver\EntityFileFieldUploadDeriver"
* )
*/
class EntityFileFieldUpload extends FileUpload {
/**
* {@inheritdoc}
*/
public function getFileUploadValidators() {
return $this->getPluginDefinition()['file_upload_validators'];
}
/**
* {@inheritdoc}
*/
public function getFileUploadDirectory() {
return $this->getPluginDefinition()['file_upload_destination'];
}
}
<?php
namespace Drupal\store_graph_upload\Plugin\GraphQL\Scalars;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\graphql\Plugin\GraphQL\Scalars\GraphQLString;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* @GraphQLScalar(
* id = "file_upload",
* name = "FileUpload",
* data_type = "id",
* description = @Translation("Name of the key holding the uploaded file data in the $_FILES variable.")
* )
*/
class FileUpload extends GraphQLString implements ContainerFactoryPluginInterface {
/**
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $pluginId, $pluginDefinition, RequestStack $request_stack) {
$this->requestStack = $request_stack;
$this->constructPlugin($configuration, $pluginId, $pluginDefinition);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
return new static(
$configuration,
$pluginId,
$pluginDefinition,
$container->get('request_stack')
);
}
/**
* {@inheritdoc}
*
* @todo remove when https://github.com/drupal-graphql/graphql/issues/420
*/
public function getName() {
return $this->getPluginDefinition()['name'];
}
/**
* {@inheritdoc}
*
* @todo remove when https://github.com/drupal-graphql/graphql/issues/420
*/
public function getDescription() {
return $this->getPluginDefinition()['description'];
}
/**
* Helper method to identify the file by its name.
*
* @param string $file_name
* The name of the file to look for.
*
* @return string|null
* The array key in the file bag.
*/
protected function findFileIdentifier(string $file_name): ?string {
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile[] $all_files */
$all_files = $this->requestStack->getCurrentRequest()->files->all();
foreach ($all_files AS $identifier => $file) {
if ($file->getClientOriginalName() === $file_name) {
return $identifier;
}
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function isValidValue($value) {
return is_string($value) && strlen($value) !== 0 && $this->findFileIdentifier($value) !== NULL;
}
/**
* {@inheritdoc}
*/
public function parseValue($value) {
// Drupal expects files to reside under 'files' key
// so we have to manually move the file to expected location.
// @see file_save_upload()
// @see \Drupal\file\Element\ManagedFile::processManagedFile()
$files_bag = $this->requestStack->getCurrentRequest()->files;
$all_files = $files_bag->get('files', []);
$identifier = $this->findFileIdentifier($value);
$file = $files_bag->get($identifier);
// Prevent key collision.
if (isset($all_files[$identifier])) {
$identifier = uniqid($identifier);
}
// Move the file.
$all_files[$identifier] = $file;
$files_bag->set('files', $all_files);
// Save the uploaded file as managed file entity.
$file = file_save_upload($identifier, $this->getFileUploadValidators(), $this->getFileUploadDirectory(), 0);
// Return the file entity id.
return parent::parseValue($file ? $file->id() : NULL);
}
/**
* {@inheritdoc}
*/
public function getValidationError($value = null) {
return is_string($value) ? sprintf('File "%s" not found in request.', $value) : parent::getValidationError($value);
}
/**
* Helper method that will return file validators.
*
* @return array
*/
public function getFileUploadValidators() {
return [];
}
/**
* Helper method that will return the target directory.
*
* @return string|false
*/
public function getFileUploadDirectory() {
return FALSE;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment