Closed rawxx closed 4 years ago
Have you got around this somehow? I'm having the same issue here
Hi @d1urno , I have had to create my own mutation for this particular case (only case in my application). See the code below.
In this case, I am able to ADD (not remove, but this was on purpose) several NodeProduct
entities in a NodeProductPack
's field_products
. The variables are the NodeProductPack's nid and an array of the NodeProducts' nids
<?php
namespace Drupal\my_module\Plugin\GraphQL\Mutations;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\graphql\GraphQL\Execution\ResolveContext;
use Drupal\graphql_core\GraphQL\EntityCrudOutputWrapper;
use Drupal\graphql\Plugin\GraphQL\Mutations\MutationPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use GraphQL\Type\Definition\ResolveInfo;
/**
*
* @GraphQLMutation(
* id = "add_products_to_pack",
* secure = true,
* name = "addProductsToPack",
* type = "EntityCrudOutput",
* arguments = {
* "packId" = {
* "type" = "String",
* "nullable" = false
* },
* "productIds" = {
* "type" = "[String]",
* "nullable" = false
* }
* }
* )
*/
class AddProductsToPack extends MutationPluginBase implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
return new static(
$configuration, $pluginId, $pluginDefinition, $container->get('entity_type.manager'), $container->get('renderer')
);
}
/**
* AddProductsToPack constructor.
*
* @param array $configuration
* The plugin configuration array.
* @param string $pluginId
* The plugin id.
* @param mixed $pluginDefinition
* The plugin definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
*/
public function __construct(array $configuration, $pluginId, $pluginDefinition, EntityTypeManagerInterface $entityTypeManager, RendererInterface $renderer) {
parent::__construct($configuration, $pluginId, $pluginDefinition);
$this->entityTypeManager = $entityTypeManager;
$this->renderer = $renderer;
}
public function resolve($value, array $args, ResolveContext $context, ResolveInfo $info) {
// There are cases where the Drupal entity API calls emit the cache metadata
// in the current render context. In such cases
// EarlyRenderingControllerWrapperSubscriber throws the leaked cache
// metadata exception. To avoid this, wrap the execution in its own render
// context.
return $this->renderer->executeInRenderContext(new RenderContext(), function () use ($value, $args, $context, $info) {
$storage = \Drupal::entityTypeManager()->getStorage('node');
/** @var \Drupal\node\Entity\Node $pack */
if (!$pack = $storage->load($args['packId'])) {
return new EntityCrudOutputWrapper(NULL, NULL, [
$this->t('The requested Pack could not be loaded : @nid.', ['@nid' => $args['packId']]),
]);
} else {
if (!$pack->bundle() === 'product_pack') {
return new EntityCrudOutputWrapper(NULL, NULL, [
$this->t('The requested Node is not of the expected type product_pack. @bundle found instead', ['@bundle' => $pack->bundle()]),
]);
} else {
$pids = [];
foreach ($pack->field_products->getValue() as $val) {
$pids[] = $val['target_id'];
}
foreach ($args['productIds'] as $nid) {
//we only ADD Products, those already in the Pack are kept
if (!in_array($nid, $pids)) {
/** @var \Drupal\node\Entity\Node $product */
if (!$product = $storage->load($nid)) {
return new EntityCrudOutputWrapper(NULL, NULL, [
$this->t('The requested Product could not be loaded : @nid.', ['@nid' => $nid]),
]);
} else {
if (!$product->bundle() === 'product') {
return new EntityCrudOutputWrapper(NULL, NULL, [
$this->t('The requested Node is not of the expected type product. @bundle found instead', ['@bundle' => $product->bundle()]),
]);
} else {
if (!product == $pack->field_products->appendItem($product)) {
return new EntityCrudOutputWrapper(NULL, NULL, [
$this->t('Unable to add product @pid to product_pack @ppid', ['@pid' => $product->id(), '@ppid' => $pack->id()]),
]);
} else {
$updated = true;
}
}
}
}
}
}
}
if ($updated) {
$pack->save();
}
return new EntityCrudOutputWrapper($pack);
});
}
}
Hope it helps.
Thank you very much for the guide, it helps a lot!
Custom mutations are the preferred solution. Closing this issue as resolved.
Hello,
I have been using graphql beta5 for a while on my project because of the issue https://github.com/drupal-graphql/graphql/issues/610 and now I am trying to port it to the latest dev version. There's something I think I can't do anymore.
I have a content type called
product_pack
with a (possibly multiple) Entity Reference fieldfieldProducts
, which lists contents of typeproduct
With beta5 I used this mutation :
with the following variable, to reference two existing nodes at the same time :
and it worked well
Now, with the latest dev version 8.x-3.x, the same mutation with the same variables will return a new
NodeProductPack
with empty fieldfieldProducts
. The syntax of the mutation and the query seems to fit the Schema, and the Explorer doesn't raise any syntax issue.Is there another way of setting multiple reference fields, or has it disappeared since the use of webonyx ?
Thanks again for this great tool