protected function validatePdfUpload(array &$form, FormStateInterface &$form_state, UploadedFile $file_upload, $file_field_name) { /** * @var $file_upload \Symfony\Component\HttpFoundation\File\UploadedFile */ if ($file_upload && $file_upload->isValid()) { // Move it to somewhere we know. $uploaded_filename = $file_upload->getClientOriginalName(); // Ensure the destination is unique; we deliberately use managed files, // but they are keyed on file URI, so we can't save the same one twice. $scheme = $this->config('fillpdf.settings')->get('scheme'); $destination = file_destination(FillPdf::buildFileUri($scheme, 'fillpdf/' . $uploaded_filename), FILE_EXISTS_RENAME); // Ensure our directory exists. $fillpdf_directory = FillPdf::buildFileUri($scheme, 'fillpdf'); $directory_exists = file_prepare_directory($fillpdf_directory, FILE_CREATE_DIRECTORY + FILE_MODIFY_PERMISSIONS); if ($directory_exists) { $file_moved = $this->fileSystem->moveUploadedFile($file_upload->getRealPath(), $destination); if ($file_moved) { // Create a File object from the uploaded file. $new_file = File::create([ 'uri' => $destination, 'uid' => $this->currentUser()->id(), ]); $errors = file_validate_extensions($new_file, 'pdf'); if (count($errors)) { $form_state->setErrorByName('upload_pdf', $this->t('Only PDF files are supported, and they must end in .pdf.')); } else { $form_state->setValue('upload_pdf', $new_file); } } else { $form_state->setErrorByName('upload_pdf', $this->t("Could not move your uploaded file from PHP's temporary location to Drupal file storage.")); } } else { $form_state->setErrorByName('upload_pdf', $this->t('Could not automatically create the <em>fillpdf</em> subdirectory. Please create this manually before uploading your PDF form.')); } } else { $form_state->setErrorByName('upload_pdf', $this->t('Your PDF could not be uploaded. Did you select one?')); } }
/** * @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 $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; }
/** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { if ($form_state->getValue('pdftk_path')) { $status = FillPdf::checkPdftkPath($form_state->getValue('pdftk_path')); if ($status === FALSE) { $form_state->setErrorByName('pdftk_path', $this->t('The path you have entered for <em>pdftk</em> is invalid. Please enter a valid path.')); } } }
/** * @param string $destination_path * @param array $token_objects * @param string $scheme * @return string */ protected function processDestinationPath($destination_path, $token_objects, $scheme = 'public') { $orig_path = $destination_path; $destination_path = trim($orig_path); // Replace any applicable tokens $types = []; if (isset($token_objects['node'])) { $types[] = 'node'; } elseif (isset($token_objects['webform'])) { $types[] = 'webform'; } // TODO: Do this kind of replacement with a common service instead, because I'm doing the same thing in like 3 places now. foreach ($types as $type) { $destination_path = $this->token->replace($destination_path, [$type => $token_objects[$type]], ['clear' => TRUE]); } // Slap on the files directory in front and return it $destination_path = FillPdf::buildFileUri($scheme, $destination_path); return $destination_path; }
/** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); /** @var FillPdfFormInterface $entity */ $entity = $this->entity; $form['tokens'] = [ '#type' => 'details', '#title' => $this->t('Tokens'), '#weight' => 11, 'token_tree' => $this->adminFormHelper->getAdminTokenForm(), ]; $entity_types = []; $entity_type_definitions = $this->entityManager->getDefinitions(); foreach ($entity_type_definitions as $machine_name => $definition) { $label = $definition->getLabel(); $entity_types[$machine_name] = "$machine_name ($label)"; } // @todo: Encapsulate this logic into a ::getDefaultEntityType() method on FillPdfForm $default_entity_type = $entity->get('default_entity_type')->first()->value; if (empty($default_entity_type)) { $default_entity_type = 'node'; } $form['default_entity_type'] = [ '#type' => 'select', '#title' => $this->t('Default entity type'), '#options' => $entity_types, '#weight' => 12.5, '#default_value' => $default_entity_type, ]; $fid = $entity->id(); /** @var FileInterface $file_entity */ $file_entity = File::load($entity->get('file')->first()->target_id); $pdf_info_weight = 0; $form['pdf_info'] = [ '#type' => 'fieldset', '#title' => $this->t('PDF form information'), '#weight' => $form['default_entity_id']['#weight'] + 1, 'submitted_pdf' => [ '#type' => 'item', '#title' => $this->t('Uploaded PDF'), '#description' => $file_entity->getFileUri(), '#weight' => $pdf_info_weight++, ], 'upload_pdf' => [ '#type' => 'file', '#title' => 'Update PDF template', '#description' => $this->t('Update the PDF template used by this form'), '#weight' => $pdf_info_weight++, ], 'sample_populate' => [ '#type' => 'item', '#title' => 'Sample PDF', '#description' => $this->l($this->t('See which fields are which in this PDF.'), $this->linkManipulator->generateLink([ 'fid' => $fid, 'sample' => TRUE, ])) . '<br />' . $this->t('If you have set a custom path on this PDF, the sample will be saved there silently.'), '#weight' => $pdf_info_weight++, ], 'form_id' => [ '#type' => 'item', '#title' => 'Form Info', '#description' => $this->t("Form ID: [@fid]. Populate this form with entity IDs, such as /fillpdf?fid=$fid&entity_type=node&entity_id=10<br/>", ['@fid' => $fid]), '#weight' => $pdf_info_weight, ], ]; if (!empty($entity->get('default_entity_id')->first()->value)) { $parameters = [ 'fid' => $fid, ]; $form['pdf_info']['populate_default'] = [ '#type' => 'item', '#title' => 'Fill PDF from default node', '#description' => $this->l($this->t('Download this PDF filled with data from the default entity (@entity_type:@entity).', [ '@entity_type' => $entity->default_entity_type->value, '@entity' => $entity->default_entity_id->value, ] ), $this->linkManipulator->generateLink($parameters)) . '<br />' . $this->t('If you have set a custom path on this PDF, the sample will be saved there silently.'), '#weight' => $form['pdf_info']['form_id']['#weight'] - 0.1, ]; } $additional_setting_set = $entity->destination_path->value || $entity->destination_redirect->value; $form['additional_settings'] = [ '#type' => 'details', '#title' => $this->t('Additional settings'), '#weight' => $form['pdf_info']['#weight'] + 1, '#open' => $additional_setting_set, ]; $form['destination_path']['#group'] = 'additional_settings'; $form['scheme']['#group'] = 'additional_settings'; $form['destination_redirect']['#group'] = 'additional_settings'; $form['replacements']['#group'] = 'additional_settings'; $form['replacements']['#weight'] = 1; // @todo: Add a button to let them attempt re-parsing if it failed. $form['fillpdf_fields']['fields'] = FillPdf::embedView('fillpdf_form_fields', 'block_1', $entity->id()); $form['fillpdf_fields']['#weight'] = 100; $form['export_fields'] = [ '#prefix' => '<div>', '#markup' => $this->l($this->t('Export these field mappings'), Url::fromRoute('entity.fillpdf_form.export_form', ['fillpdf_form' => $entity->id()])), '#suffix' => '</div>', '#weight' => 100, ]; $form['import_fields'] = [ '#prefix' => '<div>', '#markup' => $this->l($this->t('Import a previous export into this PDF'), Url::fromRoute('entity.fillpdf_form.import_form', ['fillpdf_form' => $entity->id()])), '#suffix' => '</div>', '#weight' => 100, ]; return $form; }