You are here

class HandlePdfController in FillPDF 5.0.x

Same name and namespace in other branches
  1. 8.4 src/Controller/HandlePdfController.php \Drupal\fillpdf\Controller\HandlePdfController

Class HandlePdfController.

Hierarchy

Expanded class hierarchy of HandlePdfController

File

src/Controller/HandlePdfController.php, line 24

Namespace

Drupal\fillpdf\Controller
View source
class HandlePdfController extends ControllerBase {

  /**
   * The FillPDF link manipulator.
   *
   * @var \Drupal\fillpdf\FillPdfLinkManipulatorInterface
   */
  protected $linkManipulator;

  /**
   * The FillPDF context manager.
   *
   * @var \Drupal\fillpdf\FillPdfContextManagerInterface
   */
  protected $contextManager;

  /**
   * The FillPDF token resolver.
   *
   * @var \Drupal\fillpdf\TokenResolverInterface
   */
  protected $tokenResolver;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The FillPDF backend manager.
   *
   * @var \Drupal\fillpdf\Plugin\PdfBackendManager
   */
  protected $backendManager;

  /**
   * The FillPDF action manager.
   *
   * @var \Drupal\fillpdf\Plugin\FillPdfActionPluginManager
   */
  protected $actionManager;

  /**
   * The backend proxy.
   *
   * @var \Drupal\fillpdf\Service\BackendProxyInterface
   */
  protected $backendProxy;

  /**
   * Constructs a FillPdfBackendManager object.
   *
   * @param \Drupal\fillpdf\FillPdfLinkManipulatorInterface $link_manipulator
   *   The FillPDF link manipulator.
   * @param \Drupal\fillpdf\FillPdfContextManagerInterface $context_manager
   *   The FillPDF context manager.
   * @param \Drupal\fillpdf\TokenResolverInterface $token_resolver
   *   The FillPDF token resolver.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\fillpdf\Plugin\PdfBackendManager $backend_manager
   *   The FillPDF backend manager.
   * @param \Drupal\fillpdf\Plugin\FillPdfActionPluginManager $action_manager
   *   The FillPDF action manager.
   * @param \Drupal\fillpdf\Service\BackendProxyInterface $backend_proxy
   *   The backend proxy.
   */
  public function __construct(FillPdfLinkManipulatorInterface $link_manipulator, FillPdfContextManagerInterface $context_manager, TokenResolverInterface $token_resolver, RequestStack $request_stack, PdfBackendManager $backend_manager, FillPdfActionPluginManager $action_manager, BackendProxyInterface $backend_proxy) {
    $this->linkManipulator = $link_manipulator;
    $this->contextManager = $context_manager;
    $this->tokenResolver = $token_resolver;
    $this->requestStack = $request_stack;
    $this->backendManager = $backend_manager;
    $this->actionManager = $action_manager;
    $this->backendProxy = $backend_proxy;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('fillpdf.link_manipulator'), $container
      ->get('fillpdf.context_manager'), $container
      ->get('fillpdf.token_resolver'), $container
      ->get('request_stack'), $container
      ->get('plugin.manager.fillpdf.pdf_backend'), $container
      ->get('plugin.manager.fillpdf_action.processor'), $container
      ->get('fillpdf.backend_proxy'));
  }

  /**
   * Populates PDF template from context.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The action plugin's response object.
   *
   * @throws \InvalidArgumentException
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   * @throws \Drupal\Core\Entity\EntityMalformedException
   *   If one of the passed arguments is missing or does not pass the
   *   validation.
   */
  public function populatePdf() {
    $context = $this->linkManipulator
      ->parseRequest($this->requestStack
      ->getCurrentRequest());
    $fillpdf_form = FillPdfForm::load($context['fid']);
    $entities = $this->contextManager
      ->loadEntities($context);
    $populated_pdf = $this->backendProxy
      ->merge($fillpdf_form, $entities, $context);
    if (empty($populated_pdf)) {
      $this
        ->messenger()
        ->addError($this
        ->t('Merging the FillPDF Form failed.'));
      return new RedirectResponse(Url::fromRoute('<front>')
        ->toString());
    }

    // Generate the filename of downloaded PDF from title of the PDF set in
    // admin/structure/fillpdf/%fid.
    $filename = $this
      ->buildFilename($fillpdf_form->title->value, $entities);

    // @todo: When Rules integration ported, emit an event or whatever.
    return $this
      ->handlePopulatedPdf($fillpdf_form, $populated_pdf, $context, $filename, $entities);
  }

  /**
   * Builds the filename of a populated PDF file.
   *
   * @param string $original
   *   The original filename without tokens being replaced.
   * @param \Drupal\Core\Entity\EntityInterface[] $entities
   *   An array of entities to be used for replacing tokens.
   *
   * @return string
   *   The token-replaced filename.
   */
  protected function buildFilename($original, array $entities) {

    // Replace tokens *before* sanitization.
    $original = (string) $this->tokenResolver
      ->replace($original, $entities, [
      'content' => 'text',
    ]);
    $output_name = str_replace(' ', '_', $original);
    $output_name = preg_replace('/\\.pdf$/i', '', $output_name);
    $output_name = preg_replace('/[^a-zA-Z0-9_.-]+/', '', $output_name) . '.pdf';
    return $output_name;
  }

  /**
   * Figure out what to do with the PDF and do it.
   *
   * @param \Drupal\fillpdf\FillPdfFormInterface $fillpdf_form
   *   An object containing the loaded record from {fillpdf_forms}.
   * @param string $pdf_data
   *   A string containing the content of the merged PDF.
   * @param array $context
   *   The request context as returned by
   *   FillPdfLinkManipulatorInterface::parseLink().
   * @param string $filename
   *   Filename of the merged PDF.
   * @param \Drupal\Core\Entity\EntityInterface[] $entities
   *   An array of entities to be used for replacing tokens. These may be still
   *   needed for generating the destination path, if the file is saved.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The action plugin's response object.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @see \Drupal\fillpdf\FillPdfLinkManipulatorInterface::parseLink()
   */
  protected function handlePopulatedPdf(FillPdfFormInterface $fillpdf_form, $pdf_data, array $context, $filename, array $entities) {
    $force_download = FALSE;
    if (!empty($context['force_download'])) {
      $force_download = TRUE;
    }

    // Determine the appropriate action for the PDF.
    $scheme = $fillpdf_form
      ->getStorageScheme();
    $is_available = array_key_exists($scheme, \Drupal::service('stream_wrapper_manager')
      ->getWrappers(StreamWrapperInterface::WRITE_VISIBLE));
    $is_allowed = in_array($scheme, \Drupal::config('fillpdf.settings')
      ->get('allowed_schemes') ?: []);
    if (empty($scheme)) {
      $action_plugin_id = 'download';
    }
    elseif (!$is_available || !$is_allowed) {

      // @todo: We don't need the ID once an admin_title is #required,
      // see https://www.drupal.org/project/fillpdf/issues/3040776.
      $label = $fillpdf_form
        ->label() . " ({$fillpdf_form->id()})";
      $this
        ->getLogger('fillpdf')
        ->critical('Saving a generated PDF file in unavailable storage scheme %scheme failed.', [
        '%scheme' => "{$scheme}://",
      ]);
      if ($this
        ->currentUser()
        ->hasPermission('administer pdfs')) {
        $this
          ->messenger()
          ->addError($this
          ->t('File storage scheme %scheme:// is unavailable, so a PDF file generated from FillPDF form @link could not be stored.', [
          '%scheme' => $scheme,
          '@link' => Link::fromTextAndUrl($label, $fillpdf_form
            ->toUrl())
            ->toString(),
        ]));
      }

      // Make sure the file is only sent to the browser.
      $action_plugin_id = 'download';
    }
    else {
      $redirect = !empty($fillpdf_form->destination_redirect->value);
      $action_plugin_id = $redirect ? 'redirect' : 'save';
    }

    // @todo: Remove in FillPDF 5.x. The filename is not part of the context and
    // is separately available anyway.
    $context['filename'] = $filename;

    // @todo: Rename 'token_objects' to 'entities' in FillPDF 5.x. Webform
    // submissions are now entities, too.
    $action_configuration = [
      'form' => $fillpdf_form,
      'context' => $context,
      'token_objects' => $entities,
      'data' => $pdf_data,
      'filename' => $filename,
    ];

    /** @var \Drupal\fillpdf\Plugin\FillPdfActionPluginInterface $fillpdf_action */
    $fillpdf_action = $this->actionManager
      ->createInstance($action_plugin_id, $action_configuration);
    $response = $fillpdf_action
      ->execute();

    // If we are forcing a download, then manually get a Response from
    // the download action and return that. Side effects of other plugins will
    // still happen, obviously.
    if ($force_download) {

      /** @var FillPdfDownloadAction $download_action */
      $download_action = $this->actionManager
        ->createInstance('download', $action_configuration);
      $response = $download_action
        ->execute();
    }
    return $response;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ControllerBase::$configFactory protected property The configuration factory.
ControllerBase::$currentUser protected property The current user service. 1
ControllerBase::$entityFormBuilder protected property The entity form builder.
ControllerBase::$entityTypeManager protected property The entity type manager.
ControllerBase::$formBuilder protected property The form builder. 2
ControllerBase::$keyValue protected property The key-value storage. 1
ControllerBase::$languageManager protected property The language manager. 1
ControllerBase::$moduleHandler protected property The module handler. 2
ControllerBase::$stateService protected property The state service.
ControllerBase::cache protected function Returns the requested cache bin.
ControllerBase::config protected function Retrieves a configuration object.
ControllerBase::container private function Returns the service container.
ControllerBase::currentUser protected function Returns the current user. 1
ControllerBase::entityFormBuilder protected function Retrieves the entity form builder.
ControllerBase::entityTypeManager protected function Retrieves the entity type manager.
ControllerBase::formBuilder protected function Returns the form builder service. 2
ControllerBase::keyValue protected function Returns a key/value storage collection. 1
ControllerBase::languageManager protected function Returns the language manager service. 1
ControllerBase::moduleHandler protected function Returns the module handler. 2
ControllerBase::redirect protected function Returns a redirect response object for the specified route.
ControllerBase::state protected function Returns the state storage service.
HandlePdfController::$actionManager protected property The FillPDF action manager.
HandlePdfController::$backendManager protected property The FillPDF backend manager.
HandlePdfController::$backendProxy protected property The backend proxy.
HandlePdfController::$contextManager protected property The FillPDF context manager.
HandlePdfController::$linkManipulator protected property The FillPDF link manipulator.
HandlePdfController::$requestStack protected property The request stack.
HandlePdfController::$tokenResolver protected property The FillPDF token resolver.
HandlePdfController::buildFilename protected function Builds the filename of a populated PDF file.
HandlePdfController::create public static function Instantiates a new instance of this class. Overrides ControllerBase::create
HandlePdfController::handlePopulatedPdf protected function Figure out what to do with the PDF and do it.
HandlePdfController::populatePdf public function Populates PDF template from context.
HandlePdfController::__construct public function Constructs a FillPdfBackendManager object.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.