From ae68eb93ea851831d70b41cb234cbfbd9b31601c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:39:51 +0100 Subject: [PATCH 01/11] EZP-23513: implement Expanding converter --- .../Tests/XmlText/Converter/ExpandingTest.php | 84 +++++ .../expanding/input/001-embedSingle.xml | 8 + .../input/002-compressedParagraph.xml | 11 + .../input/003-compressedParagraphs.xml | 14 + .../expanding/input/004-linkedEmbed.xml | 9 + .../input/005-linkedEmbedWrapped.xml | 10 + .../input/006-linkedEmbedDoubleWrapped.xml | 10 + .../input/007-linkedEmbedDoubleWrapped2.xml | 10 + .../_fixtures/expanding/input/008-table.xml | 42 +++ .../expanding/input/009-embedInline.xml | 10 + .../expanding/output/001-embedSingle.xml | 6 + .../output/002-compressedParagraph.xml | 11 + .../output/003-compressedParagraphs.xml | 18 ++ .../expanding/output/004-linkedEmbed.xml | 13 + .../output/005-linkedEmbedWrapped.xml | 14 + .../output/006-linkedEmbedDoubleWrapped.xml | 14 + .../output/007-linkedEmbedDoubleWrapped2.xml | 16 + .../_fixtures/expanding/output/008-table.xml | 42 +++ .../expanding/output/009-embedInline.xml | 10 + .../FieldType/XmlText/Converter/Expanding.php | 301 ++++++++++++++++++ 20 files changed, 653 insertions(+) create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/ExpandingTest.php create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/001-embedSingle.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/002-compressedParagraph.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/003-compressedParagraphs.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/004-linkedEmbed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/005-linkedEmbedWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/006-linkedEmbedDoubleWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/007-linkedEmbedDoubleWrapped2.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/008-table.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/009-embedInline.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/001-embedSingle.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/002-compressedParagraph.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/003-compressedParagraphs.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/004-linkedEmbed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/005-linkedEmbedWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/006-linkedEmbedDoubleWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/007-linkedEmbedDoubleWrapped2.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/008-table.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/009-embedInline.xml create mode 100644 eZ/Publish/Core/FieldType/XmlText/Converter/Expanding.php diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/ExpandingTest.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/ExpandingTest.php new file mode 100644 index 00000000000..373fff51fa5 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/ExpandingTest.php @@ -0,0 +1,84 @@ +preserveWhiteSpace = false; + $document->formatOutput = false; + + if ( $isPath === true ) + { + $xml = file_get_contents( $xml ); + } + + $document->loadXml( $xml ); + + return $document; + } + + /** + * @param string $inputFilePath + * @param string $outputFilePath + * + * @dataProvider providerForTestConvert + */ + public function testConvert( $inputFilePath, $outputFilePath ) + { + $inputDocument = $this->createDocument( $inputFilePath ); + + $converter = new Expanding(); + $converter->convert( $inputDocument ); + + $outputDocument = $this->createDocument( $outputFilePath ); + + $this->assertEquals( + $outputDocument, + $inputDocument + ); + } +} diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/001-embedSingle.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/001-embedSingle.xml new file mode 100644 index 00000000000..113607a2a3a --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/001-embedSingle.xml @@ -0,0 +1,8 @@ + +
+ + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/002-compressedParagraph.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/002-compressedParagraph.xml new file mode 100644 index 00000000000..6d83048f28b --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/002-compressedParagraph.xml @@ -0,0 +1,11 @@ + +
+ The paragraph below is close to blowing up. + + + Tick tick tick three nasty bugs + + The paragraph above has detonated. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/003-compressedParagraphs.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/003-compressedParagraphs.xml new file mode 100644 index 00000000000..4c9e3761627 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/003-compressedParagraphs.xml @@ -0,0 +1,14 @@ + +
+ Speak, vision of the night, Tell me why you haunt me so. + + Speak, ere the morning light, Whisper all my heart would know, + + Dawn ever finds you gone, Back to where the shadows dwell, + + Speak, my beloved speak, Tho' you only say "Farewell". + + Speak! Speak! +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/004-linkedEmbed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/004-linkedEmbed.xml new file mode 100644 index 00000000000..4e78bf15217 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/004-linkedEmbed.xml @@ -0,0 +1,9 @@ + +
+ + Hello goodbye + + Hesperus entreats thy light, Goddess excellently bright. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/005-linkedEmbedWrapped.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/005-linkedEmbedWrapped.xml new file mode 100644 index 00000000000..e867a3f9197 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/005-linkedEmbedWrapped.xml @@ -0,0 +1,10 @@ + +
+ Bless us then with wished sight + + Ihavenoideawhat isgoingonhere + + Thou who makes a day of night +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/006-linkedEmbedDoubleWrapped.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/006-linkedEmbedDoubleWrapped.xml new file mode 100644 index 00000000000..4adc6d51801 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/006-linkedEmbedDoubleWrapped.xml @@ -0,0 +1,10 @@ + +
+ When doubts and fears cause the tears that blind me. + + Whybedumbif you'vecometofindme? + + Speak to me and I'll follow, leaving all the world behind me. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/007-linkedEmbedDoubleWrapped2.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/007-linkedEmbedDoubleWrapped2.xml new file mode 100644 index 00000000000..4ebfad8d039 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/007-linkedEmbedDoubleWrapped2.xml @@ -0,0 +1,10 @@ + +
+ Stormy weather turns to blue + + don't come inagain like that,it isn't funnyand I can paysomeone elseto make the orchestrations + + Here's a song to take with you +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/008-table.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/008-table.xml new file mode 100644 index 00000000000..ec09b0aa1f9 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/008-table.xml @@ -0,0 +1,42 @@ + +
+
+
Heading 2
+
Heading 2
+
+
Heading 3
+ + + + + +
+
+
Heading 2
+
Heading 2
+
+
Heading 3
+
Heading 3
+
+
+ + + + + +
+
+
Heading 2
+
+
Heading 3
+
+
+
+
+
+
+
+
+
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/009-embedInline.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/009-embedInline.xml new file mode 100644 index 00000000000..906e937b3bf --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/input/009-embedInline.xml @@ -0,0 +1,10 @@ + +
+ When doubts and fears cause the tears that blind me. + + Whybedumbif you'vecometofindme? + + Speak to me and I'll follow, leaving all the world behind me. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/001-embedSingle.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/001-embedSingle.xml new file mode 100644 index 00000000000..f321de53a03 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/001-embedSingle.xml @@ -0,0 +1,6 @@ + +
+ +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/002-compressedParagraph.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/002-compressedParagraph.xml new file mode 100644 index 00000000000..b77e8f93684 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/002-compressedParagraph.xml @@ -0,0 +1,11 @@ + +
+ The paragraph below is close to blowing up. + + + Tick tick tick three nasty bugs + + The paragraph above has detonated. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/003-compressedParagraphs.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/003-compressedParagraphs.xml new file mode 100644 index 00000000000..a3a3997869b --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/003-compressedParagraphs.xml @@ -0,0 +1,18 @@ + +
+ Speak, vision of the night, Tell me why you haunt me so. + + Speak, ere the morning light, Whisper all my heart would know, + + + + Dawn ever finds you gone, Back to where the shadows dwell, + + + + Speak, my beloved speak, Tho' you only say "Farewell". + + Speak! Speak! +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/004-linkedEmbed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/004-linkedEmbed.xml new file mode 100644 index 00000000000..5a58c18a226 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/004-linkedEmbed.xml @@ -0,0 +1,13 @@ + +
+ + Hello + + + + goodbye + + Hesperus entreats thy light, Goddess excellently bright. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/005-linkedEmbedWrapped.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/005-linkedEmbedWrapped.xml new file mode 100644 index 00000000000..01437577c32 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/005-linkedEmbedWrapped.xml @@ -0,0 +1,14 @@ + +
+ Bless us then with wished sight + + Ihavenoidea + + + + what isgoingonhere + + Thou who makes a day of night +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/006-linkedEmbedDoubleWrapped.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/006-linkedEmbedDoubleWrapped.xml new file mode 100644 index 00000000000..37929c57512 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/006-linkedEmbedDoubleWrapped.xml @@ -0,0 +1,14 @@ + +
+ When doubts and fears cause the tears that blind me. + + Whybedumbif you've + + + + cometofindme? + + Speak to me and I'll follow, leaving all the world behind me. +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/007-linkedEmbedDoubleWrapped2.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/007-linkedEmbedDoubleWrapped2.xml new file mode 100644 index 00000000000..38bb7e38ce3 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/007-linkedEmbedDoubleWrapped2.xml @@ -0,0 +1,16 @@ + +
+ Stormy weather turns to blue + + don't come inagain like that,it isn't funny + + + + + + and I can paysomeone elseto make the orchestrations + + Here's a song to take with you +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/008-table.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/008-table.xml new file mode 100644 index 00000000000..d6c8eb54b84 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/008-table.xml @@ -0,0 +1,42 @@ + +
+
+
Heading 2
+
Heading 2
+
+
Heading 3
+ + + + + +
+
+
Heading 2
+
Heading 2
+
+
Heading 3
+
Heading 3
+
+
+ + + + + +
+
+
Heading 2
+
+
Heading 3
+
+
+
+
+
+
+
+
+
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/009-embedInline.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/009-embedInline.xml new file mode 100644 index 00000000000..906e937b3bf --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/expanding/output/009-embedInline.xml @@ -0,0 +1,10 @@ + +
+ When doubts and fears cause the tears that blind me. + + Whybedumbif you'vecometofindme? + + Speak to me and I'll follow, leaving all the world behind me. +
diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/Expanding.php b/eZ/Publish/Core/FieldType/XmlText/Converter/Expanding.php new file mode 100644 index 00000000000..e8bcf35bd4d --- /dev/null +++ b/eZ/Publish/Core/FieldType/XmlText/Converter/Expanding.php @@ -0,0 +1,301 @@ + array( + "link" => true, + ), + "table" => array(), + "ul" => array(), + "ol" => array(), + "literal" => array(), + ); + + public function convert( DOMDocument $document ) + { + // First mark temporary paragraphs by checking the namespace as an attribute. + // Reason: as namespace on an element is inherited for all children, it is unusable + // in XSL transformation. + /** @var \DOMElement $paragraph */ + foreach ( $document->getElementsByTagName( 'paragraph' ) as $paragraph ) + { + if ( $paragraph->hasAttribute( 'xmlns:tmp' ) ) + { + $paragraph->setAttribute( 'ez-temporary', 1 ); + } + } + + $xpath = new DOMXPath( $document ); + $containedExpression = "//" . implode( "|//", array_keys( $this->containmentMap ) ); + // Select all paragraphs containing elements that need expansion, + // except temporary paragraphs + $xpathExpression = "//paragraph[not(@ez-temporary=1) and ($containedExpression)]"; + + $paragraphs = $xpath->query( $xpathExpression ); + + $paragraphsDepthSorted = array(); + + foreach ( $paragraphs as $paragraph ) + { + $paragraphsDepthSorted[$this->getNodeDepth( $paragraph )][] = $paragraph; + } + + // Process deepest paragraphs first to avoid conflicts + krsort( $paragraphsDepthSorted, SORT_NUMERIC ); + + foreach ( $paragraphsDepthSorted as $paragraphs ) + { + foreach ( $paragraphs as $paragraph ) + { + $this->expandParagraph( $document, $paragraph ); + } + } + } + + /** + * Expands the given $paragraph element, as defined in containment map. + * + * @param \DOMDocument $document + * @param \DOMElement $paragraph + */ + protected function expandParagraph( DOMDocument $document, DOMElement $paragraph ) + { + $paragraph->parentNode->replaceChild( + $this->expandElement( $document, $paragraph ), + $paragraph + ); + } + + /** + * Expands the given $paragraph element, as defined in containment map. + * + * Returns document fragment holding expanded elements, which can be used by the + * caller to replace expanded child. + * + * Implemented as a separate method for the benefit of recursion. + * + * @param \DOMDocument $document + * @param \DOMElement $element + * + * @return \DOMDocumentFragment + */ + protected function expandElement( DOMDocument $document, DOMElement $element ) + { + $fragment = $document->createDocumentFragment(); + $expandingElement = $this->cloneAndEmpty( $element ); + + /** @var \DOMElement $node */ + foreach ( $element->childNodes as $node ) + { + // If node was untangled continue with next one + // New expanding element will be started by the sub-routine in that case + if ( $this->isTangled( $node ) ) + { + $this->untangleNode( $fragment, $element, $expandingElement, $node ); + continue; + } + + // Expand sub-node if it is element + if ( $node->nodeType === XML_ELEMENT_NODE ) + { + $subFragment = $this->expandElement( $document, $node ); + + /** @var \DOMElement $subNode */ + foreach ( $subFragment->childNodes as $subNode ) + { + // If not untangled just append to existing expanding element, otherwise new + // expanding element will be started by the sub-routine + if ( $this->isTangled( $subNode ) ) + { + $this->untangleNode( $fragment, $element, $expandingElement, $subNode ); + } + else + { + $expandingElement->appendChild( $subNode->cloneNode( true ) ); + } + } + } + // Else just append it to the expanding element + else + { + $expandingElement->appendChild( $node->cloneNode( true ) ); + } + } + + // Append only if expanded element is not empty, or was empty to begin with + if ( $element->childNodes->length === 0 || $expandingElement->childNodes->length > 0 ) + { + $fragment->appendChild( $expandingElement ); + } + + return $fragment; + } + + /** + * Untangles given $node from $element, appending expanded elements to the $fragment. + * + * Note that $expandingElement is intentionally passed by reference. It can be + * appended to the $fragment and recreated anew, which needs to picked up by the + * caller. + * + * @param \DOMDocumentFragment $fragment + * @param \DOMElement $element + * @param \DOMElement $expandingElement + * @param \DOMNode $node + * + * @return boolean + */ + protected function untangleNode( + DOMDocumentFragment $fragment, + DOMElement $element, + DOMElement &$expandingElement, + DOMNode $node + ) + { + // Execute if node is entangled in the paragraph context + if ( $this->isTangled( $node ) ) + { + // If expanding element is not empty, append it to the fragment and start a new one + if ( $expandingElement->childNodes->length > 0 ) + { + $fragment->appendChild( $expandingElement ); + $expandingElement = $this->cloneAndEmpty( $element ); + } + + // If element is the entangler append the node directly to the fragment + if ( $this->isTangler( $element, $node ) ) + { + $fragment->appendChild( $node->cloneNode( true ) ); + } + // Else wrap it in the expanding element and append that to the fragment + else + { + $expandingElement->appendChild( $node->cloneNode( true ) ); + $expandingElement->setAttribute( static::ATTRIBUTE_INHERIT_TANGLEMENT, 1 ); + $fragment->appendChild( $expandingElement ); + + // Start new expanding element + $expandingElement = $this->cloneAndEmpty( $element ); + } + + return true; + } + + return false; + } + + /** + * Returns boolean depending if given $node is entangled or not. + * + * @param \DOMNode $node + * + * @return boolean + */ + protected function isTangled( DOMNode $node ) + { + return ( + isset( $this->containmentMap[$node->localName] ) + || ( $node instanceof DOMElement && $node->hasAttribute( static::ATTRIBUTE_INHERIT_TANGLEMENT ) ) + ); + } + + /** + * Returns boolean depending if given $element is entangler of $node or not. + * + * @param \DOMElement $element + * @param \DOMNode $node + * + * @return boolean + */ + protected function isTangler( DOMElement $element, DOMNode $node ) + { + return ( + !isset( $this->containmentMap[$node->localName][$element->localName] ) + || ( $node instanceof DOMElement && $node->hasAttribute( static::ATTRIBUTE_INHERIT_TANGLEMENT ) ) + ); + } + + /** + * Clones given $element and removes all children from clone. + * + * @param \DOMElement $element + * + * @return \DOMElement + */ + protected function cloneAndEmpty( DOMElement $element ) + { + $clone = $element->cloneNode( true ); + + $children = array(); + + // Collect child nodes first, as we can't iterate and + // remove from \DOMNodeList directly + foreach ( $clone->childNodes as $node ) + { + $children[] = $node; + } + + foreach ( $children as $node ) + { + $clone->removeChild( $node ); + } + + return $clone; + } + + /** + * Returns depth of given $node in a DOMDocument. + * + * @param \DOMNode $node + * + * @return int + */ + protected function getNodeDepth( DomNode $node ) + { + $depth = -2; + + while ( $node ) + { + $depth++; + $node = $node->parentNode; + } + + return $depth; + } +} From e8542d2fabb23ceac95563076028f3d9705cc99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:40:48 +0100 Subject: [PATCH 02/11] EZP-23513: implement EmbedLinking converter --- .../XmlText/Converter/EmbedLinkingTest.php | 84 +++++++++++ .../embed_linking/input/001-embedUrlLink.xml | 8 + .../input/002-embedLocationLink.xml | 8 + .../input/003-embedContentLink.xml | 8 + .../input/004-inlineEmbedUrlLink.xml | 12 ++ .../input/005-inlineEmbedLocationLink.xml | 11 ++ .../input/006-inlineEmbedContentLink.xml | 11 ++ .../input/007-inlineEmbedUrlLinkMixed.xml | 12 ++ .../008-inlineEmbedLocationLinkMixed.xml | 12 ++ .../input/009-inlineEmbedContentLinkMixed.xml | 13 ++ .../embed_linking/output/001-embedUrlLink.xml | 19 +++ .../output/002-embedLocationLink.xml | 18 +++ .../output/003-embedContentLink.xml | 18 +++ .../output/004-inlineEmbedUrlLink.xml | 23 +++ .../output/005-inlineEmbedLocationLink.xml | 21 +++ .../output/006-inlineEmbedContentLink.xml | 21 +++ .../output/007-inlineEmbedUrlLinkMixed.xml | 23 +++ .../008-inlineEmbedLocationLinkMixed.xml | 24 +++ .../009-inlineEmbedContentLinkMixed.xml | 24 +++ .../XmlText/Converter/EmbedLinking.php | 138 ++++++++++++++++++ 20 files changed, 508 insertions(+) create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedLinkingTest.php create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/001-embedUrlLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/002-embedLocationLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/003-embedContentLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/004-inlineEmbedUrlLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/005-inlineEmbedLocationLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/006-inlineEmbedContentLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/007-inlineEmbedUrlLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/008-inlineEmbedLocationLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/009-inlineEmbedContentLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/001-embedUrlLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/002-embedLocationLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/003-embedContentLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/004-inlineEmbedUrlLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/005-inlineEmbedLocationLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/006-inlineEmbedContentLink.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/007-inlineEmbedUrlLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/008-inlineEmbedLocationLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/009-inlineEmbedContentLinkMixed.xml create mode 100644 eZ/Publish/Core/FieldType/XmlText/Converter/EmbedLinking.php diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedLinkingTest.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedLinkingTest.php new file mode 100644 index 00000000000..38150df73b4 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedLinkingTest.php @@ -0,0 +1,84 @@ +preserveWhiteSpace = false; + $document->formatOutput = false; + + if ( $isPath === true ) + { + $xml = file_get_contents( $xml ); + } + + $document->loadXml( $xml ); + + return $document; + } + + /** + * @param string $inputFilePath + * @param string $outputFilePath + * + * @dataProvider providerForTestConvert + */ + public function testConvert( $inputFilePath, $outputFilePath ) + { + $inputDocument = $this->createDocument( $inputFilePath ); + + $converter = new EmbedLinking(); + $converter->convert( $inputDocument ); + + $outputDocument = $this->createDocument( $outputFilePath ); + + $this->assertEquals( + $outputDocument, + $inputDocument + ); + } +} diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/001-embedUrlLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/001-embedUrlLink.xml new file mode 100644 index 00000000000..80da6e364a4 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/001-embedUrlLink.xml @@ -0,0 +1,8 @@ + +
+ + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/002-embedLocationLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/002-embedLocationLink.xml new file mode 100644 index 00000000000..7d7edd09d07 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/002-embedLocationLink.xml @@ -0,0 +1,8 @@ + +
+ + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/003-embedContentLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/003-embedContentLink.xml new file mode 100644 index 00000000000..9464a111a28 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/003-embedContentLink.xml @@ -0,0 +1,8 @@ + +
+ + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/004-inlineEmbedUrlLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/004-inlineEmbedUrlLink.xml new file mode 100644 index 00000000000..daebd66c338 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/004-inlineEmbedUrlLink.xml @@ -0,0 +1,12 @@ + +
+ + Look! + + + + It's an embed! + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/005-inlineEmbedLocationLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/005-inlineEmbedLocationLink.xml new file mode 100644 index 00000000000..963a91028ce --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/005-inlineEmbedLocationLink.xml @@ -0,0 +1,11 @@ + +
+ + Another embed! + + + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/006-inlineEmbedContentLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/006-inlineEmbedContentLink.xml new file mode 100644 index 00000000000..94b902e7635 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/006-inlineEmbedContentLink.xml @@ -0,0 +1,11 @@ + +
+ + An embed again... + + + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/007-inlineEmbedUrlLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/007-inlineEmbedUrlLinkMixed.xml new file mode 100644 index 00000000000..caa1375aef3 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/007-inlineEmbedUrlLinkMixed.xml @@ -0,0 +1,12 @@ + +
+ + Yawn... + + + another embed... + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/008-inlineEmbedLocationLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/008-inlineEmbedLocationLinkMixed.xml new file mode 100644 index 00000000000..876c7a5f2a1 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/008-inlineEmbedLocationLinkMixed.xml @@ -0,0 +1,12 @@ + +
+ + It's that embed again... + + But now it's mixed! + + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/009-inlineEmbedContentLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/009-inlineEmbedContentLinkMixed.xml new file mode 100644 index 00000000000..dd76b724b8b --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/input/009-inlineEmbedContentLinkMixed.xml @@ -0,0 +1,13 @@ + +
+ + + teh pesky embeds are everywhere + + yada yada yada + + I definitely saw that embed before. + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/001-embedUrlLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/001-embedUrlLink.xml new file mode 100644 index 00000000000..beea9191aa0 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/001-embedUrlLink.xml @@ -0,0 +1,19 @@ + +
+ +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/002-embedLocationLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/002-embedLocationLink.xml new file mode 100644 index 00000000000..0accf26262f --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/002-embedLocationLink.xml @@ -0,0 +1,18 @@ + +
+ +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/003-embedContentLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/003-embedContentLink.xml new file mode 100644 index 00000000000..f9004b9cf96 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/003-embedContentLink.xml @@ -0,0 +1,18 @@ + +
+ +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/004-inlineEmbedUrlLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/004-inlineEmbedUrlLink.xml new file mode 100644 index 00000000000..da3d9b4fcb7 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/004-inlineEmbedUrlLink.xml @@ -0,0 +1,23 @@ + +
+ + Look! + + It's an embed! + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/005-inlineEmbedLocationLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/005-inlineEmbedLocationLink.xml new file mode 100644 index 00000000000..3c603e50b8e --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/005-inlineEmbedLocationLink.xml @@ -0,0 +1,21 @@ + +
+ + Another embed! + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/006-inlineEmbedContentLink.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/006-inlineEmbedContentLink.xml new file mode 100644 index 00000000000..7706792e06d --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/006-inlineEmbedContentLink.xml @@ -0,0 +1,21 @@ + +
+ + An embed again... + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/007-inlineEmbedUrlLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/007-inlineEmbedUrlLinkMixed.xml new file mode 100644 index 00000000000..1857198244a --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/007-inlineEmbedUrlLinkMixed.xml @@ -0,0 +1,23 @@ + +
+ + Yawn... + + another embed... + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/008-inlineEmbedLocationLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/008-inlineEmbedLocationLinkMixed.xml new file mode 100644 index 00000000000..ba46d9d76de --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/008-inlineEmbedLocationLinkMixed.xml @@ -0,0 +1,24 @@ + +
+ + It's that embed again... + + But now it's mixed! + + + +
diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/009-inlineEmbedContentLinkMixed.xml b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/009-inlineEmbedContentLinkMixed.xml new file mode 100644 index 00000000000..e2b300173d1 --- /dev/null +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/embed_linking/output/009-inlineEmbedContentLinkMixed.xml @@ -0,0 +1,24 @@ + +
+ + teh pesky embeds are everywhere + + yada yada yada + + I definitely saw that embed before. + +
diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedLinking.php b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedLinking.php new file mode 100644 index 00000000000..539c75c9ad4 --- /dev/null +++ b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedLinking.php @@ -0,0 +1,138 @@ +query( $xpathExpression ); + + $collection = array(); + foreach ( $linkedEmbeds as $embed ) + { + $collection[] = $embed; + } + + /** @var \DOMElement $embed */ + foreach ( $collection as $embed ) + { + $this->copyLinkAttributes( $embed ); + $this->unwrap( $embed ); + } + } + + /** + * Copies embed's link attributes to linked embed itself, prefixed so they can be + * unambiguously recognized. + * + * @param \DOMElement $embed + */ + protected function copyLinkAttributes( DOMElement $embed ) + { + $link = $embed->parentNode; + + if ( $link->hasAttribute( "object_id" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "object_id", $link->getAttribute( "object_id" ) ); + } + + if ( $link->hasAttribute( "node_id" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "node_id", $link->getAttribute( "node_id" ) ); + } + + if ( $link->hasAttribute( "anchor_name" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "anchor_name", $link->getAttribute( "anchor_name" ) ); + } + + if ( $link->hasAttribute( "target" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "target", $link->getAttribute( "target" ) ); + } + + if ( $link->hasAttribute( "xhtml:title" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "title", $link->getAttribute( "xhtml:title" ) ); + } + + if ( $link->hasAttribute( "xhtml:id" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "id", $link->getAttribute( "xhtml:id" ) ); + } + + if ( $link->hasAttribute( "class" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "class", $link->getAttribute( "class" ) ); + } + + if ( $link->hasAttribute( "url" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "url", $link->getAttribute( "url" ) ); + } + + if ( $link->hasAttribute( "url_id" ) ) + { + $embed->setAttribute( static::TEMP_PREFIX . "url_id", $link->getAttribute( "url_id" ) ); + } + } + + /** + * Unwraps embed element in the case when it is single content of its link. + * + * The above should always be the case for block level embed after Expanding conversion pass. + * If embed (inline) is not the single content of its link, it won't be unwrapped and link + * parameters on the embed will signify this with 'wrapping' parameter set to true (done later + * in EzLinkToHtml5 converter). + * + * @param \DOMElement $embed + */ + protected function unwrap( DOMElement $embed ) + { + $link = $embed->parentNode; + $childCount = 0; + + /** @var \DOMText|\DOMElement $node */ + foreach ( $link->childNodes as $node ) + { + if ( !( $node->nodeType === XML_TEXT_NODE && $node->isWhitespaceInElementContent() ) ) + { + $childCount += 1; + } + } + + if ( $childCount === 1 ) + { + $link->parentNode->replaceChild( $embed, $link ); + } + } +} From 3db441f4f872d59a08b3716f89d8f462753184d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:42:03 +0100 Subject: [PATCH 03/11] EZP-23513: remove CustomTags converter --- .../XmlText/Converter/CustomTagsTest.php | 63 ------------------- .../XmlText/Converter/CustomTags.php | 32 ---------- 2 files changed, 95 deletions(-) delete mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/CustomTagsTest.php delete mode 100644 eZ/Publish/Core/FieldType/XmlText/Converter/CustomTags.php diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/CustomTagsTest.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/CustomTagsTest.php deleted file mode 100644 index 66a724a6e27..00000000000 --- a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/CustomTagsTest.php +++ /dev/null @@ -1,63 +0,0 @@ - -
- - - - - Placing an image - - - -
-EOT; - - $dom = new DOMDocument; - $dom->loadXML( $xml ); - $customTagConverter = new CustomTags(); - $customTagConverter->convert( $dom ); - - /** @var \DOMElement $customTag */ - foreach ( $dom->getElementsByTagName( 'custom' ) as $customTag ) - { - $name = $customTag->getAttribute( 'name' ); - switch ( $name ) - { - case 'youtube': - $this->assertTrue( $customTag->hasAttribute( 'inline' ) ); - $this->assertSame( 'false', $customTag->getAttribute( 'inline' ) ); - break; - - case 'underline': - $this->assertFalse( $customTag->hasAttribute( 'inline' ) ); - break; - } - } - } -} diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/CustomTags.php b/eZ/Publish/Core/FieldType/XmlText/Converter/CustomTags.php deleted file mode 100644 index 2031e10deff..00000000000 --- a/eZ/Publish/Core/FieldType/XmlText/Converter/CustomTags.php +++ /dev/null @@ -1,32 +0,0 @@ - declaring a local "tmp" namespace. - */ -class CustomTags implements Converter -{ - public function convert( DOMDocument $xmlDoc ) - { - /** @var \DOMElement $customTag */ - foreach ( $xmlDoc->getElementsByTagName( 'custom' ) as $customTag ) - { - if ( $customTag->parentNode->lookupNamespaceUri( 'tmp' ) !== null ) - { - $customTag->setAttribute( 'inline', 'false' ); - } - } - } -} From 9e8521abd7e02feed5dc72410f2157e2604161f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:45:30 +0100 Subject: [PATCH 04/11] EZP-23513: update Link converter to handle linked embeds --- .../XmlText/Converter/EzLinkToHtml5Test.php | 186 ++++++++++++++++-- .../XmlText/Converter/EzLinkToHtml5.php | 95 +++++++-- 2 files changed, 251 insertions(+), 30 deletions(-) diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EzLinkToHtml5Test.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EzLinkToHtml5Test.php index f1fdb7d37d9..23a98d4c599 100644 --- a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EzLinkToHtml5Test.php +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EzLinkToHtml5Test.php @@ -13,6 +13,7 @@ use PHPUnit_Framework_TestCase; use eZ\Publish\Core\Base\Exceptions\NotFoundException as APINotFoundException; use eZ\Publish\Core\Base\Exceptions\UnauthorizedException as APIUnauthorizedException; +use DOMXPath; /** * Tests the EzLinkToHtml5 Preconverter @@ -37,6 +38,26 @@ public function providerLinkXmlSample()
This is an object link.
', '/test#anchor', ), + array( + ' +
', + '/test', + ), + array( + ' +
', + '/test#anchor', + ), + array( + ' +
', + '/test', + ), + array( + ' +
', + '/test#anchor', + ), ); } @@ -62,6 +83,38 @@ public function providerObjectLinkXmlSample() 'test', 'test#anchor', ), + array( + ' +
', + 104, + 106, + 'test', + 'test', + ), + array( + ' +
', + 104, + 106, + 'test', + 'test#anchor', + ), + array( + ' +
', + 104, + 106, + 'test', + 'test', + ), + array( + ' +
', + 104, + 106, + 'test', + 'test#anchor', + ), ); } @@ -85,6 +138,34 @@ public function providerLocationLinkXmlSample() 'test', 'test#anchor', ), + array( + ' +
', + 106, + 'test', + 'test', + ), + array( + ' +
', + 106, + 'test', + 'test#anchor', + ), + array( + ' +
', + 106, + 'test', + 'test', + ), + array( + ' +
', + 106, + 'test', + 'test#anchor', + ), ); } @@ -109,7 +190,39 @@ public function providerBadLocationSample() new APIUnauthorizedException( "Location", 106 ), 'notice', 'While generating links for xmltext, unauthorized to load Location with ID 106' - ) + ), + array( + ' +
', + 106, + new APINotFoundException( "Location", 106 ), + 'warning', + 'While generating links for xmltext, could not locate Location with ID 106' + ), + array( + ' +
', + 106, + new APIUnauthorizedException( "Location", 106 ), + 'notice', + 'While generating links for xmltext, unauthorized to load Location with ID 106' + ), + array( + ' +
', + 106, + new APINotFoundException( "Location", 106 ), + 'warning', + 'While generating links for xmltext, could not locate Location with ID 106' + ), + array( + ' +
', + 106, + new APIUnauthorizedException( "Location", 106 ), + 'notice', + 'While generating links for xmltext, unauthorized to load Location with ID 106' + ), ); } @@ -134,7 +247,39 @@ public function providerBadObjectSample() new APIUnauthorizedException( "Content", 205 ), 'notice', 'While generating links for xmltext, unauthorized to load Content object with ID 205' - ) + ), + array( + ' +
', + 205, + new APINotFoundException( "Content", 205 ), + 'warning', + 'While generating links for xmltext, could not locate Content object with ID 205' + ), + array( + ' +
', + 205, + new APIUnauthorizedException( "Content", 205 ), + 'notice', + 'While generating links for xmltext, unauthorized to load Content object with ID 205' + ), + array( + ' +
', + 205, + new APINotFoundException( "Content", 205 ), + 'warning', + 'While generating links for xmltext, could not locate Content object with ID 205' + ), + array( + ' +
', + 205, + new APIUnauthorizedException( "Content", 205 ), + 'notice', + 'While generating links for xmltext, unauthorized to load Content object with ID 205' + ), ); } @@ -230,11 +375,16 @@ public function testLink( $xmlString, $url ) $converter = new EzLinkToHtml5( $locationService, $contentService, $urlAliasRouter ); $converter->convert( $xmlDoc ); - $links = $xmlDoc->getElementsByTagName( 'link' ); - foreach ( $links as $link ) + $xpath = new DOMXPath( $xmlDoc ); + $xpathExpression = "//link|//embed|//embed-inline"; + + $elements = $xpath->query( $xpathExpression ); + + /** @var \DOMElement $element */ + foreach ( $elements as $element ) { // assumes only one link, or all pointing to same url - $this->assertEquals( $url, $link->getAttribute( 'url' ) ); + $this->assertEquals( $url, $element->getAttribute( 'url' ) ); } } @@ -270,14 +420,15 @@ public function testLocationLink( $xmlString, $locationId, $rawUrl, $url ) $converter = new EzLinkToHtml5( $locationService, $contentService, $urlAliasRouter ); $converter->convert( $xmlDoc ); - $links = $xmlDoc->getElementsByTagName( 'link' ); + $xpath = new DOMXPath( $xmlDoc ); + $xpathExpression = "//link|//embed|//embed-inline"; - foreach ( $links as $link ) + $elements = $xpath->query( $xpathExpression ); + + /** @var \DOMElement $element */ + foreach ( $elements as $element ) { - if ( $link->getAttribute( 'node_id' ) == $locationId ) - { - $this->assertEquals( $url, $link->getAttribute( 'url' ) ); - } + $this->assertEquals( $url, $element->getAttribute( 'url' ) ); } } @@ -325,14 +476,15 @@ public function testObjectLink( $xmlString, $contentId, $locationId, $rawUrl, $u $converter = new EzLinkToHtml5( $locationService, $contentService, $urlAliasRouter ); $converter->convert( $xmlDoc ); - $links = $xmlDoc->getElementsByTagName( 'link' ); + $xpath = new DOMXPath( $xmlDoc ); + $xpathExpression = "//link|//embed|//embed-inline"; + + $elements = $xpath->query( $xpathExpression ); - foreach ( $links as $link ) + /** @var \DOMElement $element */ + foreach ( $elements as $element ) { - if ( $link->getAttribute( 'object_id' ) == $contentId ) - { - $this->assertEquals( $url, $link->getAttribute( 'url' ) ); - } + $this->assertEquals( $url, $element->getAttribute( 'url' ) ); } } diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/EzLinkToHtml5.php b/eZ/Publish/Core/FieldType/XmlText/Converter/EzLinkToHtml5.php index c11a6bcb20e..9e4ba9b52fa 100644 --- a/eZ/Publish/Core/FieldType/XmlText/Converter/EzLinkToHtml5.php +++ b/eZ/Publish/Core/FieldType/XmlText/Converter/EzLinkToHtml5.php @@ -16,7 +16,8 @@ use Psr\Log\LoggerInterface; use eZ\Publish\API\Repository\Exceptions\NotFoundException as APINotFoundException; use eZ\Publish\API\Repository\Exceptions\UnauthorizedException as APIUnauthorizedException; - +use DOMXPath; +use DOMElement; use DOMDocument; class EzLinkToHtml5 implements Converter @@ -58,15 +59,22 @@ public function __construct( LocationService $locationService, ContentService $c */ public function convert( DOMDocument $xmlDoc ) { - foreach ( $xmlDoc->getElementsByTagName( "link" ) as $link ) + $xpath = new DOMXPath( $xmlDoc ); + + $elements = $xpath->query( "//link|//embed|//embed-inline" ); + + /** @var \DOMElement $element */ + foreach ( $elements as $element ) { $location = null; - if ( $link->hasAttribute( 'object_id' ) ) + if ( $this->elementHasAttribute( $element, 'object_id' ) ) { try { - $contentInfo = $this->contentService->loadContentInfo( $link->getAttribute( 'object_id' ) ); + $contentInfo = $this->contentService->loadContentInfo( + $this->getElementAttribute( $element, 'object_id' ) + ); $location = $this->locationService->loadLocation( $contentInfo->mainLocationId ); } catch ( APINotFoundException $e ) @@ -75,7 +83,7 @@ public function convert( DOMDocument $xmlDoc ) { $this->logger->warning( "While generating links for xmltext, could not locate " . - "Content object with ID " . $link->getAttribute( 'object_id' ) + "Content object with ID " . $this->getElementAttribute( $element, 'object_id' ) ); } } @@ -85,17 +93,19 @@ public function convert( DOMDocument $xmlDoc ) { $this->logger->notice( "While generating links for xmltext, unauthorized to load " . - "Content object with ID " . $link->getAttribute( 'object_id' ) + "Content object with ID " . $this->getElementAttribute( $element, 'object_id' ) ); } } } - if ( $link->hasAttribute( 'node_id' ) ) + if ( $this->elementHasAttribute( $element, 'node_id' ) ) { try { - $location = $this->locationService->loadLocation( $link->getAttribute( 'node_id' ) ); + $location = $this->locationService->loadLocation( + $this->getElementAttribute( $element, 'node_id' ) + ); } catch ( APINotFoundException $e ) { @@ -103,7 +113,7 @@ public function convert( DOMDocument $xmlDoc ) { $this->logger->warning( "While generating links for xmltext, could not locate " . - "Location with ID " . $link->getAttribute( 'node_id' ) + "Location with ID " . $this->getElementAttribute( $element, 'node_id' ) ); } } @@ -113,7 +123,7 @@ public function convert( DOMDocument $xmlDoc ) { $this->logger->notice( "While generating links for xmltext, unauthorized to load " . - "Location with ID " . $link->getAttribute( 'node_id' ) + "Location with ID " . $this->getElementAttribute( $element, 'node_id' ) ); } } @@ -121,13 +131,72 @@ public function convert( DOMDocument $xmlDoc ) if ( $location !== null ) { - $link->setAttribute( 'url', $this->urlAliasRouter->generate( $location ) ); + $element->setAttribute( 'url', $this->urlAliasRouter->generate( $location ) ); + } + + // Copy temporary URL if it exists and is not set at this point + if ( !$element->hasAttribute( 'url' ) && $element->hasAttribute( EmbedLinking::TEMP_PREFIX . 'url' ) ) + { + $element->setAttribute( 'url', $element->getAttribute( EmbedLinking::TEMP_PREFIX . 'url' ) ); } - if ( $link->hasAttribute( 'anchor_name' ) ) + if ( $this->elementHasAttribute( $element, 'anchor_name' ) ) { - $link->setAttribute( 'url', $link->getAttribute( 'url' ) . "#" . $link->getAttribute( 'anchor_name' ) ); + $element->setAttribute( + 'url', + $element->getAttribute( 'url' ) . "#" . + $this->getElementAttribute( $element, 'anchor_name' ) + ); } } } + + /** + * Returns boolean on presence of given $attributeName on a link or embed element. + * + * If given $element is embed attribute value will be copied with a prefixed name. + * + * @param \DOMElement $element + * @param string $attributeName + * + * @return boolean + */ + protected function elementHasAttribute( DomElement $element, $attributeName ) + { + // First try to return for link + if ( $element->localName === "link" && $element->hasAttribute( $attributeName ) ) + { + return true; + } + + // Second return for embed + if ( $element->hasAttribute( EmbedLinking::TEMP_PREFIX . $attributeName ) ) + { + return true; + } + + return false; + } + + /** + * Returns value given $attributeName on a link or embed element. + * + * If given $element is embed attribute value will be copied with a prefixed name. + * + * @param \DOMElement $element + * @param string $attributeName + * + * @return string + */ + protected function getElementAttribute( DomElement $element, $attributeName ) + { + // First try to return for link + if ( $element->localName === "link" ) + { + return $element->getAttribute( $attributeName ); + } + + // Second return for embed + return $element->getAttribute( EmbedLinking::TEMP_PREFIX . $attributeName ); + } } From 7e69f63b36afb084505b5e3315478a7785131aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:50:22 +0100 Subject: [PATCH 05/11] EZP-23513: update Embed converter for extraction of embed's link data --- .../XmlText/Converter/EmbedToHtml5Test.php | 466 +++++++++++++++++- .../XmlText/Converter/EmbedToHtml5.php | 188 ++++++- 2 files changed, 620 insertions(+), 34 deletions(-) diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedToHtml5Test.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedToHtml5Test.php index 513f2b993e5..6007a5697a0 100644 --- a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedToHtml5Test.php +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/EmbedToHtml5Test.php @@ -103,9 +103,174 @@ public function providerEmbedXmlSampleContent() array( 'content', 'read', true ), array( 'content', 'versionread', true ), ) - ) + ), + array( + ' +
+ + + +
', + 104, + APIVersionInfo::STATUS_DRAFT, + 'embed', + array( + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'offset' => 3, + 'limit' => 5, + ), + 'noLayout' => true, + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'resourceType' => null, + 'resourceId' => null, + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + array( 'content', 'versionread', true ), + ) + ), + array( + ' +
+ + + +
', + 107, + APIVersionInfo::STATUS_DRAFT, + 'embed', + array( + 'objectParameters' => array( + 'size' => 'medium', + 'funkyattrib' => 3, + 'limit' => 5, + ), + 'noLayout' => true, + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'LOCATION', + 'resourceId' => '111', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', false ), + array( 'content', 'view_embed', true ), + array( 'content', 'versionread', true ), + ) + ), + array( + ' +
+ + + +
', + 110, + APIVersionInfo::STATUS_PUBLISHED, + 'embed-inline', + array( + 'noLayout' => true, + 'objectParameters' => array( + 'size' => 'small' + ), + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'resourceType' => null, + 'resourceId' => null, + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + ) + ), + array( + ' +
+ + + +
', + 113, + APIVersionInfo::STATUS_DRAFT, + 'embed', + array( + 'noLayout' => true, + 'objectParameters' => array( + 'align' => 'left', + 'size' => 'large', + 'limit' => '5', + 'offset' => '0', + ), + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'URL', + 'resourceId' => '333', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + array( 'content', 'versionread', true ), + ) + ), ); } + /** * @return array */ @@ -149,6 +314,97 @@ public function providerEmbedXmlSampleLocation() array( 'content', 'view_embed', true ), ) ), + array( + ' +
+ + + +
', + 114, + 'embed', + array( + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'offset' => 2, + 'limit' => 7, + ), + 'noLayout' => true, + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'resourceType' => 'CONTENT', + 'resourceId' => '333', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + ) + ), + array( + ' +
+ + + + + +
', + 114, + 'embed', + array( + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'offset' => 2, + 'limit' => 7, + ), + 'noLayout' => true, + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'URL', + 'resourceId' => '333', + 'resourceFragmentIdentifier' => 'anchovy', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', false ), + array( 'content', 'view_embed', true ), + ) + ), ); } @@ -177,6 +433,158 @@ public function providerEmbedXmlBadSample() array( 'content', 'read', true ), ) ), + array( + ' +
+ + + +
', + 104, + APIVersionInfo::STATUS_PUBLISHED, + 'embed', + array( + 'noLayout' => true, + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'limit' => 5, + 'offset' => 3, + ), + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'LOCATION', + 'resourceId' => '222', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + ) + ), + array( + ' +
+ + + +and that was embedded + + +
', + 104, + APIVersionInfo::STATUS_PUBLISHED, + 'embed', + array( + 'noLayout' => true, + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'limit' => 5, + 'offset' => 3, + ), + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'LOCATION', + 'resourceId' => '222', + 'wrapped' => true, + ), + ), + array( + array( 'content', 'read', true ), + ) + ), + array( + ' +
+ + + + + +
', + 104, + APIVersionInfo::STATUS_PUBLISHED, + 'embed', + array( + 'noLayout' => true, + 'objectParameters' => array( + 'align' => 'right', + 'size' => 'medium', + 'limit' => 5, + 'offset' => 3, + ), + 'linkParameters' => array( + 'href' => 'http://ez.no', + 'target' => 'target', + 'title' => 'title', + 'id' => 'id', + 'class' => 'class', + 'resourceType' => 'LOCATION', + 'resourceId' => '222', + 'wrapped' => false, + ), + ), + array( + array( 'content', 'read', true ), + ) + ), ); } @@ -313,7 +721,8 @@ public function runNodeEmbedContent( $xmlString, $contentId, $status, $view, $pa $converter = new EmbedToHtml5( $fragmentHandler, $repository, - array( 'view', 'class', 'node_id', 'object_id' ) + array( 'view', 'class', 'node_id', 'object_id' ), + $this->getMock( 'Psr\\Log\\LoggerInterface' ) ); $converter->convert( $dom ); @@ -379,7 +788,8 @@ public function runNodeEmbedLocation( $xmlString, $locationId, $view, $parameter $converter = new EmbedToHtml5( $fragmentHandler, $repository, - array( 'view', 'class', 'node_id', 'object_id' ) + array( 'view', 'class', 'node_id', 'object_id' ), + $this->getMock( 'Psr\\Log\\LoggerInterface' ) ); $converter->convert( $dom ); @@ -444,7 +854,7 @@ public function providerForTestEmbedContentThrowsUnauthorizedException() public function testEmbedContentThrowsUnauthorizedException( $permissionsMap ) { $dom = new \DOMDocument(); - $dom->loadXML( '
' ); + $dom->loadXML( '
' ); $fragmentHandler = $this->getMockFragmentHandler(); $contentService = $this->getMockContentService(); @@ -484,7 +894,8 @@ public function testEmbedContentThrowsUnauthorizedException( $permissionsMap ) $converter = new EmbedToHtml5( $fragmentHandler, $repository, - array( 'view', 'class', 'node_id', 'object_id' ) + array( 'view', 'class', 'node_id', 'object_id' ), + $this->getMock( 'Psr\\Log\\LoggerInterface' ) ); $converter->convert( $dom ); @@ -496,7 +907,7 @@ public function testEmbedContentThrowsUnauthorizedException( $permissionsMap ) public function testEmbedLocationThrowsUnauthorizedException() { $dom = new \DOMDocument(); - $dom->loadXML( '
' ); + $dom->loadXML( '
' ); $fragmentHandler = $this->getMockFragmentHandler(); $locationService = $this->getMockLocationService(); @@ -534,7 +945,8 @@ public function testEmbedLocationThrowsUnauthorizedException() $converter = new EmbedToHtml5( $fragmentHandler, $repository, - array( 'view', 'class', 'node_id', 'object_id' ) + array( 'view', 'class', 'node_id', 'object_id' ), + $this->getMock( 'Psr\\Log\\LoggerInterface' ) ); $converter->convert( $dom ); @@ -544,20 +956,20 @@ public function dataProviderForTestEmbedContentNotFound() { return array( array( - '
', - '
', + '
', + '
', ), array( - '
hello goodbye
', + '
hello goodbye
', '
hello goodbye
', ), array( - '
hello goodbye
', + '
hello goodbye
', '
hello goodbye
', ), array( - '
', - '
', + '
', + '
', ), ); } @@ -584,7 +996,13 @@ public function testEmbedContentNotFound( $input, $output ) ) ); - $logger->expects( $this->once() ) + $logger->expects( $this->at( 0 ) ) + ->method( "error" ) + ->with( + "Could not resolve XmlText embed link resource type and ID" + ); + + $logger->expects( $this->at( 1 ) ) ->method( "error" ) ->with( "While generating embed for xmltext, could not locate Content object with ID 42" @@ -612,20 +1030,20 @@ public function dataProviderForTestEmbedLocationNotFound() { return array( array( - '
', - '
', + '
', + '
', ), array( - '
hello goodbye
', + '
hello goodbye
', '
hello goodbye
', ), array( - '
hello goodbye
', + '
hello goodbye
', '
hello goodbye
', ), array( - '
', - '
', + '
', + '
', ), ); } @@ -652,7 +1070,13 @@ public function testEmbedLocationNotFound( $input, $output ) ) ); - $logger->expects( $this->once() ) + $logger->expects( $this->at( 0 ) ) + ->method( "error" ) + ->with( + "Could not resolve XmlText embed link resource type and ID" + ); + + $logger->expects( $this->at( 1 ) ) ->method( "error" ) ->with( "While generating embed for xmltext, could not locate Location with ID 42" diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php index b6473c38ebe..b2e97fd4570 100644 --- a/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php +++ b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php @@ -18,12 +18,34 @@ use Symfony\Component\HttpKernel\Fragment\FragmentHandler; use eZ\Publish\API\Repository\Exceptions\NotFoundException as APINotFoundException; use Psr\Log\LoggerInterface; +use DOMElement; /** * Converts embedded elements from internal XmlText representation to HTML5 */ class EmbedToHtml5 implements Converter { + /** + * Content link resource + * + * @const string + */ + const LINK_RESOURCE_CONTENT = "CONTENT"; + + /** + * Location link resource + * + * @const string + */ + const LINK_RESOURCE_LOCATION = "LOCATION"; + + /** + * URL link resource + * + * @const string + */ + const LINK_RESOURCE_URL = "URL"; + /** * List of disallowed attributes * @var array @@ -74,19 +96,7 @@ protected function processTag( DOMDocument $xmlDoc, $tagName ) } $embedContent = null; - $parameters = array( - "noLayout" => true, - "objectParameters" => array() - ); - - foreach ( $embed->attributes as $attribute ) - { - // We only consider tags in the custom namespace, and skip disallowed names - if ( !isset( $this->excludedAttributes[$attribute->localName] ) ) - { - $parameters["objectParameters"][$attribute->localName] = $attribute->nodeValue; - } - } + $parameters = $this->getParameters( $embed ); if ( $contentId = $embed->getAttribute( "object_id" ) ) { @@ -221,6 +231,158 @@ function ( Repository $repository ) use ( $locationId ) } } + /** + * Returns embed's parameters. + * + * @param \DOMElement $embed + * + * @return array + */ + protected function getParameters( DOMElement $embed ) + { + $parameters = array( + "noLayout" => true, + "objectParameters" => array(), + ); + + $linkParameters = $this->getLinkParameters( $embed ); + + if ( $linkParameters !== null ) + { + $parameters["linkParameters"] = $linkParameters; + } + + foreach ( $embed->attributes as $attribute ) + { + // We only consider tags in the custom namespace, and skip disallowed names + if ( + !isset( $this->excludedAttributes[$attribute->localName] ) + && $attribute->localName !== 'url' + && strpos( $attribute->localName, EmbedLinking::TEMP_PREFIX ) !== 0 + ) + { + $parameters["objectParameters"][$attribute->localName] = $attribute->nodeValue; + } + } + + return $parameters; + } + + /** + * Returns embed's link parameters, or null if embed is not linked. + * + * @param \DOMElement $embed + * + * @return array|null + */ + protected function getLinkParameters( DOMElement $embed ) + { + if ( !$embed->hasAttribute( "url" ) ) + { + return null; + } + + $target = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "target" ); + $title = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "title" ); + $id = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "id" ); + $class = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "class" ); + $resourceFragmentIdentifier = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "anchor_name" ); + $resourceType = null; + $resourceId = null; + + if ( $embed->hasAttribute( EmbedLinking::TEMP_PREFIX . "object_id" ) ) + { + $resourceType = static::LINK_RESOURCE_CONTENT; + $resourceId = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "object_id" ); + } + else if ( $embed->hasAttribute( EmbedLinking::TEMP_PREFIX . "node_id" ) ) + { + $resourceType = static::LINK_RESOURCE_LOCATION; + $resourceId = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "node_id" ); + } + else if ( $embed->hasAttribute( EmbedLinking::TEMP_PREFIX . "url_id" ) ) + { + $resourceType = static::LINK_RESOURCE_URL; + $resourceId = $embed->getAttribute( EmbedLinking::TEMP_PREFIX . "url_id" ); + } + else + { + $this->logger->error( + "Could not resolve XmlText embed link resource type and ID" + ); + } + + $parameters = array( + "href" => $embed->getAttribute( "url" ), + "resourceType" => $resourceType, + "resourceId" => $resourceId, + "wrapped" => $this->isLinkWrapped( $embed ), + ); + + if ( !empty( $resourceFragmentIdentifier ) ) + { + $parameters["resourceFragmentIdentifier"] = $resourceFragmentIdentifier; + } + + if ( !empty( $target ) ) + { + $parameters["target"] = $target; + } + + if ( !empty( $title ) ) + { + $parameters["title"] = $title; + } + + if ( !empty( $id ) ) + { + $parameters["id"] = $id; + } + + if ( !empty( $class ) ) + { + $parameters["class"] = $class; + } + + return $parameters; + } + + /** + * Returns boolean signifying if the embed is contained in a link element of not. + * + * After EmbedLinking converter pass this should be possible only for inline level embeds. + * + * @param \DOMElement $element + * + * @return boolean + */ + protected function isLinkWrapped( DOMElement $element ) + { + $parentNode = $element->parentNode; + + if ( $parentNode instanceof DOMDocument ) + { + return false; + } + else if ( $parentNode->localName === "link" ) + { + $childCount = 0; + + /** @var \DOMText|\DOMElement $node */ + foreach ( $parentNode->childNodes as $node ) + { + if ( !( $node->nodeType === XML_TEXT_NODE && $node->isWhitespaceInElementContent() ) ) + { + $childCount += 1; + } + } + + return $childCount !== 1; + } + + return $this->isLinkWrapped( $parentNode ); + } + /** * Converts embed elements in $xmlDoc from internal representation to HTML5 * From f9b7ea33871b8b46424f26b59f52652b9a83c381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:51:41 +0100 Subject: [PATCH 06/11] EZP-23513: simplify embedding added in #1059 --- .../XmlText/Converter/EmbedToHtml5.php | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php index b2e97fd4570..ea752bac18b 100644 --- a/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php +++ b/eZ/Publish/Core/FieldType/XmlText/Converter/EmbedToHtml5.php @@ -196,33 +196,8 @@ function ( Repository $repository ) use ( $locationId ) if ( $embedContent === null ) { - // Remove tmp paragraph - if ( $embed->parentNode->lookupNamespaceUri( 'tmp' ) !== null ) - { - $embed->parentNode->parentNode->removeChild( $embed->parentNode ); - } - // Remove empty link - else if ( $embed->parentNode->localName === "link" && $embed->parentNode->childNodes->length === 1 ) - { - // Remove paragraph with empty link - if ( - $embed->parentNode->parentNode->localName === "paragraph" && - $embed->parentNode->parentNode->childNodes->length === 1 - ) - { - $embed->parentNode->parentNode->parentNode->removeChild( $embed->parentNode->parentNode ); - } - // Remove empty link - else - { - $embed->parentNode->parentNode->removeChild( $embed->parentNode ); - } - } // Remove empty embed - else - { - $embed->parentNode->removeChild( $embed ); - } + $embed->parentNode->removeChild( $embed ); } else { From 92bcc58141b04e633b0bebbf0740742405571b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:52:50 +0100 Subject: [PATCH 07/11] EZP-23513: simplify core transformation stylesheet --- .../stylesheets/eZXml2Html5_core.xsl | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/eZ/Publish/Core/FieldType/XmlText/Input/Resources/stylesheets/eZXml2Html5_core.xsl b/eZ/Publish/Core/FieldType/XmlText/Input/Resources/stylesheets/eZXml2Html5_core.xsl index 7ff0f4e64d1..86168272799 100644 --- a/eZ/Publish/Core/FieldType/XmlText/Input/Resources/stylesheets/eZXml2Html5_core.xsl +++ b/eZ/Publish/Core/FieldType/XmlText/Input/Resources/stylesheets/eZXml2Html5_core.xsl @@ -35,21 +35,16 @@ + + + + - - - - - - - -

- - - -

-
-
+

+ + + +

From 359b64e91786f366983198a2ead8ecb5765e09f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 12 Nov 2014 15:54:36 +0100 Subject: [PATCH 08/11] EZP-23513: improve main converter tests --- .../Tests/XmlText/Converter/Html5Test.php | 167 +++++++++++++++--- .../_fixtures/html5/input/001-title.xml | 26 +++ .../_fixtures/html5/input/002-para.xml | 13 ++ .../_fixtures/html5/input/003-section.xml | 15 ++ .../html5/input/004-sectionNested.xml | 57 ++++++ .../_fixtures/html5/input/005-emphasis.xml | 9 + .../html5/input/006-emphasisStrong.xml | 9 + .../html5/input/007-emphasisUnderlined.xml | 9 + .../_fixtures/html5/input/008-orderedList.xml | 10 ++ .../html5/input/009-itemizedList.xml | 10 ++ .../html5/input/010-htmlInformaltable.xml | 37 ++++ .../_fixtures/html5/input/011-htmlTable.xml | 25 +++ .../html5/input/012-literallayout.xml | 14 ++ .../_fixtures/html5/input/013-anchor.xml | 9 + .../_fixtures/html5/input/014-link.xml | 24 +++ .../_fixtures/html5/input/015-subscript.xml | 6 + .../_fixtures/html5/input/016-superscript.xml | 6 + .../_fixtures/html5/input/018-htmlTable.xml | 25 +++ .../input/019-emphasisStrikedthrough.xml | 9 + .../_fixtures/html5/input/020-blockquote.xml | 13 ++ .../html5/input/021-titleImplicitLevels.xml | 54 ++++++ .../_fixtures/html5/input/022-embed.xml | 11 ++ .../_fixtures/html5/input/023-embedInline.xml | 7 + .../_fixtures/html5/input/026-tableTitles.xml | 56 ++++++ .../html5/input/101-expandEmbedSingle.xml | 8 + .../input/102-expandCompressedParagraph.xml | 11 ++ .../input/103-expandCompressedParagraphs.xml | 18 ++ .../html5/input/104-expandAndLinkEmbed.xml | 9 + .../input/105-expandAndLinkEmbedWrapped.xml | 10 ++ .../106-expandAndLinkEmbedDoubleWrapped.xml | 10 ++ .../107-expandAndLinkEmbedDoubleWrapped2.xml | 10 ++ .../_fixtures/html5/input/108-expandTable.xml | 42 +++++ .../html5/input/109-expandEmbedInline.xml | 10 ++ .../110-expandEmptyTemporaryParagraph.xml | 4 + .../_fixtures/html5/output/001-title.xml | 13 ++ .../_fixtures/html5/output/002-para.xml | 10 ++ .../_fixtures/html5/output/003-section.xml | 9 + .../html5/output/004-sectionNested.xml | 21 +++ .../_fixtures/html5/output/005-emphasis.xml | 6 + .../html5/output/006-emphasisStrong.xml | 6 + .../html5/output/007-emphasisUnderlined.xml | 6 + .../html5/output/008-orderedList.xml | 6 + .../html5/output/009-itemizedList.xml | 6 + .../html5/output/010-htmlInformaltable.xml | 26 +++ .../_fixtures/html5/output/011-htmlTable.xml | 21 +++ .../html5/output/012-literallayout.xml | 6 + .../_fixtures/html5/output/013-anchor.xml | 6 + .../_fixtures/html5/output/014-link.xml | 21 +++ .../_fixtures/html5/output/015-subscript.xml | 4 + .../html5/output/016-superscript.xml | 4 + .../_fixtures/html5/output/018-htmlTable.xml | 21 +++ .../output/019-emphasisStrikedthrough.xml | 6 + .../_fixtures/html5/output/020-blockquote.xml | 8 + .../html5/output/021-titleImplicitLevels.xml | 17 ++ .../_fixtures/html5/output/022-embed.xml | 5 + .../html5/output/023-embedInline.xml | 5 + .../html5/output/026-tableTitles.xml | 33 ++++ .../html5/output/101-expandEmbedSingle.xml | 4 + .../output/102-expandCompressedParagraph.xml | 9 + .../output/103-expandCompressedParagraphs.xml | 16 ++ .../html5/output/104-expandAndLinkEmbed.xml | 11 ++ .../output/105-expandAndLinkEmbedWrapped.xml | 10 ++ .../106-expandAndLinkEmbedDoubleWrapped.xml | 10 ++ .../107-expandAndLinkEmbedDoubleWrapped2.xml | 12 ++ .../html5/output/108-expandTable.xml | 24 +++ .../html5/output/109-expandEmbedInline.xml | 8 + .../110-expandEmptyTemporaryParagraph.xml | 2 + 67 files changed, 1101 insertions(+), 24 deletions(-) create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/001-title.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/002-para.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/003-section.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/004-sectionNested.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/005-emphasis.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/006-emphasisStrong.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/007-emphasisUnderlined.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/008-orderedList.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/009-itemizedList.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/010-htmlInformaltable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/011-htmlTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/012-literallayout.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/013-anchor.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/014-link.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/015-subscript.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/016-superscript.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/018-htmlTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/019-emphasisStrikedthrough.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/020-blockquote.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/021-titleImplicitLevels.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/022-embed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/023-embedInline.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/026-tableTitles.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/101-expandEmbedSingle.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/102-expandCompressedParagraph.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/103-expandCompressedParagraphs.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/104-expandAndLinkEmbed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/105-expandAndLinkEmbedWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/106-expandAndLinkEmbedDoubleWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/107-expandAndLinkEmbedDoubleWrapped2.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/108-expandTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/109-expandEmbedInline.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/input/110-expandEmptyTemporaryParagraph.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/001-title.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/002-para.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/003-section.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/004-sectionNested.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/005-emphasis.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/006-emphasisStrong.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/007-emphasisUnderlined.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/008-orderedList.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/009-itemizedList.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/010-htmlInformaltable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/011-htmlTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/012-literallayout.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/013-anchor.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/014-link.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/015-subscript.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/016-superscript.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/018-htmlTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/019-emphasisStrikedthrough.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/020-blockquote.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/021-titleImplicitLevels.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/022-embed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/023-embedInline.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/026-tableTitles.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/101-expandEmbedSingle.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/102-expandCompressedParagraph.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/103-expandCompressedParagraphs.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/104-expandAndLinkEmbed.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/105-expandAndLinkEmbedWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/106-expandAndLinkEmbedDoubleWrapped.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/107-expandAndLinkEmbedDoubleWrapped2.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/108-expandTable.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/109-expandEmbedInline.xml create mode 100644 eZ/Publish/Core/FieldType/Tests/XmlText/Converter/_fixtures/html5/output/110-expandEmptyTemporaryParagraph.xml diff --git a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/Html5Test.php b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/Html5Test.php index 243d5e1c20b..a63f86f6476 100644 --- a/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/Html5Test.php +++ b/eZ/Publish/Core/FieldType/Tests/XmlText/Converter/Html5Test.php @@ -9,12 +9,13 @@ namespace eZ\Publish\Core\FieldType\Tests\XmlText\Converter; +use eZ\Publish\Core\FieldType\XmlText\Converter\Expanding; +use eZ\Publish\Core\FieldType\XmlText\Converter\EmbedLinking; use eZ\Publish\Core\FieldType\XmlText\Converter\Html5; use PHPUnit_Framework_TestCase; use DOMDocument; use DOMNodeList; use DOMXPath; -use XSLTProcessor; /** * Tests the Html5 converter @@ -93,7 +94,7 @@ public function dataProviderAnchor() return array( array( ' -
This is the start
', +
This is the start
', '//a[@id="start"]', function ( DOMNodeList $xpathResult ) use ( $that ) { @@ -124,7 +125,7 @@ function ( DOMNodeList $xpathResult ) use ( $that ) ), array( ' -
This is a long line with an anchor in the middle
', +
This is a long line with an anchor in the middle
', '//a[@id="inside"]', function ( DOMNodeList $xpathResult ) use ( $that ) { @@ -167,8 +168,8 @@ function ( DOMNodeList $xpathResult ) use ( $that ) $that->assertEquals( $xpathResult->length, 1 ); $doc = $xpathResult->item( 0 )->ownerDocument; $that->assertEquals( - trim( $doc->saveXML( $doc->documentElement ) ), - '
This is a <em>emphasized</em> text
' + '
This is a <em>emphasized</em> text
', + trim( $doc->saveXML( $doc->documentElement ) ) ); } ), @@ -181,8 +182,8 @@ function ( DOMNodeList $xpathResult ) use ( $that ) $that->assertEquals( $xpathResult->length, 1 ); $doc = $xpathResult->item( 0 )->ownerDocument; $that->assertEquals( - $doc->saveXML( $doc->documentElement ), - '