Skip to content
Snippets Groups Projects
Commit 706359a3 authored by Bernd Oliver Suenderhauf's avatar Bernd Oliver Suenderhauf
Browse files

Issue #3039482 by Pancho: Use managed_file element for PDF template uploads

parent 601fb3a4
No related branches found
No related tags found
No related merge requests found
...@@ -64,6 +64,7 @@ class FillPdfForm extends ContentEntityBase implements FillPdfFormInterface { ...@@ -64,6 +64,7 @@ class FillPdfForm extends ContentEntityBase implements FillPdfFormInterface {
$fields['file'] = BaseFieldDefinition::create('file') $fields['file'] = BaseFieldDefinition::create('file')
->setLabel(t('The associated managed file.')) ->setLabel(t('The associated managed file.'))
->setSetting('file_extensions', 'pdf')
->setDescription(t('The associated managed file.')); ->setDescription(t('The associated managed file.'));
$overview_url = Url::fromUri('base://admin/structure/fillpdf')->toString(); $overview_url = Url::fromUri('base://admin/structure/fillpdf')->toString();
......
...@@ -21,8 +21,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; ...@@ -21,8 +21,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/ */
class FillPdfFormForm extends ContentEntityForm { class FillPdfFormForm extends ContentEntityForm {
use FillPdfFormUploadTrait;
/** /**
* The FillPdf admin form helper. * The FillPdf admin form helper.
* *
...@@ -169,31 +167,45 @@ class FillPdfFormForm extends ContentEntityForm { ...@@ -169,31 +167,45 @@ class FillPdfFormForm extends ContentEntityForm {
'#title' => $this->t('Uploaded PDF'), '#title' => $this->t('Uploaded PDF'),
'#description' => $file_entity->getFileUri(), '#description' => $file_entity->getFileUri(),
'#weight' => $pdf_info_weight++, '#weight' => $pdf_info_weight++,
], ]
'upload_pdf' => [ ];
'#type' => 'file',
$upload_location = FillPdf::buildFileUri($this->config('fillpdf.settings')->get('scheme'), 'fillpdf');
if (!file_prepare_directory($upload_location, FILE_CREATE_DIRECTORY + FILE_MODIFY_PERMISSIONS)) {
$this->messenger()->addError($this->t('The %directory subdirectory does not exist or is not writable. Please check permissions.', [
'%directory' => 'fillpdf',
]));
}
else {
$form['pdf_info']['upload_pdf'] = [
'#type' => 'managed_file',
'#title' => $this->t('Update PDF template'), '#title' => $this->t('Update PDF template'),
'#attributes' => ['accept' => 'application/pdf'], '#accept' => 'application/pdf',
'#upload_validators' => [
'file_validate_extensions' => ['pdf'],
],
'#upload_location' => $upload_location,
'#description' => $this->t('Update the PDF file used as template by this form.'), '#description' => $this->t('Update the PDF file used as template by this form.'),
'#weight' => $pdf_info_weight++, '#weight' => $pdf_info_weight++,
], ];
'sample_populate' => [ }
'#type' => 'item',
'#title' => $this->t('Sample PDF'), $form['pdf_info']['sample_populate'] = [
'#description' => $this->l($this->t('See which fields are which in this PDF.'), '#type' => 'item',
$this->linkManipulator->generateLink([ '#title' => $this->t('Sample PDF'),
'fid' => $fid, '#description' => $this->l($this->t('See which fields are which in this PDF.'),
'sample' => TRUE, $this->linkManipulator->generateLink([
])) . '<br />' . 'fid' => $fid,
$this->t('If you have set a custom path on this PDF, the sample will be saved there silently.'), 'sample' => TRUE,
'#weight' => $pdf_info_weight++, ])) . '<br />' .
], $this->t('If you have set a custom path on this PDF, the sample will be saved there silently.'),
'form_id' => [ '#weight' => $pdf_info_weight++,
'#type' => 'item', ];
'#title' => $this->t('Form info'), $form['pdf_info']['form_id'] = [
'#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]), '#type' => 'item',
'#weight' => $pdf_info_weight, '#title' => $this->t('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)) { if (!empty($entity->get('default_entity_id')->first()->value)) {
...@@ -253,18 +265,6 @@ class FillPdfFormForm extends ContentEntityForm { ...@@ -253,18 +265,6 @@ class FillPdfFormForm extends ContentEntityForm {
return $form; return $form;
} }
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
$files = $this->getRequest()->files->get('files');
if (isset($files['upload_pdf'])) {
$this->validatePdfUpload($form, $form_state, $files['upload_pdf']);
}
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -272,13 +272,13 @@ class FillPdfFormForm extends ContentEntityForm { ...@@ -272,13 +272,13 @@ class FillPdfFormForm extends ContentEntityForm {
/** @var \Drupal\fillpdf\FillPdfFormInterface $entity */ /** @var \Drupal\fillpdf\FillPdfFormInterface $entity */
$entity = $this->getEntity(); $entity = $this->getEntity();
/** @var \Drupal\file\FileInterface $file */
$file = $form_state->getValue('upload_pdf');
$message = []; $message = [];
$message[] = $this->t('FillPDF Form %link has been updated.', ['%link' => $entity->toLink()->toString()]); $message[] = $this->t('FillPDF Form %link has been updated.', ['%link' => $entity->toLink()->toString()]);
if ($file) { if ($form_state->getValue('upload_pdf')) {
/** @var \Drupal\file\FileInterface $new_file */
$new_file = File::load($form_state->getValue('upload_pdf')['0']);
$existing_fields = $this->entityHelper->getFormFields($entity); $existing_fields = $this->entityHelper->getFormFields($entity);
// Delete existing fields. // Delete existing fields.
...@@ -287,7 +287,7 @@ class FillPdfFormForm extends ContentEntityForm { ...@@ -287,7 +287,7 @@ class FillPdfFormForm extends ContentEntityForm {
$existing_field->delete(); $existing_field->delete();
} }
$added = $this->inputHelper->attachPdfToForm($file, $entity); $added = $this->inputHelper->attachPdfToForm($new_file, $entity);
$form_fields = $added['fields']; $form_fields = $added['fields'];
......
<?php
namespace Drupal\fillpdf\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
use Drupal\fillpdf\Component\Utility\FillPdf;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Class FillPdfFormUploadTrait
* @package Drupal\fillpdf\Form
*/
trait FillPdfFormUploadTrait {
protected function validatePdfUpload(array &$form, FormStateInterface &$form_state, UploadedFile $file_upload) {
/**
* @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?'));
}
}
}
...@@ -7,16 +7,15 @@ use Drupal\Core\Entity\Query\QueryFactory; ...@@ -7,16 +7,15 @@ use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface; use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\fillpdf\FillPdfBackendManager; use Drupal\fillpdf\FillPdfBackendManager;
use Drupal\fillpdf\InputHelperInterface; use Drupal\fillpdf\InputHelperInterface;
use Drupal\fillpdf\Component\Utility\FillPdf;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FillPdfOverviewForm extends FillPdfAdminFormBase { class FillPdfOverviewForm extends FillPdfAdminFormBase {
use FillPdfFormUploadTrait;
/** /**
* The backend manager (finds the filling plugin the user selected). * The backend manager (finds the filling plugin the user selected).
...@@ -84,45 +83,49 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase { ...@@ -84,45 +83,49 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
$config = $this->config('fillpdf.settings'); $config = $this->config('fillpdf.settings');
// Only show PDF upload form if fillpdf is configured. // Only show PDF upload form if fillpdf is configured.
if ($config->get('backend')) { if (!$config->get('backend')) {
// If using FillPDF Service, ensure XML-RPC module is present.
if ($config->get('backend') !== 'fillpdf_service' || $this->moduleHandler->moduleExists('xmlrpc')) {
$form['upload_pdf'] = [
'#type' => 'file',
'#title' => $this->t('Upload PDF template'),
'#attributes' => ['accept' => 'application/pdf'],
'#description' => $this->t('Upload a fillable PDF file to create a new form.'),
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Upload'),
'#weight' => 15,
];
}
else {
drupal_set_message($this->t('You must install the <a href=":xmlrpc">contributed XML-RPC module</a> in order to use FillPDF Service as your PDF-filling method.', [
'@xmlrpc' => Url::fromUri('https://drupal.org/project/xmlrpc')
->toString(),
]), 'error');
}
}
else {
$form['message'] = [ $form['message'] = [
'#markup' => '<p>' . $this->t('Before you can upload PDF files, you must @link.', ['@link' => new FormattableMarkup($this->l($this->t('configure FillPDF'), Url::fromRoute('fillpdf.settings')), [])]) . '</p>', '#markup' => '<p>' . $this->t('Before you can upload PDF files, you must @link.', ['@link' => new FormattableMarkup($this->l($this->t('configure FillPDF'), Url::fromRoute('fillpdf.settings')), [])]) . '</p>',
]; ];
drupal_set_message($this->t('FillPDF is not configured.'), 'error'); $this->messenger()->addError($this->t('FillPDF is not configured.'));
return $form;
} }
return $form;
}
public function validateForm(array &$form, FormStateInterface $form_state) { // If using FillPDF Service, ensure XML-RPC module is present.
$files = $this->getRequest()->files->get('files'); if ($config->get('backend') === 'fillpdf_service' && !$this->moduleHandler->moduleExists('xmlrpc')) {
$this->messenger()->addError($this->t('You must install the <a href=":xmlrpc">contributed XML-RPC module</a> in order to use FillPDF Service as your PDF-filling method.', [
'@xmlrpc' => Url::fromUri('https://drupal.org/project/xmlrpc')->toString(),
]));
return $form;
}
$file_upload = !empty($files) && array_key_exists('upload_pdf', $files) ? $files['upload_pdf'] : NULL; $upload_location = FillPdf::buildFileUri($this->config('fillpdf.settings')->get('scheme'), 'fillpdf');
if ($file_upload) { if (!file_prepare_directory($upload_location, FILE_CREATE_DIRECTORY + FILE_MODIFY_PERMISSIONS)) {
$this->validatePdfUpload($form, $form_state, $file_upload); $this->messenger()->addError($this->t('The %directory subdirectory does not exist or is not writable. Please check permissions.', [
'%directory' => 'fillpdf',
]));
} }
else {
$form['upload_pdf'] = [
'#type' => 'managed_file',
'#title' => $this->t('Upload PDF template'),
'#accept' => 'application/pdf',
'#upload_validators' => [
'file_validate_extensions' => ['pdf'],
],
'#upload_location' => $upload_location,
'#description' => $this->t('Upload a fillable PDF file to create a new form.'),
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Create'),
'#weight' => 15,
];
}
return $form;
} }
/** /**
...@@ -134,11 +137,12 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase { ...@@ -134,11 +137,12 @@ class FillPdfOverviewForm extends FillPdfAdminFormBase {
* The current state of the form. * The current state of the form.
*/ */
public function submitForm(array &$form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\file\FileInterface $file */ if ($form_state->getValue('upload_pdf')) {
$file = $form_state->getValue('upload_pdf'); /** @var \Drupal\file\FileInterface $file */
if ($file) { $file = File::load($form_state->getValue('upload_pdf')['0']);
$added = $this->inputHelper->attachPdfToForm($file); $added = $this->inputHelper->attachPdfToForm($file);
/** @var \Drupal\fillpdf\Entity\FillPdfForm $fillpdf_form */
$fillpdf_form = $added['form']; $fillpdf_form = $added['form'];
$fid = $fillpdf_form->id(); $fid = $fillpdf_form->id();
......
...@@ -206,6 +206,11 @@ class FillPdfSettingsForm extends ConfigFormBase { ...@@ -206,6 +206,11 @@ class FillPdfSettingsForm extends ConfigFormBase {
} }
break; break;
} }
$directory = FillPdf::buildFileUri($form_state->getValue('scheme'), 'fillpdf');
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY + FILE_MODIFY_PERMISSIONS)) {
$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.'));
}
} }
/** /**
......
...@@ -39,7 +39,7 @@ class TemplateUploadTest extends BrowserTestBase { ...@@ -39,7 +39,7 @@ class TemplateUploadTest extends BrowserTestBase {
$this->drupalGet('admin/structure/fillpdf'); $this->drupalGet('admin/structure/fillpdf');
// Check if the 'accept' attribute is correctly set. // Check if the 'accept' attribute is correctly set.
$this->assertSession()->elementAttributeContains('css', '#edit-upload-pdf', 'accept', 'application/pdf'); $this->assertSession()->elementAttributeContains('css', 'input#edit-upload-pdf-upload', 'accept', 'application/pdf');
// Without a PDF file being supplied, no FillPdfForm should be created. // Without a PDF file being supplied, no FillPdfForm should be created.
$this->uploadTestPdf(NULL); $this->uploadTestPdf(NULL);
...@@ -51,7 +51,7 @@ class TemplateUploadTest extends BrowserTestBase { ...@@ -51,7 +51,7 @@ class TemplateUploadTest extends BrowserTestBase {
$this->drupalPostForm(NULL, ['files[upload_pdf]' => $file->uri], 'Upload'); $this->drupalPostForm(NULL, ['files[upload_pdf]' => $file->uri], 'Upload');
$this->assertSession()->statusCodeEquals(200); $this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextNotContains('New FillPDF form has been created.'); $this->assertSession()->pageTextNotContains('New FillPDF form has been created.');
$this->assertSession()->pageTextContains('Only PDF files are supported, and they must end in .pdf.'); $this->assertSession()->pageTextContains('Only files with the following extensions are allowed: pdf.');
// With a PDF file being supplied, a new FillPdfForm should be created. // With a PDF file being supplied, a new FillPdfForm should be created.
$this->uploadTestPdf('fillpdf_test_v3.pdf'); $this->uploadTestPdf('fillpdf_test_v3.pdf');
...@@ -71,14 +71,14 @@ class TemplateUploadTest extends BrowserTestBase { ...@@ -71,14 +71,14 @@ class TemplateUploadTest extends BrowserTestBase {
$this->assertSession()->statusCodeEquals(200); $this->assertSession()->statusCodeEquals(200);
// Check if the 'accept' attribute is correctly set. // Check if the 'accept' attribute is correctly set.
$this->assertSession()->elementAttributeContains('css', '#edit-upload-pdf', 'accept', 'application/pdf'); $this->assertSession()->elementAttributeContains('css', 'input#edit-upload-pdf-upload', 'accept', 'application/pdf');
// When trying to upload a .txt file, validation should set an error. // When trying to upload a .txt file, validation should set an error.
$files = $this->getTestFiles('text'); $files = $this->getTestFiles('text');
$file = reset($files); $file = reset($files);
$this->drupalPostForm(NULL, ['files[upload_pdf]' => $file->uri], 'Save'); $this->drupalPostForm(NULL, ['files[upload_pdf]' => $file->uri], 'Save');
$this->assertSession()->statusCodeEquals(200); $this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Only PDF files are supported, and they must end in .pdf.'); $this->assertSession()->pageTextContains('Only files with the following extensions are allowed: pdf.');
} }
/** /**
......
...@@ -83,7 +83,7 @@ trait TestFillPdfTrait { ...@@ -83,7 +83,7 @@ trait TestFillPdfTrait {
$edit = [ $edit = [
'files[upload_pdf]' => isset($path) ? $path : NULL, 'files[upload_pdf]' => isset($path) ? $path : NULL,
]; ];
$this->drupalPostForm('admin/structure/fillpdf', $edit, 'Upload'); $this->drupalPostForm('admin/structure/fillpdf', $edit, 'Create');
$this->assertSession()->statusCodeEquals(200); $this->assertSession()->statusCodeEquals(200);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment