From 655583f7f3d257ecef556883fb3629242bf492bc Mon Sep 17 00:00:00 2001
From: Kevin Kaland <kevin@wizonesolutions.com>
Date: Thu, 19 Nov 2015 22:22:46 +0100
Subject: [PATCH] Issue #2359213: Implement other backends.

---
 lib/JavaBridge                                |   1 +
 .../FillPdfBackend/LocalFillPdfBackend.php    | 108 +++++++++++++
 .../FillPdfBackend/PdftkFillPdfBackend.php    | 147 ++++++++++++++++++
 3 files changed, 256 insertions(+)
 create mode 120000 lib/JavaBridge
 create mode 100644 src/Plugin/FillPdfBackend/LocalFillPdfBackend.php
 create mode 100644 src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php

diff --git a/lib/JavaBridge b/lib/JavaBridge
new file mode 120000
index 0000000..92e195d
--- /dev/null
+++ b/lib/JavaBridge
@@ -0,0 +1 @@
+/var/lib/tomcat6/webapps/JavaBridge
\ No newline at end of file
diff --git a/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php b/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php
new file mode 100644
index 0000000..ae59ef0
--- /dev/null
+++ b/src/Plugin/FillPdfBackend/LocalFillPdfBackend.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\fillpdf\Plugin\FillPdfBackend\LocalFillPdfBackend.
+ */
+
+namespace Drupal\fillpdf\Plugin\FillPdfBackend;
+
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\File\FileSystem;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\file\Entity\File;
+use Drupal\file\FileInterface;
+use Drupal\fillpdf\FillPdfBackendPluginInterface;
+use Drupal\fillpdf\FillPdfFormInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @Plugin(
+ *   id = "local",
+ *   label = @Translation("Locally-installed PHP/JavaBridge")
+ * )
+ */
+class LocalFillPdfBackend implements FillPdfBackendPluginInterface, ContainerFactoryPluginInterface {
+  /** @var array $configuration */
+  protected $configuration;
+
+  /** @var \Drupal\Core\File\FileSystem */
+  protected $fileSystem;
+
+  public function __construct(FileSystem $file_system, array $configuration, $plugin_id, $plugin_definition) {
+    $this->configuration = $configuration;
+    $this->fileSystem = $file_system;
+  }
+
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($container->get('file_system'), $configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function parse(FillPdfFormInterface $fillpdf_form) {
+    /** @var FileInterface $file */
+    $file = File::load($fillpdf_form->file->target_id);
+    $content = file_get_contents($file->getFileUri());
+
+    $require = drupal_get_path('module', 'fillpdf') . '/lib/JavaBridge/java/Java.inc';
+    require_once DRUPAL_ROOT . '/' . $require;
+    try {
+      $fillpdf = new \java('com.ocdevel.FillpdfService', base64_encode($content), 'bytes');
+      $fields = java_values($fillpdf->parse());
+    }
+    catch (\JavaException $e) {
+      drupal_set_message(java_truncate((string) $e), 'error');
+    }
+
+    return $fields;
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function populateWithFieldData(FillPdfFormInterface $pdf_form, array $field_mapping, array $context) {
+    /** @var FileInterface $original_file */
+    $original_file = File::load($pdf_form->file->target_id);
+    $pdf_data = file_get_contents($original_file->getFileUri());
+    $fields = $field_mapping['fields'];
+
+    $require = drupal_get_path('module', 'fillpdf') . '/lib/JavaBridge/java/Java.inc';
+    require_once DRUPAL_ROOT . '/' . $require;
+    try {
+      $fillpdf = new \java('com.ocdevel.FillpdfService', base64_encode($pdf_data), 'bytes');
+      foreach ($fields as $key => $field) {
+        if (substr($field, 0, 7) == '{image}') {
+          // Remove {image} marker.
+          $image_filepath = substr($field, 7);
+          $image_realpath = $this->fileSystem->realpath($image_filepath);
+          $fillpdf->image($key, $image_realpath, 'file');
+        }
+        else {
+          $fillpdf->text($key, $field);
+        }
+      }
+    }
+    catch (\JavaException $e) {
+      drupal_set_message(java_truncate((string) $e), 'error');
+      return NULL;
+    }
+    try {
+      if ($context['flatten']) {
+        $populated_pdf = java_values(base64_decode($fillpdf->toByteArray()));
+      }
+      else {
+        $populated_pdf = java_values(base64_decode($fillpdf->toByteArrayUnflattened()));
+      }
+    }
+    catch (\JavaException $e) {
+      drupal_set_message(java_truncate((string) $e), 'error');
+      return NULL;
+    }
+
+    return $populated_pdf;
+  }
+
+}
diff --git a/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php b/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php
new file mode 100644
index 0000000..e5a7cd9
--- /dev/null
+++ b/src/Plugin/FillPdfBackend/PdftkFillPdfBackend.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\fillpdf\Plugin\FillPdfBackend\PdftkFillPdfBackend.
+ */
+
+namespace Drupal\fillpdf\Plugin\FillPdfBackend;
+
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\File\FileSystem;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\file\Entity\File;
+use Drupal\file\FileInterface;
+use Drupal\fillpdf\Component\Utility\FillPdf;
+use Drupal\fillpdf\FillPdfBackendPluginInterface;
+use Drupal\fillpdf\FillPdfFormInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @Plugin(
+ *   id = "pdftk",
+ *   label = @Translation("PDFtk"),
+ * )
+ */
+class PdftkFillPdfBackend implements FillPdfBackendPluginInterface, ContainerFactoryPluginInterface {
+
+  use StringTranslationTrait;
+
+  /** @var array $configuration */
+  protected $configuration;
+
+  /** @var \Drupal\Core\File\FileSystem */
+  protected $fileSystem;
+
+  /** @var \Drupal\Core\Config\ConfigFactoryInterface */
+  protected $configFactory;
+
+  public function __construct(FileSystem $file_system, ConfigFactoryInterface $config, array $configuration, $plugin_id, $plugin_definition) {
+    $this->configuration = $configuration;
+    $this->fileSystem = $file_system;
+    $this->configFactory = $config;
+  }
+
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($container->get('file_system'), $container->get('config.factory'), $configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function parse(FillPdfFormInterface $fillpdf_form) {
+    /** @var FileInterface $file */
+    $file = File::load($fillpdf_form->file->target_id);
+    $filename = $file->getFileUri();
+
+    $path_to_pdftk = $this->getPdftkPath();
+    $status = FillPdf::checkPdftkPath($path_to_pdftk);
+    if ($status === FALSE) {
+      drupal_set_message($this->t('pdftk not properly installed.'), 'error');
+      return [];
+    }
+
+    // Use exec() to call pdftk (because it will be easier to go line-by-line parsing the output) and pass $content via stdin. Retrieve the fields with dump_data_fields.
+    $output = [];
+    exec($path_to_pdftk . ' ' . escapeshellarg($this->fileSystem->realpath($filename)) . ' dump_data_fields', $output, $status);
+    if (count($output) === 0) {
+      drupal_set_message($this->t('PDF does not contain fillable fields.'), 'warning');
+      return [];
+    }
+
+    // Build a simple map of dump_data_fields keys to our own array keys
+    $data_fields_map = [
+      'FieldType' => 'type',
+      'FieldName' => 'name',
+      'FieldFlags' => 'flags',
+      'FieldJustification' => 'justification',
+    ];
+
+    // Build the fields array
+    $fields = [];
+    $fieldindex = -1;
+    foreach ($output as $line => $lineitem) {
+      if ($lineitem == '---') {
+        $fieldindex++;
+        continue;
+      }
+      // Separate the data key from the data value
+      $linedata = explode(':', $lineitem);
+      if (in_array($linedata[0], array_keys($data_fields_map), NULL)) {
+        $fields[$fieldindex][$data_fields_map[$linedata[0]]] = trim($linedata[1]);
+      }
+    }
+
+    return $fields;
+  }
+
+  /**
+   * @return array|mixed|null|string
+   */
+  protected function getPdftkPath() {
+    $path_to_pdftk = $this->configFactory->get('fillpdf.settings')
+      ->get('pdftk_path');
+
+    if (empty($path_to_pdftk)) {
+      $path_to_pdftk = 'pdftk';
+      return $path_to_pdftk;
+    }
+    return $path_to_pdftk;
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function populateWithFieldData(FillPdfFormInterface $pdf_form, array $field_mapping, array $context) {
+    /** @var FileInterface $original_file */
+    $original_file = File::load($pdf_form->file->target_id);
+    $filename = $original_file->getFileUri();
+    $fields = $field_mapping['fields'];
+
+    module_load_include('inc', 'fillpdf', 'xfdf');
+    $xfdfname = $filename . '.xfdf';
+    $xfdf = create_xfdf(basename($xfdfname), $fields);
+    // Generate the file
+    $xfdffile = file_save_data($xfdf, $xfdfname, FILE_EXISTS_RENAME);
+
+    // Now feed this to pdftk and save the result to a variable
+    $path_to_pdftk = $this->getPdftkPath();
+    ob_start();
+    passthru($path_to_pdftk . ' ' . escapeshellarg($this->fileSystem->realpath($filename)) . ' fill_form ' . escapeshellarg($this->fileSystem->realpath($xfdffile->getFileUri())) . ' output - ' . ($context['flatten'] ? 'flatten ' : '') . 'drop_xfa');
+    $data = ob_get_clean();
+    if ($data === FALSE) {
+      drupal_set_message($this->t('pdftk not properly installed. No PDF generated.'), 'error');
+    }
+    $xfdffile->delete();
+
+    if ($data) {
+      return $data;
+    }
+
+    return FALSE;
+  }
+
+}
-- 
GitLab