Skip to content

Commit

Permalink
Add support of document fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
Imangazaliev committed Jan 21, 2020
1 parent 1d49997 commit ed1677e
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 17 deletions.
8 changes: 8 additions & 0 deletions src/DiDom/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ public function createCdataSection($data)
return new Element(new DOMCdataSection($data));
}

/**
* @return DocumentFragment
*/
public function createDocumentFragment()
{
return new DocumentFragment($this->document->createDocumentFragment());
}

/**
* Adds a new child at the end of the children.
*
Expand Down
34 changes: 34 additions & 0 deletions src/DiDom/DocumentFragment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace DiDom;

use DOMDocumentFragment;
use InvalidArgumentException;

/**
* @property string $tag
*/
class DocumentFragment extends Node
{
/**
* @param DOMDocumentFragment $documentFragment
*/
public function __construct($documentFragment)
{
if ( ! $documentFragment instanceof DOMDocumentFragment) {
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMDocumentFragment, %s given', __METHOD__, (is_object($documentFragment) ? get_class($documentFragment) : gettype($documentFragment))));
}

$this->setNode($documentFragment);
}

/**
* Append raw XML data.
*
* @param string $data
*/
public function appendXml($data)
{
$this->node->appendXML($data);
}
}
30 changes: 16 additions & 14 deletions src/DiDom/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use DOMCdataSection;
use DOMComment;
use DOMDocument;
use DOMDocumentFragment;
use DOMElement;
use DOMNode;
use DOMText;
Expand All @@ -21,14 +22,14 @@ abstract class Node
/**
* The DOM element instance.
*
* @var DOMElement|DOMText|DOMComment|DOMCdataSection
* @var DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment
*/
protected $node;

/**
* Adds a new child at the start of the children.
*
* @param Element|DOMNode|array $nodes The prepended child
* @param Node|DOMNode|array $nodes The prepended child
*
* @return Element|Element[]
*
Expand Down Expand Up @@ -67,7 +68,7 @@ public function prependChild($nodes)
/**
* Adds a new child at the end of the children.
*
* @param Element|DOMNode|array $nodes The appended child
* @param Node|DOMNode|array $nodes The appended child
*
* @return Element|Element[]
*
Expand Down Expand Up @@ -119,7 +120,7 @@ public function appendChild($nodes)
/**
* Adds a new child before a reference node.
*
* @param Element|DOMNode $node The new node
* @param Node|DOMNode $node The new node
* @param Element|DOMNode|null $referenceNode The reference node
*
* @return Element
Expand Down Expand Up @@ -167,7 +168,7 @@ public function insertBefore($node, $referenceNode = null)
/**
* Adds a new child after a reference node.
*
* @param Element|DOMNode $node The new node
* @param Node|DOMNode $node The new node
* @param Element|DOMNode|null $referenceNode The reference node
*
* @return Element
Expand Down Expand Up @@ -378,9 +379,10 @@ public function innerXml($delimiter = '')
*
* @param string $html
*
* @return Element
* @return static
*
* @throws InvalidArgumentException if passed argument is not a string
* @throws InvalidSelectorException
*/
public function setInnerHtml($html)
{
Expand Down Expand Up @@ -438,7 +440,7 @@ public function text()
*
* @param string $value The new value of the node
*
* @return Element
* @return static
*
* @throws InvalidArgumentException if value is not string
*/
Expand Down Expand Up @@ -907,7 +909,7 @@ public function children()
/**
* Removes child from list of children.
*
* @param DOMNode|Element $childNode
* @param Node|DOMNode $childNode
*
* @return Element the node that has been removed
*/
Expand Down Expand Up @@ -973,7 +975,7 @@ public function remove()
/**
* Replaces a child.
*
* @param DOMNode|Element $newNode The new node
* @param Node|DOMNode $newNode The new node
* @param bool $clone Clone the node if true, otherwise move it
*
* @return Element The node that has been replaced
Expand Down Expand Up @@ -1032,16 +1034,16 @@ public function cloneNode($deep = true)
/**
* Sets current node instance.
*
* @param DOMElement|DOMText|DOMComment|DOMCdataSection $node
* @param DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment $node
*
* @return Element
* @return static
*/
protected function setNode($node)
{
$allowedClasses = ['DOMElement', 'DOMText', 'DOMComment', 'DOMCdataSection'];
$allowedClasses = ['DOMElement', 'DOMText', 'DOMComment', 'DOMCdataSection', 'DOMDocumentFragment'];

if ( ! is_object($node) || ! in_array(get_class($node), $allowedClasses, true)) {
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMElement, DOMText, DOMComment or DOMCdataSection, %s given', __METHOD__, (is_object($node) ? get_class($node) : gettype($node))));
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMElement, DOMText, DOMComment, DOMCdataSection or DOMDocumentFragment, %s given', __METHOD__, (is_object($node) ? get_class($node) : gettype($node))));
}

$this->node = $node;
Expand All @@ -1052,7 +1054,7 @@ protected function setNode($node)
/**
* Returns current node instance.
*
* @return DOMElement|DOMText|DOMComment|DOMCdataSection
* @return DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment
*/
public function getNode()
{
Expand Down
30 changes: 30 additions & 0 deletions tests/DocumentFragmentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace DiDom\Tests;

use DiDom\Document;
use DiDom\DocumentFragment;
use DOMElement;
use InvalidArgumentException;

class DocumentFragmentTest extends TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testConstructorWithInvalidNodeType()
{
new DocumentFragment(new DOMElement('span'));
}

public function testAppendXml()
{
$document = new Document();

$documentFragment = $document->createDocumentFragment();

$documentFragment->appendXml('<foo>bar</foo>');

$this->assertEquals('<foo>bar</foo>', $documentFragment->innerXml());
}
}
12 changes: 11 additions & 1 deletion tests/DocumentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public function testCreateComment()
$this->assertEquals('foo bar baz', $comment->text());
}

public function testCreateCDATASection()
public function testCreateCdataSection()
{
$document = new Document();

Expand All @@ -154,6 +154,16 @@ public function testCreateCDATASection()
$this->assertEquals('foo bar baz', $cdataSection->text());
}

public function testCreateDocumentFragment()
{
$document = new Document();

$documentFragment = $document->createDocumentFragment();

$this->assertInstanceOf('DiDom\DocumentFragment', $documentFragment);
$this->assertInstanceOf('DOMDocumentFragment', $documentFragment->getNode());
}

/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage Argument 1 passed to DiDom\Document::appendChild must be an instance of DiDom\Element or DOMNode, string given
Expand Down
106 changes: 104 additions & 2 deletions tests/ElementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,40 @@ public function testPrependChildWithArrayOfNodes()
}
}

public function testPrependDocumentFragment()
{
$xml = '
<list>
<item>Foo</item>
<item>Bar</item>
<item>Baz</item>
</list>
';

$document = new Document();

$document->loadXml($xml);

$fragmentXml = '
<item>Qux</item>
<item>Quux</item>
<item>Quuz</item>
';

$documentFragment = $document->createDocumentFragment();

$documentFragment->appendXml($fragmentXml);

$document->first('list')->prependChild($documentFragment);

$expectedContent = ['Qux', 'Quux', 'Quuz', 'Foo', 'Bar', 'Baz'];

foreach ($document->find('item') as $index => $childNode) {
$this->assertEquals('item', $childNode->tag);
$this->assertEquals($expectedContent[$index], $childNode->text());
}
}

/**
* @expectedException InvalidArgumentException
*/
Expand Down Expand Up @@ -253,6 +287,40 @@ public function testAppendChildWithArray()
}
}

public function testAppendDocumentFragment()
{
$xml = '
<list>
<item>Foo</item>
<item>Bar</item>
<item>Baz</item>
</list>
';

$document = new Document();

$document->loadXml($xml);

$fragmentXml = '
<item>Qux</item>
<item>Quux</item>
<item>Quuz</item>
';

$documentFragment = $document->createDocumentFragment();

$documentFragment->appendXml($fragmentXml);

$document->first('list')->appendChild($documentFragment);

$expectedContent = ['Foo', 'Bar', 'Baz', 'Qux', 'Quux', 'Quuz'];

foreach ($document->find('item') as $index => $childNode) {
$this->assertEquals('item', $childNode->tag);
$this->assertEquals($expectedContent[$index], $childNode->text());
}
}

/**
* @expectedException InvalidArgumentException
*/
Expand Down Expand Up @@ -1918,7 +1986,7 @@ public function testReplace()
$this->assertCount(2, $document->find('li'));
}

public function testReplaceToNewElement()
public function testReplaceWithNewElement()
{
$html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';

Expand All @@ -1944,7 +2012,7 @@ public function testReplaceToNewElement()
$anchor->replace($textNode);
}

public function testReplaceWithDifferentDocuments()
public function testReplaceWithElementFromAnotherDocument()
{
$html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';

Expand All @@ -1957,6 +2025,40 @@ public function testReplaceWithDifferentDocuments()
$first->replace($third);
}

public function testReplaceWithDocumentFragment()
{
$xml = '
<list>
<item>Foo</item>
<item>Bar</item>
<item>Baz</item>
</list>
';

$document = new Document();

$document->loadXml($xml);

$fragmentXml = '
<item>Qux</item>
<item>Quux</item>
<item>Quuz</item>
';

$documentFragment = $document->createDocumentFragment();

$documentFragment->appendXml($fragmentXml);

$document->first('item:nth-child(2)')->replace($documentFragment);

$expectedContent = ['Foo', 'Qux', 'Quux', 'Quuz', 'Baz'];

foreach ($document->find('item') as $index => $childNode) {
$this->assertEquals('item', $childNode->tag);
$this->assertEquals($expectedContent[$index], $childNode->text());
}
}

/**
* @expectedException InvalidArgumentException
*/
Expand Down

0 comments on commit ed1677e

Please sign in to comment.