graphql_core_schema-1.0.x-dev/src/Plugin/GraphQL/DataProducer/ViewExecutor.php

src/Plugin/GraphQL/DataProducer/ViewExecutor.php
<?php

namespace Drupal\graphql_core_schema\Plugin\GraphQL\DataProducer;

use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\graphql\GraphQL\Execution\FieldContext;
use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
use Drupal\graphql_core_schema\EntitySchemaHelper;
use Drupal\graphql_core_schema\GraphQL\Buffers\SubRequestBuffer;
use Drupal\search_api\Plugin\views\query\SearchApiQuery;
use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
use Drupal\views\ViewExecutable;
use GraphQL\Deferred;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * The data producer to execute views.
 *
 * @DataProducer(
 *   id = "view_executor",
 *   name = @Translation("View Executor"),
 *   description = @Translation("Execute the view and return the results."),
 *   produces = @ContextDefinition("any",
 *     label = @Translation("Executable")
 *   ),
 *   consumes = {
 *     "viewExecutable" = @ContextDefinition("any",
 *       label = @Translation("View Executable"),
 *     ),
 *     "page" = @ContextDefinition("any",
 *       label = @Translation("Page"),
 *       required = FALSE
 *     ),
 *     "limit" = @ContextDefinition("any",
 *       label = @Translation("Limit"),
 *       required = FALSE
 *     ),
 *     "sortBy" = @ContextDefinition("string",
 *       label = @Translation("Sort by"),
 *       required = FALSE
 *     ),
 *     "sortOrder" = @ContextDefinition("string",
 *       label = @Translation("Sort order"),
 *       required = FALSE
 *     ),
 *     "filters" = @ContextDefinition("any",
 *       label = @Translation("Filters"),
 *       required = FALSE
 *     ),
 *     "contextualFilters" = @ContextDefinition("any",
 *       label = @Translation("Contextual filters"),
 *       required = FALSE
 *     ),
 *     "queryParams" = @ContextDefinition("any",
 *       label = @Translation("Query Parameters"),
 *       required = FALSE
 *     ),
 *   }
 * )
 */
class ViewExecutor extends DataProducerPluginBase implements ContainerFactoryPluginInterface {

  use EntityTranslationRenderTrait {
    getEntityTranslationRenderer as parentGetEntityTranslationRenderer;
  }

  /**
   * View.
   *
   * @var \Drupal\views\ViewExecutable
   */
  protected ViewExecutable $view;

  /**
   * Entity type ID.
   *
   * @var string
   */
  protected string $entityTypeId;

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $pluginId,
    $pluginDefinition,
  ) {
    return new static(
      $configuration,
      $pluginId,
      $pluginDefinition,
      $container->get('graphql_core_schema.buffer.subrequest'),
      $container->get('language_manager'),
      $container->get('entity_type.manager'),
      $container->get('entity.repository')
    );
  }

  public function __construct(
    array $configuration,
    $pluginId,
    $pluginDefinition,
    protected SubRequestBuffer $subRequestBuffer,
    protected LanguageManagerInterface $languageManager,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected EntityRepositoryInterface $entityRepository,
  ) {
    parent::__construct($configuration, $pluginId, $pluginDefinition);
    $this->subRequestBuffer = $subRequestBuffer;
    $this->languageManager = $languageManager;
    $this->entityTypeManager = $entityTypeManager;
    $this->entityRepository = $entityRepository;
  }

  /**
   * The resolver.
   *
   * @param \Drupal\views\ViewExecutable $executable
   *   The view.
   * @param int $page
   *   The page.
   * @param int $limit
   *   The limit.
   * @param string $sortBy
   *   The sort field.
   * @param string $sortOrder
   *   The sort order.
   * @param array|null $filters
   *   The exposed filters.
   * @param array|null $contextualFilters
   *   The contextual filters.
   * @param array|null $queryParams
   *   The query params.
   * @param \Drupal\graphql\GraphQL\Execution\FieldContext $fieldContext
   *   The field context.
   *
   * @return \GraphQL\Deferred
   *   The result.
   */
  public function resolve(ViewExecutable $executable, ?int $page = NULL, ?int $limit = NULL, ?string $sortBy = NULL, ?string $sortOrder = NULL, ?array $filters = NULL, ?array $contextualFilters = NULL, ?array $queryParams = NULL, ?FieldContext $fieldContext = NULL) {
    $page = $page ?? 0;
    $url = $executable->hasUrl() ? $executable->getUrl() : Url::fromRoute('<front>');
    $exposedInput = [];
    $queryArguments = [];

    if ($queryParams) {
      foreach ($queryParams as $param) {
        if (!isset($param['key'])) {
          continue;
        }
        $value = $param['value'] ?? NULL;
        if ($value === NULL) {
          continue;
        }
        $queryArguments[$param['key']] = $value;
        $exposedInput[$param['key']] = $value;
      }
    }
    if ($filters) {
      $displayOptions = $executable->getDisplay()->getOption('filters') ?: [];
      $exposedFilters = array_reduce(array_filter($displayOptions, function ($definition) {
        return !empty($definition['exposed']) && !empty($definition['expose']['identifier']);
      }), function ($carry, $definition) {
        $identifier = $definition['expose']['identifier'];
        $carry[EntitySchemaHelper::toCamelCase($identifier)] = $identifier;
        return $carry;
      }, []);

      foreach ($filters as $graphqlIdentifier => $value) {
        if (!array_key_exists($graphqlIdentifier, $exposedFilters)) {
          continue;
        }
        if ($value === NULL) {
          continue;
        }
        $identifier = $exposedFilters[$graphqlIdentifier];
        $queryArguments[$identifier] = $value;
        $exposedInput[$identifier] = $value;
      }
    }

    if (isset($queryArguments['page'])) {
      $limit = $queryArguments['items_per_page'] ?? $limit;
    }

    if (!empty($queryArguments)) {
      $url->setOption('query', $queryArguments);
    }
    if ($sortBy) {
      $exposedInput['sort_by'] = $sortBy;
    }
    if ($sortOrder) {
      $exposedInput['sort_order'] = $sortOrder;
    }
    if ($contextualFilters) {
      $args = [];
      foreach ($contextualFilters as $contextualFilter) {
        $args[$contextualFilter['key']] = $contextualFilter['value'];
      }
      $executable->setArguments($args);
    }
    // Needed by the EntityTranslationRenderTrait.
    $this->view = $executable;
    $baseEntityType = $executable->getBaseEntityType();
    if (!empty($baseEntityType)) {
      $this->entityTypeId = $baseEntityType->id();
    }

    $self = $this;
    $resolve = $this->subRequestBuffer->add($url, function () use ($executable, $page, $limit, $exposedInput, $self, $fieldContext) {
      if ($page) {
        $executable->setCurrentPage($page);
      }
      if ($limit) {
        $executable->setItemsPerPage($limit);
      }

      if (!empty($exposedInput)) {
        $executable->setExposedInput($exposedInput);
      }

      $executable->isGraphQLQuery = TRUE;

      $executable->execute();
      $executable->render();
      $rows = [];
      foreach ($executable->result as $row) {
        // Some views, especially those with search api backend do not have a
        // base entity type on the view. To avoid fatal error, we provide the
        // entity type per rows because it can be different in the same view.
        if (empty($this->entityTypeId)) {
          $this->entityTypeId = $row->_entity->getEntityTypeId();
        }
        // The search api backend uses its own language management. So only run
        // translation handling if this isn't a search api backend view.
        $row_entity = $row->_entity;
        if (!($this->view->getQuery() instanceof SearchApiQuery)) {
          $row_entity = $self->getEntityTranslationByRelationship($row->_entity, $row);
        }
        $rows[] = $row_entity;
      }
      $fieldContext->addCacheContexts(['url.query_args']);
      $fieldContext->addCacheTags($executable->getCacheTags());
      return [
        'rows' => $rows,
        'total_rows' => $executable->getPager()->getTotalItems(),
        'executable' => $executable,
      ];
    });

    return new Deferred(function () use ($resolve) {
      return $resolve();
    });
  }

  /**
   * {@inheritdoc}
   */
  protected function getEntityTranslationRenderer() {
    // We need to call the query method on the renderer so that the language
    // alias is set or getLanguage will only return the default language.
    $renderer = $this->parentGetEntityTranslationRenderer();
    $renderer->query($this->view->getQuery());
    return $renderer;
  }

  /**
   * Get the entity type manager.
   *
   * @todo open issue to have this added as an abstract method on the trait.
   *
   * @return \Drupal\Core\Entity\EntityTypeManagerInterface
   *   The entity type manager.
   */
  public function getEntityTypeManager(): EntityTypeManagerInterface {
    return $this->entityTypeManager;
  }

  /**
   * Get the entity type repository.
   *
   * @todo open issue to have this added as an abstract method on the trait.
   *
   * @return \Drupal\Core\Entity\EntityRepositoryInterface
   *   The entity type repository.
   */
  public function getEntityRepository(): EntityRepositoryInterface {
    return $this->entityRepository;
  }

  /**
   * {@inheritdoc}
   */
  public function getEntityTypeId(): string {
    return $this->entityTypeId ?? '';
  }

  /**
   * {@inheritdoc}
   */
  protected function getLanguageManager(): LanguageManagerInterface {
    return $this->languageManager;
  }

  /**
   * {@inheritdoc}
   */
  protected function getView(): ViewExecutable {
    return $this->view;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc