diff --git a/src/FillPdfLinkManipulatorInterface.php b/src/FillPdfLinkManipulatorInterface.php index 9a849c043091c3080bb68ea8ceb964d0bc190bf4..cedd9442bc25b0aa12af35479ac4e6dc49f19726 100644 --- a/src/FillPdfLinkManipulatorInterface.php +++ b/src/FillPdfLinkManipulatorInterface.php @@ -62,8 +62,11 @@ interface FillPdfLinkManipulatorInterface { * always be downloaded. TRUE if yes, otherwise NULL. * flatten: false|null Flag indicating if the populated file should * be flattened. FALSE if not, otherwise NULL. + * + * @throws \InvalidArgumentException + * If $link contains no query string or doesn't specify a valid FillPdfForm. */ - public static function parseLink(Url $link); + public function parseLink(Url $link); /** * Generates a FillPdf Url from the given parameters. diff --git a/src/Service/FillPdfLinkManipulator.php b/src/Service/FillPdfLinkManipulator.php index 80ac7395c9c712c07d6bafd51a11a5ee5c72a428..ec001a8f208e762c06fbf4a18cde8e289056641a 100644 --- a/src/Service/FillPdfLinkManipulator.php +++ b/src/Service/FillPdfLinkManipulator.php @@ -24,7 +24,15 @@ class FillPdfLinkManipulator implements FillPdfLinkManipulatorInterface { $path = $request->getUri(); $request_url = $this->createUrlFromString($path); - return static::parseLink($request_url); + return $this->parseLink($request_url); + } + + /** + * {@inheritdoc} + */ + public function parseUrlString($url) { + $link = $this->createUrlFromString($url); + return $this->parseLink($link); } /** @@ -50,105 +58,124 @@ class FillPdfLinkManipulator implements FillPdfLinkManipulatorInterface { /** * {@inheritdoc} */ - public static function parseLink(Url $link) { + public function parseLink(Url $link) { $query = $link->getOption('query'); if (!$query) { throw new \InvalidArgumentException("This link doesn't specify a query string, so failing."); } - $request_context = [ - 'entity_ids' => [], - 'fid' => NULL, - 'sample' => FALSE, - 'force_download' => FALSE, - 'flatten' => TRUE, - ]; + if (empty($query['fid'])) { + throw new \InvalidArgumentException('No FillPdfForm was specified in the query string, so failing.'); + } - if (!empty($query['fid'])) { - $request_context['fid'] = $query['fid']; + $fillpdf_form = FillPdfForm::load($query['fid']); + if (!$fillpdf_form) { + throw new \InvalidArgumentException("The requested FillPdfForm doesn't exist, so failing."); } - else { - throw new \InvalidArgumentException('No FillPdfForm was specified in the query string, so failing.'); + + // Set the fid, merging in evaluated boolean flags. + $context = [ + 'fid' => $query['fid'], + ] + static::parseBooleanFlags($query); + + // Early return if PDF is just to be populated with sample data. + if ($context['sample'] === TRUE) { + $context['entity_ids'] = []; + return $context; } + // No sample and no entities given, so try enriching with defaults. + if (empty($query['entity_id']) && empty($query['entity_ids'])) { + $default_entity_id = $fillpdf_form->default_entity_id->value; + if ($default_entity_id) { + $default_entity_type = $fillpdf_form->default_entity_type->value; + if (empty($default_entity_type)) { + $default_entity_type = 'node'; + } + $query['entity_ids'] = [ + $default_entity_type => [$default_entity_id => $default_entity_id], + ]; + } + } + + // Merge in parsed entities. + $context += static::parseEntityIds($query); + + return $context; + } + + /** + * Helper method parsing boolean flags. + * + * @param array $query + * Array of query parameters. + * + * @return array + * An associative array representing the request context. + * + * @internal + */ + public static function parseBooleanFlags(array $query) { + $context = [ + 'force_download' => FALSE, + 'flatten' => TRUE, + 'sample' => FALSE, + ]; + if (isset($query['download']) && filter_var($query['download'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === TRUE) { - $request_context['force_download'] = TRUE; + $context['force_download'] = TRUE; } if (isset($query['flatten']) && $query['flatten'] !== '' && filter_var($query['flatten'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === FALSE) { - $request_context['flatten'] = FALSE; + $context['flatten'] = FALSE; } - // Early return if PDF is just to be populated with sample data. if (isset($query['sample']) && filter_var($query['sample'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === TRUE) { - $request_context['sample'] = TRUE; - return $request_context; + $context['sample'] = TRUE; } - if (!empty($query['entity_type'])) { - $request_context['entity_type'] = $query['entity_type']; + return $context; + } + + /** + * Helper method parsing entities. + * + * @param array $query + * Array of query parameters. + * + * @return array + * An associative array representing the request context. + * + * @internal + */ + public static function parseEntityIds(array $query) { + if (!empty($query['entity_id'])) { + $query['entity_ids'] = [$query['entity_id']]; } - if (!empty($query['entity_id']) || !empty($query['entity_ids'])) { - $entity_ids = (!empty($query['entity_id']) ? [$query['entity_id']] : $query['entity_ids']); + $context = [ + 'entity_ids' => [], + ]; + if (!empty($query['entity_ids'])) { + $common_entity_type = !empty($query['entity_type']) ? $query['entity_type'] : 'node'; // Re-key entity IDs so they can be loaded easily with loadMultiple(). - // If we have type information, add it to the types array, and remove it - // in order to make sure we only store the ID in the entity_ids key. - foreach ($entity_ids as $entity_id) { + foreach ($query['entity_ids'] as $entity_id) { $entity_id_parts = explode(':', $entity_id); if (count($entity_id_parts) == 2) { $entity_type = $entity_id_parts[0]; $entity_id = $entity_id_parts[1]; } - elseif (!empty($request_context['entity_type'])) { - $entity_type = $request_context['entity_type']; - } else { - $entity_type = 'node'; - } - $request_context['entity_ids'] += [ - $entity_type => [], - ]; - - $request_context['entity_ids'][$entity_type][$entity_id] = $entity_id; - } - } - else { - // Populate defaults. - $fillpdf_form = FillPdfForm::load($request_context['fid']); - - if (!$fillpdf_form) { - throw new \InvalidArgumentException("The requested FillPdfForm doesn't exist, so failing."); - } - - $default_entity_id = $fillpdf_form->default_entity_id->value; - if ($default_entity_id) { - $default_entity_type = $fillpdf_form->default_entity_type->value; - if (empty($default_entity_type)) { - $default_entity_type = 'node'; + $entity_type = $common_entity_type; } - - $request_context['entity_ids'] = [ - $default_entity_type => [$default_entity_id => $default_entity_id], - ]; + $context['entity_ids'][$entity_type][$entity_id] = $entity_id; } } - // We've processed the shorthand forms, so unset them. - unset($request_context['entity_id'], $request_context['entity_type']); - - return $request_context; - } - - /** - * {@inheritdoc} - */ - public function parseUrlString($url) { - $link = $this->createUrlFromString($url); - return static::parseLink($link); + return $context; } /** diff --git a/tests/src/Functional/LinkManipulatorTest.php b/tests/src/Functional/LinkManipulatorTest.php index 9bb148da1cf8d60a183b48c437962aa110af33be..b7ee8aff8274be7dcb80224dea58752b3103f755 100644 --- a/tests/src/Functional/LinkManipulatorTest.php +++ b/tests/src/Functional/LinkManipulatorTest.php @@ -3,6 +3,8 @@ namespace Drupal\Tests\fillpdf\Functional; use Drupal\Core\Url; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\fillpdf\Traits\TestFillPdfTrait; /** * @coversDefaultClass \Drupal\fillpdf\Service\FillPdfLinkManipulator @@ -11,7 +13,22 @@ use Drupal\Core\Url; * * @todo Convert into a unit test. */ -class LinkManipulatorTest extends FillPdfUploadTestBase { +class LinkManipulatorTest extends BrowserTestBase { + + use TestFillPdfTrait; + + static public $modules = ['fillpdf_test']; + protected $profile = 'minimal'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->configureFillPdf(); + $this->initializeUser(); + } /** * Tests handling of a non-existing FillPdfForm ID. @@ -47,4 +64,33 @@ class LinkManipulatorTest extends FillPdfUploadTestBase { $this->assertSession()->pageTextContains("The requested FillPdfForm doesn't exist, so failing."); } + /** + * Tests parsing a sample link. + */ + public function testSampleLink() { + $this->uploadTestPdf('fillpdf_test_v3.pdf'); + $form_id = $this->getLatestFillPdfForm(); + + // Prepare a query with the sample flag and all kinds of (redundant) + // entity parameters set. + $query = [ + 'fid' => $form_id, + 'entity_type' => 'user', + 'entity_id' => 3, + 'entity_ids' => ['node:1', 'node:2'], + 'sample' => TRUE, + ]; + $url = Url::fromRoute('fillpdf.populate_pdf', [], ['query' => $query]); + $context = \Drupal::service('fillpdf.link_manipulator')->parseLink($url); + + // Test 'fid' and 'sample' parameters are correctly set. + $this->assertEquals($form_id, $context['fid']); + $this->assertEquals(TRUE, $context['sample']); + + // Make sure 'entity_ids' is empty and all other entity parameters stripped. + $this->assertEmpty($context['entity_ids']); + $this->assertArrayNotHasKey('entity_type', $context); + $this->assertArrayNotHasKey('entity_id', $context); + } + } diff --git a/tests/src/Unit/LinkManipulator/ParseLinkBooleansTest.php b/tests/src/Unit/LinkManipulator/ParseBooleanFlagsTest.php similarity index 60% rename from tests/src/Unit/LinkManipulator/ParseLinkBooleansTest.php rename to tests/src/Unit/LinkManipulator/ParseBooleanFlagsTest.php index 1476d7199acb7206b90fcb2b2df4c0f6c3701888..8050f0cee727ad05a1bd50709d56b2cb5ea702db 100644 --- a/tests/src/Unit/LinkManipulator/ParseLinkBooleansTest.php +++ b/tests/src/Unit/LinkManipulator/ParseBooleanFlagsTest.php @@ -3,51 +3,50 @@ namespace Drupal\Tests\fillpdf\Unit\LinkManipulator; use Drupal\fillpdf\Service\FillPdfLinkManipulator; -use Drupal\Core\Url; use Drupal\Tests\UnitTestCase; /** - * @covers \Drupal\fillpdf\Service\FillPdfLinkManipulator::parseLink + * @coversDefaultClass \Drupal\fillpdf\Service\FillPdfLinkManipulator * * @group fillpdf */ -class ParseLinkBooleansTest extends UnitTestCase { +class ParseBooleanFlagsTest extends UnitTestCase { /** * Tests &sample=, &download= and &flatten= query parameters. * - * @dataProvider dataProvider + * @covers ::parseBooleanFlags + * + * @dataProvider providerTestBooleanFlags */ - public function testBooleans($input, $expected) { - $request_context = FillPdfLinkManipulator::parseLink($this->link($input)); + public function testBooleanFlags($input, $expected) { + $context = FillPdfLinkManipulator::parseBooleanFlags($this->buildQuery($input)); - $this->assertEquals(is_null($expected) ? FALSE : $expected, $request_context['sample']); + $this->assertEquals(is_null($expected) ? FALSE : $expected, $context['sample']); - $this->assertEquals(is_null($expected) ? FALSE : $expected, $request_context['force_download']); + $this->assertEquals(is_null($expected) ? FALSE : $expected, $context['force_download']); - $this->assertEquals(is_null($expected) ? TRUE : $expected, $request_context['flatten']); + $this->assertEquals(is_null($expected) ? TRUE : $expected, $context['flatten']); } /** - * Input helper for testBooleans(). + * Input helper for testBooleanFlags(). */ - public function link($input) { - return Url::fromRoute('fillpdf.populate_pdf', [], [ - 'query' => [ - 'fid' => 1, - 'entity_type' => 'node', - 'entity_id' => 1, - 'sample' => $input, - 'download' => $input, - 'flatten' => $input, - ], - ]); + public function buildQuery($input) { + return [ + 'fid' => 1, + 'entity_type' => 'node', + 'entity_id' => 1, + 'sample' => $input, + 'download' => $input, + 'flatten' => $input, + ]; } /** - * Data provider for testBooleans(). + * Data provider for testBooleanFlags(). */ - public function dataProvider() { + public function providerTestBooleanFlags() { return [ ['1', TRUE], ['true', TRUE], diff --git a/tests/src/Unit/LinkManipulator/ParseEntityIdsTest.php b/tests/src/Unit/LinkManipulator/ParseEntityIdsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..010d1b96846072994eb4c180b893ced7ee6f8f48 --- /dev/null +++ b/tests/src/Unit/LinkManipulator/ParseEntityIdsTest.php @@ -0,0 +1,91 @@ +<?php + +namespace Drupal\Tests\fillpdf\Unit\LinkManipulator; + +use Drupal\fillpdf\Service\FillPdfLinkManipulator; +use Drupal\Tests\UnitTestCase; + +/** + * @coversDefaultClass \Drupal\fillpdf\Service\FillPdfLinkManipulator + * + * @group fillpdf + */ +class ParseEntityIdsTest extends UnitTestCase { + + /** + * Tests parsing entities. + * + * @covers ::parseEntityIds + * + * @dataProvider providerTestEntityIds + */ + public function testEntityIds($entity_ids, $entity_type, $entity_id, $expected) { + $context = FillPdfLinkManipulator::parseEntityIds($this->buildQuery($entity_ids, $entity_type, $entity_id)); + + $this->assertEquals($expected, $context['entity_ids']); + } + + /** + * Input helper for testEntityIds(). + */ + public function buildQuery($entity_ids, $entity_type, $entity_id) { + $query = [ + 'fid' => 1, + ]; + if (!empty($entity_ids)) { + $query['entity_ids'] = $entity_ids; + } + if (!empty($entity_type)) { + $query['entity_type'] = $entity_type; + } + if (!empty($entity_id)) { + $query['entity_id'] = $entity_id; + } + return $query; + } + + /** + * Data provider for testEntityIds(). + */ + public function providerTestEntityIds() { + $cases = []; + $cases[0] = [ + [], NULL, NULL, [], + ]; + $cases[1] = [ + ['node:1'], NULL, NULL, ['node' => [1 => '1']], + ]; + $cases[2] = [ + ['term:5'], NULL, NULL, ['term' => [5 => '5']], + ]; + $cases[3] = [ + ['node:1', 'node:2'], NULL, NULL, ['node' => [1 => '1', 2 => '2']], + ]; + $cases[4] = [ + ['node:1', 'node:1'], NULL, NULL, ['node' => [1 => '1']], + ]; + $cases[5] = [ + ['user:3', 'term:5'], NULL, NULL, ['user' => [3 => '3'], 'term' => [5 => '5']], + ]; + $cases[6] = [ + NULL, NULL, 1, ['node' => [1 => '1']], + ]; + $cases[7] = [ + NULL, 'term', 5, ['term' => [5 => '5']], + ]; + $cases[8] = [ + ['1'], 'node', NULL, ['node' => [1 => '1']], + ]; + $cases[9] = [ + ['1', '2'], 'node', NULL, ['node' => [1 => '1', 2 => '2']], + ]; + $cases[10] = [ + ['3', '4'], 'user', NULL, ['user' => [3 => '3', 4 => '4']], + ]; + $cases[11] = [ + ['3', '4'], 'user', 5, ['user' => [5 => '5']], + ]; + return $cases; + } + +} diff --git a/tests/src/Unit/LinkManipulator/ParseLinkSampleTest.php b/tests/src/Unit/LinkManipulator/ParseLinkSampleTest.php deleted file mode 100644 index 39d12666ad994d5685684180428943fe47463e63..0000000000000000000000000000000000000000 --- a/tests/src/Unit/LinkManipulator/ParseLinkSampleTest.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -namespace Drupal\Tests\fillpdf\Unit\LinkManipulator; - -use Drupal\fillpdf\Service\FillPdfLinkManipulator; -use Drupal\Core\Url; -use Drupal\Tests\UnitTestCase; - -/** - * @covers \Drupal\fillpdf\Service\FillPdfLinkManipulator::parseLink - * - * @group fillpdf - */ -class ParseLinkSampleTest extends UnitTestCase { - - /** - * Tests boolean query parameters. - * - * @dataProvider dataProvider - */ - public function testSample($sample, $entity_ids, $entity_type = NULL, $entity_id = NULL) { - $request_context = FillPdfLinkManipulator::parseLink($this->link($sample, $entity_ids, $entity_type, $entity_id)); - - // Test '&fid=' is set. - $this->assertEquals(1, $request_context['fid']); - - // Test '&entity_ids=' is only set if '&sample=' isn't. - if ($request_context['sample']) { - $this->assertEmpty($request_context['entity_ids']); - } - else { - $expected = [ - 'node' => ['1' => '1'], - ]; - if (is_array($entity_ids) && count($entity_ids) == 2) { - $expected['node']['2'] = '2'; - } - $this->assertEquals($expected, $request_context['entity_ids']); - } - } - - /** - * Input helper for testBooleanFlags(). - */ - public function link($sample, $entity_ids, $entity_type = NULL, $entity_id = NULL) { - $query = [ - 'fid' => 1, - 'sample' => $sample, - ]; - - if (!empty($entity_ids)) { - $query['entity_ids'] = $entity_ids; - } - if (!empty($entity_type)) { - $query['entity_type'] = $entity_type; - } - if (!empty($entity_id)) { - $query['entity_id'] = $entity_id; - } - - return Url::fromRoute('fillpdf.populate_pdf', [], ['query' => $query]); - } - - /** - * Data provider for testSample(). - * - * @todo Mock FillPdfForm::load() so we can also test default entities. - */ - public function dataProvider() { - return [ - ['true', ['node:1']], - ['false', ['node:1']], - ['true', ['node:1', 'node:2']], - ['false', ['node:1', 'node:2']], - ['true', NULL, 'node', '1'], - ['false', NULL, 'node', '1'], - ]; - } - -}