muser-8.x-1.x-dev/modules/custom/muser_system/src/Controller/MuserPdfExportController.php

modules/custom/muser_system/src/Controller/MuserPdfExportController.php
<?php

namespace Drupal\muser_system\Controller;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\File\FileSystem;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use setasign\FPDF\FPDF;
use setasign\Fpdi\Fpdi;
use Drupal\views\Views;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\Settings as PhpWordSettings;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;

/**
 * Returns responses for Muser System routes.
 */
class MuserPdfExportController extends ControllerBase {

  /**
   * Encoding value to convert to.
   */
  const ENCODING = 'CP1251';

  /**
   * @var Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The FileSystem service.
   *
   * @var \Drupal\Core\File\FileSystem
   */
  protected $fileSystem;

  /**
   * Logger Factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * Include uploaded resume, transcript in document?
   *
   * @var bool
   */
  protected $includeUploadedDcouments = FALSE;

  /**
   * The controller constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
   *   The entity type manager.
   * @param \Drupal\Core\File\FileSystem $file_system
   *   Filesystem service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   Logger Factory object.
   */
  public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $current_user, EntityTypeManagerInterface $entity_manager, FileSystem $file_system, LoggerChannelFactoryInterface $logger_factory) {
    $this->configFactory = $config_factory;
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entity_manager;
    $this->fileSystem = $file_system;
    $this->loggerFactory = $logger_factory->get('muser_system');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('current_user'),
      $container->get('entity_type.manager'),
      $container->get('file_system'),
      $container->get('logger.factory')
    );
  }

  /**
   * Create a PDF of the applications for the current user..
   *
   * Documentation:
   * http://www.fpdf.org/en/doc/index.php
   *
   * @param string $stage
   *   Stage to show applications for (submitted|review).
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   Build array.
   * @throws \setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException
   * @throws \setasign\Fpdi\PdfParser\Filter\FilterException
   * @throws \setasign\Fpdi\PdfParser\PdfParserException
   * @throws \setasign\Fpdi\PdfParser\Type\PdfTypeException
   * @throws \setasign\Fpdi\PdfReader\PdfReaderException
   */
  public function build($stage) {

    $display = ($stage == 'in-review') ? 'page_review' : 'page_new';

    $args = [$this->currentUser->id()];
    $view = Views::getView('applications');
    if (is_object($view)) {
      $view->setArguments($args);
      $view->setDisplay($display);
      $view->preExecute();
      $view->execute();
    }

    if (empty($view->result)) {
      throw new NotFoundHttpException();
    }

    $flagging_handler = $this->entityTypeManager->getStorage('flagging');
    $node_handler = $this->entityTypeManager->getStorage('node');
    $user_handler = $this->entityTypeManager->getStorage('user');

    $pdf = new Fpdi();

    foreach ($view->result as $row) {

      /** @var \Drupal\flag\FlaggingInterface $flagging */
      $flagging = $flagging_handler->load($row->flagging_node_field_data_id);
      $project = $node_handler->load($row->node_field_data_node__field_project_nid);
      $applicant = $user_handler->load($flagging->getOwnerId());

      $pdf->AddPage();
      $pdf->SetFont('Arial', 'B', 16);
      $pdf->Cell(40, 10, $this->convertEncoding($project->label()));
      $pdf->Ln();

      if ($display == 'page_review') {

        $pdf->SetFont('Arial', 'B', 14);
        $pdf->Cell(40, 10, $this->t('Applicant information'));
        $pdf->Ln();

        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(20, 10, $this->t('Name:'));
        $pdf->SetFont('Arial', '', 12);
        $pdf->Cell(80, 10, $this->convertEncoding($applicant->getDisplayName()));
        $pdf->Ln();

        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(20, 10, $this->t('Email:'));
        $pdf->SetFont('Arial', '', 12);
        $pdf->Cell(80, 10, $this->convertEncoding($applicant->getEmail()));
        $pdf->Ln();

        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(40, 10, $this->t('About me:'));
        if ($text = $applicant->field_about_me->value) {
          $pdf->Ln();
          $this->addText($pdf, $text, TRUE);
        }
        $pdf->Ln();

        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(40, 10, $this->t('Student information'));
        $pdf->Ln();

        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(40, 10, $this->t('Year in college:'));
        if ($applicant->field_yr_in_college->entity) {
          $pdf->SetFont('Arial', '', 12);
          $pdf->Cell(80, 10, $this->convertEncoding($applicant->field_yr_in_college->entity->label()));
        }
        $pdf->Ln();

        $major = [];
        /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item */
        foreach ($applicant->field_major as $item) {
          $major[] = $item->entity->label();
        }
        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(20, 10, $this->t('Major:'));
        if ($major) {
          $pdf->SetFont('Arial', '', 12);
          $pdf->Cell(80, 10, $this->convertEncoding(implode(', ', $major)));
          $pdf->Ln();
        }

      } // In review?

      $pdf->SetFont('Arial', 'B', 12);
      $pdf->Cell(40, 10, $this->t('Application text:'));
      if ($text = $flagging->field_essay->value) {
        $pdf->Ln();
        $this->addText($pdf, $text, TRUE);
      }
      $pdf->Ln();

      if ($display == 'page_review') {
        if ($this->includeUploadedDcouments) {
          // Attempt to include the actual documents in the PDF.
          // Not overly reliable due to the various formats of PDFs, docs, etc.
          if ($resume = $applicant->field_resume->entity) {
            $this->addFile($pdf, $resume);
          }
          if ($transcript = $applicant->field_transcript->entity) {
            $this->addFile($pdf, $transcript);
          }
        }
        else {
          // Don't include docs, just say if they're there.
          $docs_uploaded = [];
          $docs_uploaded['resume'] = $applicant->field_resume->entity;
          $docs_uploaded['transcript'] = $applicant->field_transcript->entity;
          $docs_uploaded = array_filter($docs_uploaded);

          $pdf->SetFont('Arial', 'B', 12);
          $pdf->Cell(40, 10, $this->t('Documents'));
          $pdf->SetFont('Arial', '', 12);
          $pdf->Ln();
          $num_docs = count($docs_uploaded);
          $text = [];
          if ($num_docs == 2) {
            $text[] = $this->t('This student opted to upload both a resume and a transcript.');
            $text[] = $this->t("These can be viewed along with the student's full application and profile on the website under Mentor tasks > Applications.");
          }
          elseif ($num_docs == 1) {
            if ($docs_uploaded['resume']) {
              $uploaded = $this->t('resume');
              $not_uploaded = $this->t('transcript');
            }
            else {
              $uploaded = $this->t('transcript');
              $not_uploaded = $this->t('resume');
            }
            $text[] = $this->t('This student opted to upload their @uploaded but not their @not_uploaded.', [
              '@uploaded' => $uploaded,
              '@not_uploaded' => $not_uploaded,
            ]);
            $text[] = $this->t("Their @uploaded can be viewed along with their full application and profile on the website under Mentor tasks > Applications.", [
              '@uploaded' => $uploaded,
            ]);
          }
          else {
            $text[] = $this->t('This student opted not to upload their resume or transcript.');
          }
          $pdf->Write(5, implode("\n", $text));
        }
      } // In review?

    } // Loop thru rows.

    $site_config = $this->configFactory->get('system.site');
    $site_name = $site_config->get('name') ?? $this->t('Muser');
    $stage_text = ($display == 'page_review') ? $this->t('Review') : $this->t('Pending');
    $filename = $this->t('@site_name - Applications - @stage - @date', [
      '@site_name' => $site_name,
      '@stage' => $stage_text,
      '@date' => date('Y-m-d'),
    ]);
    $full_path = $this->fileSystem->createFilename($filename . '.pdf', './');
    $filename = pathinfo($full_path, PATHINFO_BASENAME);
    $content = $pdf->Output('S', $filename);

    $response = new Response();
    $response->headers->set('Content-Type', 'application/pdf');
    $response->headers->set('Content-Disposition', 'attachment;filename="' . $filename . '"');
    $response->setContent($content);
    return $response;

  }

  /**
   * Convert encoding of text.
   *
   * @param string $text
   *   Text in.
   *
   * @return array|false|string|string[]|null
   *   Text out.
   */
  public function convertEncoding(string $text) {
    return mb_convert_encoding($text, self::ENCODING);
  }

  /**
   * Adds text field to PDF.
   *
   * @param \setasign\Fpdi\Fpdi $pdf
   *   PDF object.
   * @param string $text
   *   Text to add.
   */
  public function addText(Fpdi &$pdf, string $text, $strip_tags = FALSE) {
    $tr = [
      "\n" => chr(30),
      "\r" => chr(30),
    ];
    $text = strtr($text, $tr);
    if ($strip_tags) {
      $text = preg_replace('~<style>.*?</style>~i', '', $text);
      $text = preg_replace('~<head>.*?</head>~i', '', $text);
      $text = preg_replace('~</p>|<br>~i', "\n\n", $text);
    }
    $text = preg_replace('~\r~', "\n", $text);
    $text = strtr($text, array_flip($tr));
    $text = preg_replace('~\n{2,}~', "\n", $text);
    if ($strip_tags) {
      $text = $this->convertEncoding($text);
      $text = strip_tags($text);
      $text = trim(html_entity_decode($text, ENT_QUOTES, self::ENCODING));
    }
    $pdf->SetFont('Arial', '', 12);
    $pdf->Write(5, $text);
//    $lines = explode("\n", $text);
//    foreach ($lines as $line) {
//      $pdf->Write(5, trim($line));
//      $pdf->Ln();
//      $pdf->Ln();
//    }
  }

  /**
   * Adds file to PDF.
   *
   * @param \setasign\Fpdi\Fpdi $pdf
   *   PDF object.
   * @param \Drupal\file\Entity\File $file
   *   File object.
   *
   * @throws \setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException
   * @throws \setasign\Fpdi\PdfParser\Filter\FilterException
   * @throws \setasign\Fpdi\PdfParser\PdfParserException
   * @throws \setasign\Fpdi\PdfParser\Type\PdfTypeException
   * @throws \setasign\Fpdi\PdfReader\PdfReaderException
   */
  public function addFile(Fpdi &$pdf, $file) {

    if (!$path = $this->fileSystem->realpath($file->getFileUri())) {
      // Can't get path.
      return;
    }

    switch ($file->getMimeType()) {

      case 'application/pdf':
        $this->addPdfFile($pdf, $path);
        break;

      case 'text/plain':
        $this->addTextFile($pdf, $path);
        break;

      default:
        // Try it as a Word doc.
        $this->addWordDoc($pdf, $path);
        break;

    } // End switch on mime type.

  }

  /**
   * Adds PDF file.
   *
   * @param \setasign\Fpdi\Fpdi $pdf
   * @param $path
   *
   * @throws \setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException
   * @throws \setasign\Fpdi\PdfParser\Filter\FilterException
   * @throws \setasign\Fpdi\PdfParser\PdfParserException
   * @throws \setasign\Fpdi\PdfParser\Type\PdfTypeException
   * @throws \setasign\Fpdi\PdfReader\PdfReaderException
   */
  public function addPdfFile(Fpdi &$pdf, $path) {
    try {
      $page_count = $pdf->setSourceFile($path);
      // Iterate through all pages.
      for ($page_num = 1; $page_num <= $page_count; $page_num++) {
        // iIport a page.
        $template_id = $pdf->importPage($page_num);
        $pdf->AddPage();
        // Use the imported page and adjust the page size.
        $pdf->useTemplate($template_id, ['adjustPageSize' => TRUE]);
      } // Loop thru pages.
    }
    catch (\Exception $exception) {
      // Log the exception.
      $this->loggerFactory->error('The PDF "@path" could not be exported for User ID @uid. Exception: "@exception" in @file:@line', [
        '@path' => $path,
        '@uid' => $this->currentUser->id(),
        '@exception' => $exception->getMessage(),
        '@file' => $exception->getFile(),
        '@line' => $exception->getLine(),
      ]);
      // Add an error message to the PDF.
      $filename = pathinfo($path, PATHINFO_BASENAME);
      $pdf->AddPage();
      $pdf->SetFont('Arial', 'B', 16);
      $pdf->Cell(20, 10, $this->t('Warning'));
      $pdf->Ln();
      $pdf->SetFont('Arial', 'I', 12);
      $pdf->Cell(80, 10, $this->t('The PDF "@file" could not be added to this PDF.', ['@file' => $filename]));
      $pdf->Ln();
      $pdf->Cell(80, 10, $this->t('To view it, go to the website under Mentor tasks > Applications.'));
      $pdf->Ln();
    }
  }

  /**
   * Adds text file.
   *
   * @param \setasign\Fpdi\Fpdi $pdf
   * @param $path
   *
   * @throws \setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException
   * @throws \setasign\Fpdi\PdfParser\Filter\FilterException
   * @throws \setasign\Fpdi\PdfParser\PdfParserException
   * @throws \setasign\Fpdi\PdfParser\Type\PdfTypeException
   * @throws \setasign\Fpdi\PdfReader\PdfReaderException
   */
  public function addTextFile(Fpdi &$pdf, $path, $strip_tags = FALSE) {
    try {
      if ($text = file_get_contents($path)) {
        $pdf->AddPage();
        $this->addText($pdf, $text, $strip_tags);
      }
    }
    catch (\Exception $exception) {
      // Log the exception.
      $this->loggerFactory->error('The text file "@path" could not be exported for User ID @uid. Exception: "@exception" in @file:@line', [
        '@path' => $path,
        '@uid' => $this->currentUser->id(),
        '@exception' => $exception->getMessage(),
        '@file' => $exception->getFile(),
        '@line' => $exception->getLine(),
      ]);
      // Add an error message to the PDF.
      $filename = pathinfo($path, PATHINFO_BASENAME);
      $pdf->AddPage();
      $pdf->SetFont('Arial', 'B', 16);
      $pdf->Cell(20, 10, $this->t('Warning'));
      $pdf->Ln();
      $pdf->SetFont('Arial', 'I', 12);
      $pdf->Cell(80, 10, $this->t('The text file "@file" could not be added to this PDF.', ['@file' => $filename]));
      $pdf->Ln();
      $pdf->Cell(80, 10, $this->t('To view it, go to the website under Mentor tasks > Applications.'));
      $pdf->Ln();
    }

  }

  /**
   * Parse Word doc and return content as HTML.
   *
   * Note:
   * For old versions of .doc files, this may throw a notice:
   * > Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object
   * > in PhpOffice\Common\XMLReader->getDomFromZip()
   * This is because those old versions are not supported.
   */
  protected function addWordDoc(&$pdf, $path) {
    $tmp_file_out = '';
    try {
      $tmp_name = md5($path . '|' . microtime());
      $tmp_file_out = $this->fileSystem->getTempDirectory() . '/' . $tmp_name . '-out.pdf';
      // Set up PhpWord and read file.
      PhpWordSettings::setPdfRendererPath('../vendor/dompdf/dompdf');
      PhpWordSettings::setPdfRendererName('DomPDF');
      if (!class_exists('ZipArchive')) {
        PhpWordSettings::setZipClass(PhpWordSettings::PCLZIP);
      }
      $php_word = @IOFactory::load($path);
      // Output the file as a PDF.
      $xml_writer = IOFactory::createWriter($php_word, 'PDF');
      $xml_writer->save($tmp_file_out);
      // Add the PDF to the document.
      $this->addPdfFile($pdf, $tmp_file_out);
    }
    catch (\Exception $exception) {
      // Could not parse Word Doc.
      // Log the exception.
      $this->loggerFactory->error('The document "@path" could not be exported as a Word Doc for User ID @uid. Exception: "@exception" in @file:@line', [
        '@path' => $path,
        '@uid' => $this->currentUser->id(),
        '@exception' => $exception->getMessage(),
        '@file' => $exception->getFile(),
        '@line' => $exception->getLine(),
      ]);
      // Add an error message to the PDF.
      $filename = pathinfo($path, PATHINFO_BASENAME);
      $pdf->AddPage();
      $pdf->SetFont('Arial', 'B', 16);
      $pdf->Cell(20, 10, $this->t('Warning'));
      $pdf->Ln();
      $pdf->SetFont('Arial', 'I', 12);
      $pdf->Cell(80, 10, $this->t('The document "@file" could not be added to this PDF.', ['@file' => $filename]));
      $pdf->Ln();
      $pdf->Cell(80, 10, $this->t('To view it, go to the website under Mentor tasks > Applications.'));
      $pdf->Ln();
    }
    if ($tmp_file_out && is_file($tmp_file_out)) {
      $this->fileSystem->unlink($tmp_file_out);
    }
  }

}

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

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