diff --git a/src/Symfony/Component/VarDumper/CHANGELOG.md b/src/Symfony/Component/VarDumper/CHANGELOG.md index f7021f59a4598..6a63e88d78534 100644 --- a/src/Symfony/Component/VarDumper/CHANGELOG.md +++ b/src/Symfony/Component/VarDumper/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.1 +--- + + * Add support for new DOM extension classes in `DOMCaster` + 7.0 --- diff --git a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php index ca1ffcea6ad59..52bd31c4489c6 100644 --- a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php @@ -63,7 +63,7 @@ class DOMCaster \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; - public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested): array + public static function castException(\DOMException|\DOM\Exception $e, array $a, Stub $stub, bool $isNested): array { $k = Caster::PREFIX_PROTECTED.'code'; if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { @@ -82,7 +82,7 @@ public static function castLength($dom, array $a, Stub $stub, bool $isNested): a return $a; } - public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested): array + public static function castImplementation(\DOMImplementation|\DOM\Implementation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'Core' => '1.0', @@ -92,7 +92,7 @@ public static function castImplementation(\DOMImplementation $dom, array $a, Stu return $a; } - public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested): array + public static function castNode(\DOMNode|\DOM\Node $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -104,15 +104,20 @@ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNes 'lastChild' => new CutStub($dom->lastChild), 'previousSibling' => new CutStub($dom->previousSibling), 'nextSibling' => new CutStub($dom->nextSibling), - 'attributes' => $dom->attributes, 'ownerDocument' => new CutStub($dom->ownerDocument), - 'namespaceURI' => $dom->namespaceURI, - 'prefix' => $dom->prefix, - 'localName' => $dom->localName, 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent), ]; + if ($dom instanceof \DOMNode || $dom instanceof \DOM\Element) { + $a += [ + 'attributes' => $dom->attributes, + 'namespaceURI' => $dom->namespaceURI, + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + ]; + } + return $a; } @@ -166,7 +171,48 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo return $a; } - public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested): array + public static function castXMLDocument(\DOM\XMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'xmlEncoding' => $dom->xmlEncoding, + 'xmlStandalone' => $dom->xmlStandalone, + 'xmlVersion' => $dom->xmlVersion, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + 'formatOutput' => $dom->formatOutput, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; + $dom->formatOutput = $formatOutput; + } + + return $a; + } + + public static function castHTMLDocument(\DOM\HTMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += [Caster::PREFIX_VIRTUAL.'html' => $dom->saveHTML()]; + } + + return $a; + } + + public static function castCharacterData(\DOMCharacterData|\DOM\CharacterData $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'data' => $dom->data, @@ -176,30 +222,40 @@ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub return $a; } - public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested): array + public static function castAttr(\DOMAttr|\DOM\Attr $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, 'specified' => $dom->specified, 'value' => $dom->value, 'ownerElement' => $dom->ownerElement, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMAttr) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested): array + public static function castElement(\DOMElement|\DOM\Element $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'tagName' => $dom->tagName, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMElement) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested): array + public static function castText(\DOMText|\DOM\Text $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'wholeText' => $dom->wholeText, @@ -208,7 +264,7 @@ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNes return $a; } - public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested): array + public static function castDocumentType(\DOMDocumentType|\DOM\DocumentType $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, @@ -222,7 +278,7 @@ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $s return $a; } - public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested): array + public static function castNotation(\DOMNotation|\DOM\Notation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -232,7 +288,7 @@ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, boo return $a; } - public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested): array + public static function castEntity(\DOMEntity|\DOM\Entity $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -246,7 +302,7 @@ public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $i return $a; } - public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array + public static function castProcessingInstruction(\DOMProcessingInstruction|\DOM\ProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'target' => $dom->target, @@ -256,7 +312,7 @@ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, return $a; } - public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested): array + public static function castXPath(\DOMXPath|\DOM\XPath $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'document' => $dom->document, diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index e7cb39469a58f..addab129747a6 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -54,23 +54,38 @@ abstract class AbstractCloner implements ClonerInterface 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'DOM\Exception' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'DOM\Implementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'DOM\Node' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'DOM\XMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXMLDocument'], + 'DOM\HTMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castHTMLDocument'], 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOM\NodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOM\DTDNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'DOM\CharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'DOM\Attr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'DOM\Element' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'DOM\Text' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'DOM\DocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'DOM\Notation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'DOM\Entity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'DOM\ProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/DOMCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/DOMCasterTest.php new file mode 100644 index 0000000000000..81cdc120ccd34 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/DOMCasterTest.php @@ -0,0 +1,303 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +class DOMCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testCastImplementation() + { + $implementation = new \DOMImplementation(); + + $this->assertDumpEquals(<<<'EODUMP' + DOMImplementation { + Core: "1.0" + XML: "2.0" + } + EODUMP, $implementation); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernImplementation() + { + $implementation = new \DOM\Implementation(); + + $this->assertDumpEquals(<<<'EODUMP' + DOM\Implementation { + Core: "1.0" + XML: "2.0" + } + EODUMP, $implementation); + } + + public function testCastNode() + { + $doc = new \DOMDocument(); + $doc->loadXML(''); + $node = $doc->documentElement->firstChild; + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMElement {%A + +ownerDocument: ? ?DOMDocument + +namespaceURI: ? ?string + +prefix: ? string + +localName: ? ?string + %A} + EODUMP, $node); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernNode() + { + $doc = \DOM\XMLDocument::createFromString(''); + $node = $doc->documentElement->firstChild; + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\Element {%A + +baseURI: ? string + +isConnected: ? bool + +ownerDocument: ? ?DOM\Document + %A} + EODUMP, $node); + } + + public function testCastDocument() + { + $doc = new \DOMDocument(); + $doc->loadXML(''); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMDocument {%A + xml: """ + \n + \n + \n + \n + """ + } + EODUMP, $doc); + } + + /** + * @requires PHP 8.4 + */ + public function testCastXMLDocument() + { + $doc = \DOM\XMLDocument::createFromString(''); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\XMLDocument {%A + xml: """ + \n + \n + \n + + """ + } + EODUMP, $doc); + } + + /** + * @requires PHP 8.4 + */ + public function testCastHTMLDocument() + { + $doc = \DOM\HTMLDocument::createFromString('

foo

'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\HTMLDocument {%A + html: "

foo

" + } + EODUMP, $doc); + } + + public function testCastText() + { + $doc = new \DOMText('foo'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMText {%A + +wholeText: ? string + } + EODUMP, $doc); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernText() + { + $text = \DOM\HTMLDocument::createEmpty()->createTextNode('foo'); + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\Text {%A + +wholeText: ? string + } + EODUMP, $text); + } + + public function testCastAttr() + { + $attr = new \DOMAttr('attr', 'value'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMAttr {%A + +name: ? string + +specified: true + +value: ? string + +ownerElement: ? ?DOMElement + +schemaTypeInfo: null + } + EODUMP, $attr); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernAttr() + { + $attr = \DOM\HTMLDocument::createEmpty()->createAttribute('attr'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\Attr {%A + +name: ? string + +value: ? string + +ownerElement: ? ?DOM\Element + +specified: true + } + EODUMP, $attr); + } + + public function testCastElement() + { + $attr = new \DOMElement('foo'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMElement {%A + +tagName: ? string + %A} + EODUMP, $attr); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernElement() + { + $attr = \DOM\HTMLDocument::createEmpty()->createElement('foo'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\Element {%A + +tagName: ? string + %A} + EODUMP, $attr); + } + + public function testCastDocumentType() + { + $implementation = new \DOMImplementation(); + $type = $implementation->createDocumentType('html', 'publicId', 'systemId'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMDocumentType {%A + +name: ? string + +entities: ? DOMNamedNodeMap + +notations: ? DOMNamedNodeMap + +publicId: ? string + +systemId: ? string + +internalSubset: ? ?string + } + EODUMP, $type); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernDocumentType() + { + $implementation = new \DOM\Implementation(); + $type = $implementation->createDocumentType('html', 'publicId', 'systemId'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\DocumentType {%A + +name: ? string + +entities: ? DOM\DTDNamedNodeMap + +notations: ? DOM\DTDNamedNodeMap + +publicId: ? string + +systemId: ? string + +internalSubset: ? ?string + } + EODUMP, $type); + } + + public function testCastProcessingInstruction() + { + $entity = new \DOMProcessingInstruction('target', 'data'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOMProcessingInstruction {%A + +target: ? string + +data: ? string + } + EODUMP, $entity); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernProcessingInstruction() + { + $entity = \DOM\HTMLDocument::createEmpty()->createProcessingInstruction('target', 'data'); + + $this->assertDumpMatchesFormat(<<<'EODUMP' + DOM\ProcessingInstruction {%A + +data: ? string + +length: ? int + +target: ? string + } + EODUMP, $entity); + } + + public function testCastXPath() + { + $xpath = new \DOMXPath(new \DOMDocument()); + + $this->assertDumpEquals(<<<'EODUMP' + DOMXPath { + +document: ? DOMDocument + +registerNodeNamespaces: ? bool + } + EODUMP, $xpath); + } + + /** + * @requires PHP 8.4 + */ + public function testCastModernXPath() + { + $entity = new \DOM\XPath(\DOM\HTMLDocument::createEmpty()); + + $this->assertDumpEquals(<<<'EODUMP' + DOM\XPath { + +document: ? DOM\Document + +registerNodeNamespaces: ? bool + } + EODUMP, $entity); + } +}