orm: DOMDocument schemaValidate error migrating to PHP 8.2

BC Break Report

Q A
BC Break not sure
Version 2.17.1 (latest at time of writing)

Summary

Currently upgrading one our projects to PHP 8.2 from PHP 7.4. Application runs fine on PHP 7.4 with doctrine/orm already on 2.17.1. However, when I bump the PHP-version to ^8.2 and run composer upgrade, the subsequent symfony console cache:clear fails with an Warning: DOMDocument::schemaValidate(): Invalid Schema error.

Previous behavior

The commands symfony console cache:clear works just fine.

Current behavior

When I bump the PHP-version to ^8.2 and run composer upgrade, the subsequent symfony console cache:clear fails with the following error:

 [WARNING] Some commands could not be registered:                                                                       

In XmlDriver.php line 1006:

  Warning: DOMDocument::schemaValidate(): Invalid Schema

Line 1006 is the schemaValidate() in the following code block in [...]/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php:

$backedUpErrorSetting = libxml_use_internal_errors(true);

try {
    $document = new DOMDocument();
    $document->load($file);

    if (! $document->schemaValidate(__DIR__ . '/../../../../../doctrine-mapping.xsd')) {
        throw MappingException::fromLibXmlErrors(libxml_get_errors());
    }

    // more code here
}

When I dump the $file that’s being processed, it outputs [...]/vendor/friendsofsymfony/user-bundle/Resources/config/doctrine-mapping/User.orm.xml. So you might think this problem is related to that particular bundle, where I also created an issue, however that packages also didn’t change versions during the version bump to PHP 8.2. Both doctrine/orm and friendsofsymfony/user-bundle were already on the latest version.

I messed around a little bit, to see if I could get some more info on the error. If I change the first line of that code block to $backedUpErrorSetting = libxml_use_internal_errors(false);, it shows a bit more information:

 [WARNING] Some commands could not be registered:                                                                       

In XmlDriver.php line 1006:

  Warning: DOMDocument::schemaValidate(): complex type 'sql-result-set-mapping': The content model is not determinist.

I assume I have an error somewhere in my model definition, that somehow was acceptable before the upgrade, but I have a hard time pinpointing where that might be. The friendsofsymfony/user-bundle file looks fine, and also works fine in another project we upgraded to PHP 8.2.

EDIT package overview and User model removed, because in the end they had nothing to do with this issue

Any suggestions?

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 41 (19 by maintainers)

Commits related to this issue

Most upvoted comments

$ /usr/local/opt/libxml2/bin/xmllint --version
/usr/local/opt/libxml2/bin/xmllint: using libxml version 21203
   compiled with: Threads Tree Output Push Reader Patterns Writer SAXv1 HTTP DTDValid HTML C14N Catalog XPath XPointer XInclude Iconv ICU ISO8859X Unicode Regexps Automata Schemas Schematron Modules Debug Zlib

Running xmllint against this file with the below schema which imports the ORM 2.17.2 XSD and the doctrine-extensions 3.14.0 XSD:

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema">
    <import namespace="http://doctrine-project.org/schemas/orm/doctrine-mapping" schemaLocation="./vendor/doctrine/orm/doctrine-mapping.xsd"/>
    <import namespace="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping" schemaLocation="./vendor/gedmo/doctrine-extensions/schemas/orm/doctrine-extensions-mapping-2-2.xsd"/>
</schema>
$ /usr/local/opt/libxml2/bin/xmllint --schema doctrine-mapping.xsd Sluggable.dcm.xml --noout
vendor/doctrine/orm/doctrine-mapping.xsd:146: element complexType: Schemas parser error : complex type 'sql-result-set-mapping': The content model is not determinist.
vendor/doctrine/orm/doctrine-mapping.xsd:227: element complexType: Schemas parser error : complex type 'mapped-superclass': The content model is not determinist.
vendor/doctrine/orm/doctrine-mapping.xsd:238: element complexType: Schemas parser error : complex type 'embeddable': The content model is not determinist.
vendor/doctrine/orm/doctrine-mapping.xsd:561: element complexType: Schemas parser error : complex type 'many-to-one': The content model is not determinist.
vendor/doctrine/orm/doctrine-mapping.xsd:579: element complexType: Schemas parser error : complex type 'one-to-one': The content model is not determinist.
WXS schema doctrine-mapping.xsd failed to compile

With this diff (based on the 2.17.2 tag), it validates:

diff --git a/doctrine-mapping.xsd b/doctrine-mapping.xsd
index a9b1a367e..4c78c805c 100644
--- a/doctrine-mapping.xsd
+++ b/doctrine-mapping.xsd
@@ -148,7 +148,7 @@
         <xs:choice minOccurs="0" maxOccurs="unbounded">
             <xs:element name="entity-result" type="orm:entity-result"/>
             <xs:element name="column-result" type="orm:column-result"/>
-            <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
+            <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
         </xs:choice>
         <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
     </xs:choice>
@@ -228,7 +228,7 @@
     <xs:complexContent>
       <xs:extension base="orm:entity">
         <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
+          <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
         </xs:choice>
         <xs:anyAttribute namespace="##other"/>
       </xs:extension>
@@ -239,7 +239,7 @@
     <xs:complexContent>
       <xs:extension base="orm:entity">
         <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
+          <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
         </xs:choice>
       </xs:extension>
     </xs:complexContent>
@@ -565,7 +565,7 @@
       <xs:choice minOccurs="0" maxOccurs="1">
         <xs:element name="join-column" type="orm:join-column"/>
         <xs:element name="join-columns" type="orm:join-columns"/>
-        <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
+        <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
       </xs:choice>
       <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
     </xs:choice>
@@ -583,7 +583,7 @@
       <xs:choice minOccurs="0" maxOccurs="1">
         <xs:element name="join-column" type="orm:join-column"/>
         <xs:element name="join-columns" type="orm:join-columns"/>
-        <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
+        <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
       </xs:choice>
       <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
     </xs:choice>

As far as I know the version 2.12.3 should run fine

2.12.3 might not have the segmentation fault, but I see no reason why it would no longer have the schema validation error.

[root@host ~]# ea-php82 -i | grep libxml
[...snip...]
libxml Version => 2.12.2
libxml
libxml2 Version => 2.12.2
libxslt compiled against libxml Version => 2.9.1

Linked files as they are now:

[root@host ~]# ea-php82 parse.php 
<pre>array(5) {
  [0]=>
  object(LibXMLError)#2 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(77) "complex type 'sql-result-set-mapping': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(146)
  }
  [1]=>
  object(LibXMLError)#3 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(72) "complex type 'mapped-superclass': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(227)
  }
  [2]=>
  object(LibXMLError)#4 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(65) "complex type 'embeddable': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(238)
  }
  [3]=>
  object(LibXMLError)#5 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(66) "complex type 'many-to-one': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(561)
  }
  [4]=>
  object(LibXMLError)#6 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(65) "complex type 'one-to-one': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(579)
  }
}
</pre>

After commenting the <xs:any tag in the sql-result-set-mapping type:

[root@host ~]# ea-php82 parse.php 
<pre>array(4) {
  [0]=>
  object(LibXMLError)#2 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(72) "complex type 'mapped-superclass': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(227)
  }
  [1]=>
  object(LibXMLError)#3 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(65) "complex type 'embeddable': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(238)
  }
  [2]=>
  object(LibXMLError)#4 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(66) "complex type 'many-to-one': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(561)
  }
  [3]=>
  object(LibXMLError)#5 (6) {
    ["level"]=>
    int(2)
    ["code"]=>
    int(3070)
    ["column"]=>
    int(0)
    ["message"]=>
    string(65) "complex type 'one-to-one': The content model is not determinist.
"
    ["file"]=>
    string(26) "/root/doctrine-mapping.xsd"
    ["line"]=>
    int(579)
  }
}
</pre>

So, yes, it does appear to be related to those tags and the issue reported by @shyim with Shopware’s XSD at least looks somewhat related.

It’s not all of the any’s, either. This passes for sql-result-set-mapping:

  <xs:complexType name="sql-result-set-mapping">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="entity-result" type="orm:entity-result"/>
            <xs:element name="column-result" type="orm:column-result"/>
            <!-- <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/> -->
        </xs:choice>
        <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
    </xs:choice>
    <xs:attribute name="name" type="xs:string" use="required" />
  </xs:complexType>

Thanks @greg0ire for fixing this nasty problem. If I’m not mistaken, the fix seems to be scheduled for 2.18.x. When can I expect 2.18.0 to be made available to the general public?

EDIT My bad, it’s already in 2.17.3. Thanks again!

@mbabker could you maybe work on producing an XSD file that:

  • is valid according to the latest libxml
  • still allows gedmo/doctrine-extensions to work?

Don’t really know if this is a fix or just some cheat.

It’s a cheat. That validate_xml_mapping setting disables the XML schema validation, preventing the error in this thread from being triggered in the first place. And IIRC, that setting is no-op’d with ORM 3 and XML validation is always required.

Can confirm 2.12.3 still causes the schema validation error. Only remedy still remains xsd:any change.

Don’t use 2.12.0 or 2.12.1, those versions had bugs causing PHP to segfault. https://github.com/php/php-src/issues/12847

Yeah, there’s a whole chain of issues on the DoctrineExtensions repo about the XML mappings and validation issues in general, which to my understanding of https://github.com/doctrine-extensions/DoctrineExtensions/issues/2055 haven’t even worked with the MongoDB ODM for years since they went strict on their schema and totally disallowed extending like the ORM had allowed.

When you know exactly which elements will be inside the XML I would get rid of the xsd:any. In our case it was allowed to add custom elements which were not described in the xsd.

Exactly, the error concerns the schema file (doctrine-mapping.xsd), not the current xml file that needs to be checked.

Hi! 👋 After reading this, I think I should have added an @. Can you try restoring the code to its initial state then adding an @, like so:

-if (! @$document->schemaValidate(__DIR__ . '/../../../../../doctrine-mapping.xsd')) {
+if (! $document->schemaValidate(__DIR__ . '/../../../../../doctrine-mapping.xsd')) {

After that, you should get a detailed error message.