Introduce Dom\AdjacentPosition and use it in the insert adjacent methods

See https://wiki.php.net/rfc/dom_additions_84#allowing_php-specific_developer_experience_improvements
This commit is contained in:
Niels Dossche 2024-06-23 22:00:54 +02:00
parent a068a9a5bb
commit e4250cec79
7 changed files with 140 additions and 25 deletions

View file

@ -66,5 +66,6 @@ extern PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry;
#endif #endif
extern PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_adjacent_position_class_entry;
#endif /* DOM_CE_H */ #endif /* DOM_CE_H */

View file

@ -21,6 +21,7 @@
#include "php.h" #include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM) #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "zend_enum.h"
#include "php_dom.h" #include "php_dom.h"
#include "namespace_compat.h" #include "namespace_compat.h"
#include "internal_helpers.h" #include "internal_helpers.h"
@ -1573,17 +1574,12 @@ static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp
/* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacentelement /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacentelement
Since: Since:
*/ */
static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *element_ce) static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, const zend_string *where, zval *element_zval)
{ {
zend_string *where; zval *id;
zval *element_zval, *id;
xmlNodePtr thisp, otherp; xmlNodePtr thisp, otherp;
dom_object *this_intern, *other_intern; dom_object *this_intern, *other_intern;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SO", &where, &element_zval, element_ce) != SUCCESS) {
RETURN_THROWS();
}
DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern); DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern);
DOM_GET_OBJ(otherp, element_zval, xmlNodePtr, other_intern); DOM_GET_OBJ(otherp, element_zval, xmlNodePtr, other_intern);
@ -1599,29 +1595,39 @@ static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, ze
PHP_METHOD(DOMElement, insertAdjacentElement) PHP_METHOD(DOMElement, insertAdjacentElement)
{ {
dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_element_class_entry); zend_string *where;
zval *element_zval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SO", &where, &element_zval, dom_element_class_entry) != SUCCESS) {
RETURN_THROWS();
}
dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, element_zval);
} }
PHP_METHOD(Dom_Element, insertAdjacentElement) PHP_METHOD(Dom_Element, insertAdjacentElement)
{ {
dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_element_class_entry); zval *element_zval, *where_zv;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(where_zv, dom_adjacent_position_class_entry)
Z_PARAM_OBJECT_OF_CLASS(element_zval, dom_modern_element_class_entry)
ZEND_PARSE_PARAMETERS_END();
const zend_string *where = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(where_zv)));
dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, element_zval);
} }
/* }}} end DOMElement::insertAdjacentElement */ /* }}} end DOMElement::insertAdjacentElement */
/* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacenttext /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacenttext
Since: Since:
*/ */
PHP_METHOD(DOMElement, insertAdjacentText) static void dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAMETERS, const zend_string *where, const zend_string *data)
{ {
zend_string *where, *data;
dom_object *this_intern; dom_object *this_intern;
zval *id; zval *id;
xmlNodePtr thisp; xmlNodePtr thisp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &where, &data) == FAILURE) {
RETURN_THROWS();
}
DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern); DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern);
if (UNEXPECTED(ZEND_SIZE_T_INT_OVFL(ZSTR_LEN(data)))) { if (UNEXPECTED(ZEND_SIZE_T_INT_OVFL(ZSTR_LEN(data)))) {
@ -1635,6 +1641,31 @@ PHP_METHOD(DOMElement, insertAdjacentText)
xmlFreeNode(otherp); xmlFreeNode(otherp);
} }
} }
PHP_METHOD(DOMElement, insertAdjacentText)
{
zend_string *where, *data;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &where, &data) == FAILURE) {
RETURN_THROWS();
}
dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, data);
}
PHP_METHOD(Dom_Element, insertAdjacentText)
{
zval *where_zv;
zend_string *data;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(where_zv, dom_adjacent_position_class_entry)
Z_PARAM_STR(data)
ZEND_PARSE_PARAMETERS_END();
const zend_string *where = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(where_zv)));
dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, data);
}
/* }}} end DOMElement::insertAdjacentText */ /* }}} end DOMElement::insertAdjacentText */
/* {{{ URL: https://dom.spec.whatwg.org/#dom-element-toggleattribute /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-toggleattribute

View file

@ -22,6 +22,7 @@
#include "php.h" #include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM) #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "zend_enum.h"
#include "php_dom.h" #include "php_dom.h"
#include "nodelist.h" #include "nodelist.h"
#include "html_collection.h" #include "html_collection.h"
@ -84,6 +85,7 @@ PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry;
#endif #endif
PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_adjacent_position_class_entry;
/* }}} */ /* }}} */
static zend_object_handlers dom_object_handlers; static zend_object_handlers dom_object_handlers;
@ -729,6 +731,8 @@ PHP_MINIT_FUNCTION(dom)
zend_hash_init(&classes, 0, NULL, NULL, true); zend_hash_init(&classes, 0, NULL, NULL, true);
dom_adjacent_position_class_entry = register_class_Dom_AdjacentPosition();
dom_domexception_class_entry = register_class_DOMException(zend_ce_exception); dom_domexception_class_entry = register_class_DOMException(zend_ce_exception);
dom_parentnode_class_entry = register_class_DOMParentNode(); dom_parentnode_class_entry = register_class_DOMParentNode();

View file

@ -1280,6 +1280,14 @@ namespace Dom
public function getIterator(): \Iterator {} public function getIterator(): \Iterator {}
} }
enum AdjacentPosition : string
{
case BeforeBegin = "beforebegin";
case AfterBegin = "afterbegin";
case BeforeEnd = "beforeend";
case AfterEnd = "afterend";
}
class Element extends Node implements ParentNode, ChildNode class Element extends Node implements ParentNode, ChildNode
{ {
/** @readonly */ /** @readonly */
@ -1330,9 +1338,8 @@ namespace Dom
public function getElementsByTagName(string $qualifiedName): HTMLCollection {} public function getElementsByTagName(string $qualifiedName): HTMLCollection {}
public function getElementsByTagNameNS(?string $namespace, string $localName): HTMLCollection {} public function getElementsByTagNameNS(?string $namespace, string $localName): HTMLCollection {}
public function insertAdjacentElement(string $where, Element $element): ?Element {} public function insertAdjacentElement(AdjacentPosition $where, Element $element): ?Element {}
/** @implementation-alias DOMElement::insertAdjacentText */ public function insertAdjacentText(AdjacentPosition $where, string $data): void {}
public function insertAdjacentText(string $where, string $data): void {}
/** @readonly */ /** @readonly */
public ?Element $firstElementChild; public ?Element $firstElementChild;

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: e75e734f710ab2c18322463f348b95dde4f937b2 */ * Stub hash: c93643bad9675fddf31ca52f82f843218f208a5d */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0)
ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0) ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0)
@ -797,11 +797,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Dom_Element_getElementsByTa
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Dom_Element_insertAdjacentElement, 0, 2, Dom\\Element, 1) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Dom_Element_insertAdjacentElement, 0, 2, Dom\\Element, 1)
ZEND_ARG_TYPE_INFO(0, where, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, where, Dom\\AdjacentPosition, 0)
ZEND_ARG_OBJ_INFO(0, element, Dom\\Element, 0) ZEND_ARG_OBJ_INFO(0, element, Dom\\Element, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#define arginfo_class_Dom_Element_insertAdjacentText arginfo_class_DOMElement_insertAdjacentText ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Dom_Element_insertAdjacentText, 0, 2, IS_VOID, 0)
ZEND_ARG_OBJ_INFO(0, where, Dom\\AdjacentPosition, 0)
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Dom_Element_setIdAttribute, 0, 2, IS_VOID, 0) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Dom_Element_setIdAttribute, 0, 2, IS_VOID, 0)
ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0)
@ -1267,6 +1270,7 @@ ZEND_METHOD(Dom_Element, removeAttributeNode);
ZEND_METHOD(Dom_Element, getElementsByTagName); ZEND_METHOD(Dom_Element, getElementsByTagName);
ZEND_METHOD(Dom_Element, getElementsByTagNameNS); ZEND_METHOD(Dom_Element, getElementsByTagNameNS);
ZEND_METHOD(Dom_Element, insertAdjacentElement); ZEND_METHOD(Dom_Element, insertAdjacentElement);
ZEND_METHOD(Dom_Element, insertAdjacentText);
ZEND_METHOD(Dom_Element, setIdAttributeNode); ZEND_METHOD(Dom_Element, setIdAttributeNode);
ZEND_METHOD(Dom_CharacterData, appendData); ZEND_METHOD(Dom_CharacterData, appendData);
ZEND_METHOD(Dom_CharacterData, insertData); ZEND_METHOD(Dom_CharacterData, insertData);
@ -1632,6 +1636,10 @@ static const zend_function_entry class_Dom_HTMLCollection_methods[] = {
ZEND_FE_END ZEND_FE_END
}; };
static const zend_function_entry class_Dom_AdjacentPosition_methods[] = {
ZEND_FE_END
};
static const zend_function_entry class_Dom_Element_methods[] = { static const zend_function_entry class_Dom_Element_methods[] = {
ZEND_RAW_FENTRY("hasAttributes", zim_DOMNode_hasAttributes, arginfo_class_Dom_Element_hasAttributes, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("hasAttributes", zim_DOMNode_hasAttributes, arginfo_class_Dom_Element_hasAttributes, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("getAttributeNames", zim_DOMElement_getAttributeNames, arginfo_class_Dom_Element_getAttributeNames, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("getAttributeNames", zim_DOMElement_getAttributeNames, arginfo_class_Dom_Element_getAttributeNames, ZEND_ACC_PUBLIC, NULL, NULL)
@ -1652,7 +1660,7 @@ static const zend_function_entry class_Dom_Element_methods[] = {
ZEND_ME(Dom_Element, getElementsByTagName, arginfo_class_Dom_Element_getElementsByTagName, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, getElementsByTagName, arginfo_class_Dom_Element_getElementsByTagName, ZEND_ACC_PUBLIC)
ZEND_ME(Dom_Element, getElementsByTagNameNS, arginfo_class_Dom_Element_getElementsByTagNameNS, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, getElementsByTagNameNS, arginfo_class_Dom_Element_getElementsByTagNameNS, ZEND_ACC_PUBLIC)
ZEND_ME(Dom_Element, insertAdjacentElement, arginfo_class_Dom_Element_insertAdjacentElement, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, insertAdjacentElement, arginfo_class_Dom_Element_insertAdjacentElement, ZEND_ACC_PUBLIC)
ZEND_RAW_FENTRY("insertAdjacentText", zim_DOMElement_insertAdjacentText, arginfo_class_Dom_Element_insertAdjacentText, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Dom_Element, insertAdjacentText, arginfo_class_Dom_Element_insertAdjacentText, ZEND_ACC_PUBLIC)
ZEND_RAW_FENTRY("setIdAttribute", zim_DOMElement_setIdAttribute, arginfo_class_Dom_Element_setIdAttribute, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("setIdAttribute", zim_DOMElement_setIdAttribute, arginfo_class_Dom_Element_setIdAttribute, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("setIdAttributeNS", zim_DOMElement_setIdAttributeNS, arginfo_class_Dom_Element_setIdAttributeNS, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("setIdAttributeNS", zim_DOMElement_setIdAttributeNS, arginfo_class_Dom_Element_setIdAttributeNS, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_ME(Dom_Element, setIdAttributeNode, arginfo_class_Dom_Element_setIdAttributeNode, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, setIdAttributeNode, arginfo_class_Dom_Element_setIdAttributeNode, ZEND_ACC_PUBLIC)
@ -2957,6 +2965,33 @@ static zend_class_entry *register_class_Dom_HTMLCollection(zend_class_entry *cla
return class_entry; return class_entry;
} }
static zend_class_entry *register_class_Dom_AdjacentPosition(void)
{
zend_class_entry *class_entry = zend_register_internal_enum("Dom\\AdjacentPosition", IS_STRING, class_Dom_AdjacentPosition_methods);
zval enum_case_BeforeBegin_value;
zend_string *enum_case_BeforeBegin_value_str = zend_string_init("beforebegin", strlen("beforebegin"), 1);
ZVAL_STR(&enum_case_BeforeBegin_value, enum_case_BeforeBegin_value_str);
zend_enum_add_case_cstr(class_entry, "BeforeBegin", &enum_case_BeforeBegin_value);
zval enum_case_AfterBegin_value;
zend_string *enum_case_AfterBegin_value_str = zend_string_init("afterbegin", strlen("afterbegin"), 1);
ZVAL_STR(&enum_case_AfterBegin_value, enum_case_AfterBegin_value_str);
zend_enum_add_case_cstr(class_entry, "AfterBegin", &enum_case_AfterBegin_value);
zval enum_case_BeforeEnd_value;
zend_string *enum_case_BeforeEnd_value_str = zend_string_init("beforeend", strlen("beforeend"), 1);
ZVAL_STR(&enum_case_BeforeEnd_value, enum_case_BeforeEnd_value_str);
zend_enum_add_case_cstr(class_entry, "BeforeEnd", &enum_case_BeforeEnd_value);
zval enum_case_AfterEnd_value;
zend_string *enum_case_AfterEnd_value_str = zend_string_init("afterend", strlen("afterend"), 1);
ZVAL_STR(&enum_case_AfterEnd_value, enum_case_AfterEnd_value_str);
zend_enum_add_case_cstr(class_entry, "AfterEnd", &enum_case_AfterEnd_value);
return class_entry;
}
static zend_class_entry *register_class_Dom_Element(zend_class_entry *class_entry_Dom_Node, zend_class_entry *class_entry_Dom_ParentNode, zend_class_entry *class_entry_Dom_ChildNode) static zend_class_entry *register_class_Dom_Element(zend_class_entry *class_entry_Dom_Node, zend_class_entry *class_entry_Dom_ParentNode, zend_class_entry *class_entry_Dom_ChildNode)
{ {
zend_class_entry ce, *class_entry; zend_class_entry ce, *class_entry;

View file

@ -0,0 +1,37 @@
--TEST--
Element::insertAdjacentElement()
--EXTENSIONS--
dom
--FILE--
<?php
$dom = Dom\XMLDocument::createFromString('<?xml version="1.0"?><container><p>foo</p></container>');
$container = $dom->documentElement;
$p = $container->firstElementChild;
var_dump($p->insertAdjacentElement(Dom\AdjacentPosition::BeforeBegin, $dom->createElement('A'))->tagName);
echo $dom->saveXML(), "\n";
var_dump($p->insertAdjacentElement(Dom\AdjacentPosition::AfterBegin, $dom->createElement('B'))->tagName);
echo $dom->saveXML(), "\n";
var_dump($p->insertAdjacentElement(Dom\AdjacentPosition::BeforeEnd, $dom->createElement('C'))->tagName);
echo $dom->saveXML(), "\n";
var_dump($p->insertAdjacentElement(Dom\AdjacentPosition::AfterEnd, $dom->createElement('D'))->tagName);
echo $dom->saveXML(), "\n";
?>
--EXPECT--
string(1) "A"
<?xml version="1.0" encoding="UTF-8"?>
<container><A/><p>foo</p></container>
string(1) "B"
<?xml version="1.0" encoding="UTF-8"?>
<container><A/><p><B/>foo</p></container>
string(1) "C"
<?xml version="1.0" encoding="UTF-8"?>
<container><A/><p><B/>foo<C/></p></container>
string(1) "D"
<?xml version="1.0" encoding="UTF-8"?>
<container><A/><p><B/>foo<C/></p><D/></container>

View file

@ -8,13 +8,13 @@ dom
$dom = Dom\HTMLDocument::createEmpty(); $dom = Dom\HTMLDocument::createEmpty();
$foo = $dom->appendChild($dom->createElement("foo")); $foo = $dom->appendChild($dom->createElement("foo"));
try { try {
$foo->insertAdjacentText("beforebegin", "bar"); $foo->insertAdjacentText(Dom\AdjacentPosition::BeforeBegin, "bar");
} catch (DOMException $e) { } catch (DOMException $e) {
echo $e->getMessage(), "\n"; echo $e->getMessage(), "\n";
} }
$foo->insertAdjacentText("afterbegin", "bar"); $foo->insertAdjacentText(Dom\AdjacentPosition::AfterBegin, "bar");
$foo->insertAdjacentText("beforeend", "baz"); $foo->insertAdjacentText(Dom\AdjacentPosition::BeforeEnd, "baz");
echo $dom->saveHtml(), "\n"; echo $dom->saveHtml(), "\n";