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

Issue #3048065 by Pancho: Fatal error when a file storage scheme is no longer available

parent 7c9ab8eb
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,7 @@ namespace Drupal\fillpdf\Controller; ...@@ -4,6 +4,7 @@ namespace Drupal\fillpdf\Controller;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\file\Entity\File; use Drupal\file\Entity\File;
use Drupal\file\FileInterface; use Drupal\file\FileInterface;
use Drupal\fillpdf\Component\Helper\FillPdfMappingHelper; use Drupal\fillpdf\Component\Helper\FillPdfMappingHelper;
...@@ -17,6 +18,7 @@ use Drupal\fillpdf\TokenResolverInterface; ...@@ -17,6 +18,7 @@ use Drupal\fillpdf\TokenResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\Link;
/** /**
* Class HandlePdfController. * Class HandlePdfController.
...@@ -289,9 +291,30 @@ class HandlePdfController extends ControllerBase { ...@@ -289,9 +291,30 @@ class HandlePdfController extends ControllerBase {
} }
// Determine the appropriate action for the PDF. // Determine the appropriate action for the PDF.
$destination_path_set = !empty($fillpdf_form->destination_path->value); $scheme = $fillpdf_form->getStorageScheme();
$redirect = !empty($fillpdf_form->destination_redirect->value); $available_schemes = array_keys(\Drupal::service('stream_wrapper_manager')->getWrappers(StreamWrapperInterface::WRITE_VISIBLE));
if ($destination_path_set) {
// The configured file storage scheme is no longer available.
if (!empty($scheme) && !in_array($scheme, $available_schemes)) {
$id = $fillpdf_form->id();
// @todo: We can simpify this once an admin_title is #required,
// see https://www.drupal.org/project/fillpdf/issues/3040776.
$label = $fillpdf_form->label() . " ({$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(),
]));
}
// Unset the scheme to make sure the file is only sent to the browser.
$scheme = NULL;
}
if (!empty($scheme) && !empty($fillpdf_form->getStoragePath())) {
$redirect = !empty($fillpdf_form->destination_redirect->value);
$action_plugin_id = $redirect ? 'redirect' : 'save'; $action_plugin_id = $redirect ? 'redirect' : 'save';
} }
else { else {
......
...@@ -177,6 +177,20 @@ class FillPdfForm extends ContentEntityBase implements FillPdfFormInterface { ...@@ -177,6 +177,20 @@ class FillPdfForm extends ContentEntityBase implements FillPdfFormInterface {
return $field_storage->loadMultiple($field_ids); return $field_storage->loadMultiple($field_ids);
} }
/**
* {@inheritdoc}
*/
public function getStorageScheme() {
return $this->get('scheme')->value;
}
/**
* {@inheritdoc}
*/
public function getStoragePath() {
return $this->get('destination_path')->value;
}
/** /**
* Allowed values callback for 'scheme' base field definition. * Allowed values callback for 'scheme' base field definition.
* *
......
...@@ -19,4 +19,22 @@ interface FillPdfFormInterface extends ContentEntityInterface { ...@@ -19,4 +19,22 @@ interface FillPdfFormInterface extends ContentEntityInterface {
*/ */
public function getFormFields(); public function getFormFields();
/**
* Gets this FillPdfForm's storage scheme.
*
* @return string
* The storage scheme to be used for PDF files generated from this
* FillPdfForm.
*/
public function getStorageScheme();
/**
* Gets this FillPdfForm's storage path.
*
* @return string
* The storage path to be used for PDF files generated from this
* FillPdfForm.
*/
public function getStoragePath();
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
namespace Drupal\fillpdf\Plugin\FillPdfActionPlugin; namespace Drupal\fillpdf\Plugin\FillPdfActionPlugin;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
/** /**
...@@ -22,15 +23,13 @@ class FillPdfRedirectAction extends FillPdfSaveAction { ...@@ -22,15 +23,13 @@ class FillPdfRedirectAction extends FillPdfSaveAction {
* Saves the PDF file to the filesystem and redirects to it. * Saves the PDF file to the filesystem and redirects to it.
* *
* @return \Symfony\Component\HttpFoundation\RedirectResponse * @return \Symfony\Component\HttpFoundation\RedirectResponse
* Redirects user to the generated PDF file. * Redirects user to the generated PDF file, or if saving the file fails,
* to the front page.
*/ */
public function execute() { public function execute() {
$saved_file = $this->savePdf(); $saved_file = $this->savePdf();
$url = ($saved_file !== FALSE) ? $saved_file->toUrl() : Url::fromRoute('<front>');
// Get file URI, then return a RedirectResponse to it. return new RedirectResponse($url->toString());
$destination = $saved_file->url();
return new RedirectResponse($destination);
} }
} }
...@@ -102,4 +102,58 @@ class HandlePdfControllerTest extends FillPdfUploadTestBase { ...@@ -102,4 +102,58 @@ class HandlePdfControllerTest extends FillPdfUploadTestBase {
} }
} }
/**
* Tests handling of an unavailable storage scheme.
*/
public function testStorageSchemePrivate() {
$this->uploadTestPdf('fillpdf_test_v3.pdf');
$form_id = $this->getLatestFillPdfForm();
$previous_file_id = $this->getLastFileId();
$edit = [
'admin_title[0][value]' => 'Scheme test',
'scheme' => 'private',
'destination_path[0][value]' => 'test',
];
$this->drupalPostForm(NULL, $edit, 'Save');
$fillpdf_route = Url::fromRoute('fillpdf.populate_pdf', [], [
'query' => [
'fid' => $form_id,
],
]);
// Hit the generation route. Make sure we are redirected to the front page.
$this->drupalGet($fillpdf_route);
$this->assertSession()->addressNotEquals('/fillpdf');
$this->assertSession()->statusCodeEquals(200);
// Get back to the front page and make sure the file was stored in the
// private storage.
$this->drupalGet('<front>');
$this->assertSession()->pageTextNotContains('File storage scheme private:// is unavailable');
$this->assertEquals(++$previous_file_id, $this->getLastFileId(), 'Generated file was stored.');
$this->assertStringStartsWith('private://', File::load($this->getLastFileId())->getFileUri());
// Now remove the private path from settings.php and rebuild the container.
$this->writeSettings([
'settings' => [
'file_private_path' => (object) [
'value' => '',
'required' => TRUE,
],
],
]);
$this->rebuildContainer();
// Hit the generation route again. This time we should be redirected to the
// PDF file. Make sure no PHP error occured.
$this->drupalGet($fillpdf_route);
$this->assertSession()->addressEquals('/fillpdf');
$this->assertSession()->statusCodeEquals(200);
// Get back to the front page and check if an error was set, and we didn't
// try to store the file.
$this->drupalGet('<front>');
$this->assertSession()->pageTextContains("File storage scheme private:// is unavailable, so a PDF file generated from FillPDF form Scheme test ($form_id) could not be stored.");
$this->assertEquals($previous_file_id, $this->getLastFileId(), 'Generated file was not stored.');
}
} }
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