Skip to content

Write a namespaced class name with dots, and refuse a document the parser objects to - #5

Merged
ctrlaltca merged 1 commit into
pradosoft:masterfrom
belisoful:4-namespaced-providers
Sep 17, 2026
Merged

ctrlaltca merged 1 commit into
pradosoft:masterfrom
belisoful:4-namespaced-providers

Conversation

@belisoful

Copy link
Copy Markdown
Member

Fixes #4.

The provider's class name reached the document as it stood: in the target namespace, urn:App\Soap\QuoteProviderwsdl, and in the definitions, portType, binding, service and port names and the QNames referring to them. A backslash is valid in neither a URI nor an NCName. libxml loads such a document and warns about the namespace, PRADO's error handler turns the warning into an exception, and TSoapServer::getWsdl() threw for every namespaced provider. The unreleased loadOrFail() hid the warning behind @ and handed the document back, which is worse: it parses, and no client accepts it.

A namespaced type had a related gap. The @PARAM, @return, @var and @soaptype grammars accepted only \w, so App\Soap\Quote was cut at the first separator and reflected on as a class named App.

Separate the class name, which reflection needs, from the name the document carries. Wsdl::documentName() replaces each separator with a dot and drops a leading one, so App\Soap\QuoteProvider is written as App.Soap.QuoteProvider, valid as both a URN and an NCName. The full name is kept rather than the short one, so two classes sharing a short name do not collide. Wsdl maps the service name once and writes the mapped name everywhere, and convertType() maps a type name the same way while declaring it and referring to it, so every tns: reference resolves to the complexType it names, the Array form included. The four tags take a fully qualified name, with or without the leading separator; a short name resolves in the global namespace as it always did.

A class name holds nothing else the mapping touches, so a global class produces the document it always did, byte for byte. Two documents generated before this change are committed under tests/unit/Fixtures and compared whole, in both styles.

loadOrFail() no longer hides anything. It keeps libxml's errors internal, so no warning reaches an error handler, and refuses a document the parser said anything about, naming what it said. The first parse now catches an invalid namespace, so the re-parse of the serialized document is gone. A service name that is not a class name and yields a URN the parser rejects, such as one holding a quote or a space, is refused where it loaded with a hidden warning before.

The SOAP client and server of PHP accept the document of a namespaced provider in both styles: a client reads the signatures and the dotted struct names, and a client calling a server in the same process round-trips a call, through an adapter in the document style, where PHP hands a method the request wrapper as one object and encodes what it returns as the response wrapper.

…e a document the parser objects to

The provider's class name reached the document as it stood: in the target
namespace, urn:App\Soap\QuoteProviderwsdl, and in the definitions, portType,
binding, service and port names and the QNames referring to them. A backslash
is valid in neither a URI nor an NCName. libxml loads such a document and warns
about the namespace, PRADO's error handler turns the warning into an exception,
and TSoapServer::getWsdl() threw for every namespaced provider. The unreleased
loadOrFail() hid the warning behind @ and handed the document back, which is
worse: it parses, and no client accepts it.

A namespaced type had a related gap. The @PARAM, @return, @var and @soaptype
grammars accepted only \w, so App\Soap\Quote was cut at the first separator and
reflected on as a class named App.

Separate the class name, which reflection needs, from the name the document
carries. Wsdl::documentName() replaces each separator with a dot and drops a
leading one, so App\Soap\QuoteProvider is written as App.Soap.QuoteProvider,
valid as both a URN and an NCName. The full name is kept rather than the short
one, so two classes sharing a short name do not collide. Wsdl maps the service
name once and writes the mapped name everywhere, and convertType() maps a type
name the same way while declaring it and referring to it, so every tns:
reference resolves to the complexType it names, the Array form included. The
four tags take a fully qualified name, with or without the leading separator;
a short name resolves in the global namespace as it always did.

A class name holds nothing else the mapping touches, so a global class produces
the document it always did, byte for byte. Two documents generated before this
change are committed under tests/unit/Fixtures and compared whole, in both
styles.

loadOrFail() no longer hides anything. It keeps libxml's errors internal, so
no warning reaches an error handler, and refuses a document the parser said
anything about, naming what it said. The first parse now catches an invalid
namespace, so the re-parse of the serialized document is gone. A service name
that is not a class name and yields a URN the parser rejects, such as one
holding a quote or a space, is refused where it loaded with a hidden warning
before.

The SOAP client and server of PHP accept the document of a namespaced provider
in both styles: a client reads the signatures and the dotted struct names, and
a client calling a server in the same process round-trips a call, through an
adapter in the document style, where PHP hands a method the request wrapper as
one object and encodes what it returns as the response wrapper.
@ctrlaltca
ctrlaltca merged commit 8e3577e into pradosoft:master Sep 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A namespaced provider class produces an invalid WSDL

2 participants