-
-
Notifications
You must be signed in to change notification settings - Fork 585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added support for xml-attributes as discriminators #692
added support for xml-attributes as discriminators #692
Conversation
Thanks for the pull request. Have a look also to #560 Some considerations:
|
Actually adding this to Discriminator, just like in #560 was our first approach, but after discussing this internally we concluded Discriminator would be better off remaining format-agnostic. With additional options in mind, i would like to suggest changing the new annotation to
which would enable future changes like
and changing the other drivers accordingly... |
hmm.. sounds reasonable. even now we have almost always xml-specific annotations. So interesting options would be:
right? |
Correct, just one question: I belive the current behaviour is to use cdata, which means we should default cdata to true...? |
@fivetide you are right, my bad, i have updated my comment |
Okay, i will propably get that done on monday, will update the PR then :) |
Ok, i updated the PR with the changes we agreed on. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job :)
i will just change the YAML format and few minor changes here and there...
the namespaced xml element will be cool to have, but can be implemented in a second iteration...)
@@ -58,6 +58,9 @@ class ClassMetadata extends MergeableClassMetadata | |||
public $discriminatorMap = array(); | |||
public $discriminatorGroups = array(); | |||
|
|||
public $xmlDiscriminatorAttribute = false; | |||
public $xmlDiscriminatorCData = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be $xmlDiscriminatorCDATA
or $xmlDiscriminatorCdata
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
capitalizing CD follows the convention used in PropertyMetadata::$xmlElementCData ...
@@ -257,6 +257,15 @@ private function addClassProperties(ClassMetadata $metadata, array $config) | |||
$metadata->xmlRootNamespace = (string) $config['xml_root_namespace']; | |||
} | |||
|
|||
if (isset($config['xml_discriminator'])) { | |||
if (isset($config['xml_discriminator']['attribute'])) { | |||
$metadata->xmlDiscriminatorAttribute = $config['xml_discriminator']['attribute']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cast to boolean please
$metadata->xmlDiscriminatorAttribute = $config['xml_discriminator']['attribute']; | ||
} | ||
if (isset($config['xml_discriminator']['cdata'])) { | ||
$metadata->xmlDiscriminatorCData = $config['xml_discriminator']['cdata']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cast to boolean please
@@ -99,6 +100,9 @@ public function loadMetadataForClass(\ReflectionClass $class) | |||
} else { | |||
$classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups); | |||
} | |||
} elseif ($annot instanceof XmlDiscriminator) { | |||
$classMetadata->xmlDiscriminatorAttribute = $annot->attribute; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cast to boolean please
@@ -99,6 +100,9 @@ public function loadMetadataForClass(\ReflectionClass $class) | |||
} else { | |||
$classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups); | |||
} | |||
} elseif ($annot instanceof XmlDiscriminator) { | |||
$classMetadata->xmlDiscriminatorAttribute = $annot->attribute; | |||
$classMetadata->xmlDiscriminatorCData = $annot->cdata; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cast to boolean please
<serializer> | ||
<class name="JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent" | ||
discriminator-field-name="type" | ||
xml-discriminator-attribute="true" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this attribute (i mean xml-discriminator-attribute
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, forgot to remove that one...
child: JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild | ||
xml_discriminator: | ||
attribute: true | ||
cdata: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about having a structure as:
JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent:
discriminator:
field_name: type
map:
child: JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild
xml_attribute: true
xml_element:
cdata: false
namespace: http://www.w3.org/2005/Atom
this is not a big deal, but is just to keep consistency with the current YAML metadata format.
(see http://jmsyst.com/libs/serializer/master/reference/yml_reference the xml_attribute property example)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the YAML format being wildly different to annotations and xml feels odd to me, but if you insist, i will change it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My idea is just to keep it consistent. I would like to keep consistency within a format mainly.
Having consistency across formats is nice to have.
Since XML and YAML formats have already differences, and users use only one of them, will try to keep them consistent with the rest of the format itself.
public function testDiscriminatorAsXmlAttribute() | ||
{ | ||
$xml = simplexml_load_string($this->serialize(new ObjectWithXmlAttributeDiscriminatorChild())); | ||
$this->assertEquals('type="child"', trim($xml->xpath('//result/@type')[0]->saveXML())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of "re-loading" the xml into a simplexml object, why not re-use the $this->getContent('template_name')
method? the whole test case will be:
$xml = $this->serialize(new ObjectWithXmlAttributeDiscriminatorChild());
$this->assertEquals($this->getContent('xml_discriminator_attribute'), $xml);
$this->assertInstanceOf(
ObjectWithXmlAttributeDiscriminatorChild::class,
$this->deserialize(
$xml,
ObjectWithXmlAttributeDiscriminatorParent::class
)
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the benefit when comparing to a predefined xml? I assumed the test should only cover if the discriminator is rendered as an attribute, while other aspects of xml-generation (whitespace, xml-header, if the tag is rendered as self-closing...) should not break the test, which might happen when comparing to predefined xml..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting topic about testing, and how much we want to do "unit" testing...
Your test currently tests only of the type is rendered as attribute... but what if for some other change, make the type to be rendered using both strategies.. I mean as attribute and as element? This test will not detect it.
Of course, testing the whole xml content, has some drawbacks, as example will give some "false" failures if we decide to change indentation or other format specific differences... that generally should not make fail your testcase.
To be honest, I prefer to have a false failure, instead of having a not detected failure.
(this means less "unit" testing, and going more in direction of functional or integration tests... (event if the border between this definitions is really blurry)
What is your opinion on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally and totally subjective, i like to have my tests represent actual requirements and i like to be able to treat them as much. When working with foreign code, i can not determine of a false failure is indeed false, or if there is an actual requirement... But since in this case, it is pretty obvious, i feel okay doing it your way.
@@ -261,6 +261,11 @@ private function resolveMetadata($data, ClassMetadata $metadata) | |||
$typeValue = (string) $data->{$metadata->discriminatorFieldName}; | |||
break; | |||
|
|||
// Check XML attribute for discriminatorFieldName | |||
case is_object($data) && $metadata->xmlDiscriminatorAttribute && isset($data[$metadata->discriminatorFieldName]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i will put this statement before the previous one
removed old attribute from test fixture changed order of metadata-resolution
changed syntax of yml configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry missed that small PSR thing. Will try to include this in 1.5.0 (next feature release).
@@ -278,6 +278,17 @@ private function addClassProperties(ClassMetadata $metadata, array $config) | |||
} | |||
$groups = isset($config['discriminator']['groups']) ? $config['discriminator']['groups'] : array(); | |||
$metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map'], $groups); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PSR standards, max one empty line
Thanks a lot! 👍 |
Until now when using Discriminator-maps with XML, the discriminator was hard coded to be a child node. This PR allows to use an attribute instead if desired.
would result in
now you can do this:
to get: