diff --git a/src/Plugin/EntityUsage/Track/CkeditorImage.php b/src/Plugin/EntityUsage/Track/CkeditorImage.php index e75a5b44c7b27c9bfd13c5f99ae93f1664707162..0c473970e7205dea52bb9be2136536835fd6431b 100644 --- a/src/Plugin/EntityUsage/Track/CkeditorImage.php +++ b/src/Plugin/EntityUsage/Track/CkeditorImage.php @@ -24,6 +24,13 @@ class CkeditorImage extends TextFieldEmbedBase { $xpath = new \DOMXPath($dom); $entities = []; foreach ($xpath->query('//img[@data-entity-type and @data-entity-uuid]') as $node) { + // Skip elements with empty data-entity-uuid/type attributes. + if (empty($node->getAttribute('data-entity-uuid')) + || empty($node->getAttribute('data-entity-type')) + ) { + continue; + } + // Note that this does not cover 100% of the situations. In the (unlikely // but possible) use case where the user embeds the same entity twice in // the same field, we are just recording 1 usage for this target entity, diff --git a/src/Plugin/EntityUsage/Track/EntityEmbed.php b/src/Plugin/EntityUsage/Track/EntityEmbed.php index b721f21d5529f43dd8b7e3356b8a23627f4dfd59..a3f0bc55792cc474068d1ddb7217f0a57eec48af 100644 --- a/src/Plugin/EntityUsage/Track/EntityEmbed.php +++ b/src/Plugin/EntityUsage/Track/EntityEmbed.php @@ -24,6 +24,12 @@ class EntityEmbed extends TextFieldEmbedBase { $xpath = new \DOMXPath($dom); $entities = []; foreach ($xpath->query('//drupal-entity[@data-entity-type and @data-entity-uuid]') as $node) { + // Skip elements with empty data-entity-uuid/type attributes. + if (empty($node->getAttribute('data-entity-uuid')) + || empty($node->getAttribute('data-entity-type')) + ) { + continue; + } // Note that this does not cover 100% of the situations. In the (unlikely // but possible) use case where the user embeds the same entity twice in // the same field, we are just recording 1 usage for this target entity, diff --git a/src/Plugin/EntityUsage/Track/LinkIt.php b/src/Plugin/EntityUsage/Track/LinkIt.php index 6bff6e310017d6206add05b9b9041c8b802f69c2..49b32fcf909fc1111ceb15793b8ea8057404759a 100644 --- a/src/Plugin/EntityUsage/Track/LinkIt.php +++ b/src/Plugin/EntityUsage/Track/LinkIt.php @@ -24,6 +24,13 @@ class LinkIt extends TextFieldEmbedBase { $xpath = new \DOMXPath($dom); $entities = []; foreach ($xpath->query('//a[@data-entity-type and @data-entity-uuid]') as $node) { + // Skip elements with empty data-entity-uuid/type attributes. + if (empty($node->getAttribute('data-entity-uuid')) + || empty($node->getAttribute('data-entity-type')) + ) { + continue; + } + // Note that this does not cover 100% of the situations. In the (unlikely // but possible) use case where the user embeds the same entity twice in // the same field, we are just recording 1 usage for this target entity, diff --git a/src/Plugin/EntityUsage/Track/MediaEmbed.php b/src/Plugin/EntityUsage/Track/MediaEmbed.php index 22540bf513675b1ef9374f1b48fdd4fdbb9f386c..d04bd67866587da02fc30b79fa33b52cc5e0439f 100644 --- a/src/Plugin/EntityUsage/Track/MediaEmbed.php +++ b/src/Plugin/EntityUsage/Track/MediaEmbed.php @@ -24,6 +24,10 @@ class MediaEmbed extends TextFieldEmbedBase { $xpath = new \DOMXPath($dom); $entities = []; foreach ($xpath->query('//drupal-media[@data-entity-type="media" and @data-entity-uuid]') as $node) { + // Skip elements with empty data-entity-uuid attributes. + if (empty($node->getAttribute('data-entity-uuid'))) { + continue; + } // Note that this does not cover 100% of the situations. In the (unlikely // but possible) use case where the user embeds the same entity twice in // the same field, we are just recording 1 usage for this target entity, diff --git a/tests/src/FunctionalJavascript/EmbeddedContentTest.php b/tests/src/FunctionalJavascript/EmbeddedContentTest.php index f6992e9635fdf2bcdd787f3ac80fa0a5460a2c5a..50f84f1737d6733018a96a5a500d6699f1ce252d 100644 --- a/tests/src/FunctionalJavascript/EmbeddedContentTest.php +++ b/tests/src/FunctionalJavascript/EmbeddedContentTest.php @@ -112,6 +112,27 @@ class EmbeddedContentTest extends EntityUsageJavascriptTestBase { $this->assertEquals($expected, $usage); } + /** + * Tests the Entity Embed plugin parsing does not error with malformed HTML. + */ + public function testEntityEmbedWithMalformedHtml() { + $embedded_text = '<drupal-entity data-embed-button="node" data-entity-embed-display="entity_reference:entity_reference_label" data-entity-embed-display-settings="{"link":1}" data-entity-type="" data-entity-uuid=""></drupal-entity>'; + + $node = Node::create([ + 'type' => 'eu_test_ct', + 'title' => 'This is a node with malformed EntityEmbed HTML', + 'field_eu_test_rich_text' => [ + 'value' => $embedded_text, + 'format' => 'eu_test_text_format', + ], + ]); + + $node->save(); + + $this->drupalGet('/node/' . $node->id()); + $this->assertSession()->pageTextContains('This is a node with malformed EntityEmbed HTML'); + } + /** * Tests the LinkIt parsing. */ @@ -214,6 +235,27 @@ class EmbeddedContentTest extends EntityUsageJavascriptTestBase { $this->assertEquals([], $usage); } + /** + * Tests the LinkIt plugin parsing does not error with malformed HTML. + */ + public function testLinkItdWithMalformedHtml() { + $embedded_text = '<p>foo <a data-entity-substitution="canonical" data-entity-type="" data-entity-uuid="">linked text</a> bar</p>'; + + $node = Node::create([ + 'type' => 'eu_test_ct', + 'title' => 'This is a node with malformed LinkIt HTML', + 'field_eu_test_rich_text' => [ + 'value' => $embedded_text, + 'format' => 'eu_test_text_format', + ], + ]); + + $node->save(); + + $this->drupalGet('/node/' . $node->id()); + $this->assertSession()->pageTextContains('This is a node with malformed LinkIt HTML'); + } + /** * Tests the HtmlLink parsing. */ @@ -505,4 +547,25 @@ class EmbeddedContentTest extends EntityUsageJavascriptTestBase { $this->assertEquals($expected, $usage); } + /** + * Tests the MediaEmbed plugin parsing does not error with malformed HTML. + */ + public function testMediaEmbeddWithMalformedHtml() { + $embedded_text = '<drupal-media data-entity-type="media" data-entity-uuid=""></drupal-media>'; + + $node = Node::create([ + 'type' => 'eu_test_ct', + 'title' => 'This is a node with malformed MediaEmbed HTML', + 'field_eu_test_rich_text' => [ + 'value' => $embedded_text, + 'format' => 'eu_test_text_format', + ], + ]); + + $node->save(); + + $this->drupalGet('/node/' . $node->id()); + $this->assertSession()->pageTextContains('This is a node with malformed MediaEmbed HTML'); + } + }