Skip to content
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

Jms deserializer class with parent properties #1135

Open
shubaivan opened this issue Oct 30, 2019 · 8 comments
Open

Jms deserializer class with parent properties #1135

shubaivan opened this issue Oct 30, 2019 · 8 comments

Comments

@shubaivan
Copy link

shubaivan commented Oct 30, 2019

Q A
Bug report? yes
Feature request? yes
BC Break report? no
RFC? no

I use "jms/serializer": "^3.3", stand alone. And my goal create parent class for two child with common properties. I did it. Cretae parent class Request and two child - ApiRequest and FormRequest. Child differ in that they have different serializer names for properties that's all. I use yml mapping.

/**
 * Class Request
 */

class Request
{
/**
 * @var SignatureType
 * @Assert\NotBlank()
 */
public $signatureType;

Child

/**
 * Class ApiRequest
 * @package CDB\Collection\DTO
 * @RequestApplication()
 * @SignatoryTypeConstraint()
 */
class ApiRequest extends Request
{

}

and child config CDB.Collection.DTO.ApiRequest.yml

CDB\Collection\DTO\ApiRequest:
  exclusion_policy: ALL
  properties:
    signatureType:
      expose: true
      type: string
      serialized_name: signatureType

For parent I don't have config

and when I try deserialize json

{
 
    "signatureType": "bankid"
}

Object have empty property

When I try deserializer json

{
 
    "signature_type": "bankid"
}

I determined that metadata for child class did not contain `propertyMetadata. When I remove condtiion in

src/Metadata/Driver/YamlDriver.php

from

            foreach ($class->getProperties() as $property) {
                if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
                    continue;
                }

to

            foreach ($class->getProperties() as $property) {
                if ((isset($property->info) && $property->info['class'] !== $name) {
                    continue;
                }

$metadata for my class metadata began to contain data about my child class. Because $class->getProperties() reflection function which get properties from parent, that's why property class name and class for which metadata generated is different.
Maybe I select wrong way or who know how to correct work with yml configuration for class whose properties from parent classes ?

Steps required to reproduce the problem

  1. Create Child and Parent classes. Properties only in parent
  2. Configure yml annotation for child class with differ properties configuration
  3. Try deserialize child class

Expected Result

  • metadata contain parent properties and handle it by child configure

Actual Result

  • metadata for child class don't contain propertyMetadata
@goetas
Copy link
Collaborator

goetas commented Oct 30, 2019

In jms/serializer properties are per class. Any change that you need in the parent class have to be done in the parent class metadata definition.

If you need to deserialize a json, make sure to provide the type for each property for each class.

@shubaivan
Copy link
Author

shubaivan commented Oct 31, 2019

@goetas Example I have one parent class and two child with differ serialize rules, serialized name example, this mean need deserializer the same model but with the differ properties configurationб becasuse from different resources got different json

{

"signature_type": "bankid"

}

and

{

"signatureType": "bankid"

}

for this case I create one parent class and two child and create two yml configuration for child... But in yml driver class, properties not set to metadata class, because getProperties for reflection class initialize class parent for each properties and this condition $property->class !== $name rerurn true. That's prolem. I solved creating PR

#1136

But if it wrong approach, could you explain how to do it right ?

@shubaivan
Copy link
Author

In jms/serializer properties are per class. Any change that you need in the parent class have to be done in the parent class metadata definition.

If you need to deserialize a json, make sure to provide the type for each property for each class.

I don't need provide type or something else for parent class, because it should be dynamically by creating configuration for each child classes. This approach does not imply configuration properties for parent class, only for childs

@goetas
Copy link
Collaborator

goetas commented Oct 31, 2019

Dynanic type should be done by type handlers or event listeners. Each property must have a type defined.

@shubaivan
Copy link
Author

shubaivan commented Oct 31, 2019

@goetas yes, it's true, each property must have type (but if exclusion_policy: ALL and property describe on config with expose: true) an other configuration which describe in child yml configuration. But each child contain different configurto for the same properties which describe in parent class. LIke this

CDB\Collection\DTO\FormRequest:
  exclusion_policy: ALL
  properties:
    signatureType:
      expose: true
      type: string
      from_parent: true
      serialized_name: application_signature_type
    type:
      expose: true
      type: string
      from_parent: true
      serialized_name: application_app_types
      accessor:
        setter: setAccessorType
    received:
      expose: true
      type: DateTime<'Y-m-d H:i'>
      from_parent: true
      serialized_name: application_received

and

CDB\Collection\DTO\ApiRequest:
  exclusion_policy: ALL
  properties:
    signatureType:
      expose: true
      type: string
      from_parent: true
      serialized_name: SignatureType
    type:
      expose: true
      type: string
      from_parent: true
      serialized_name: Type
      accessor:
        setter: setAccessorType
    received:
      expose: true
      type: DateTime<'Y-m-d'>
      from_parent: true
      serialized_name: Received 
    company:
      expose: true
      type: CDB\Collection\DTO\Company
      from_parent: true
      serialized_name: Company   
class ApiRequest extends CommonRequest
{

}
class FormRequest extends CommonRequest
{

}

and parent

abstract class CommonRequest 
{
    /**
     * @var Collection\Company
     * @Assert\NotBlank()
     * @Assert\Valid()
     */
    public $company;

    /**
     * @var SignatureType
     * @Assert\NotBlank()
     */
    public $signatureType;

    /**
     * set default app type
     * @var int|null
     */
    public $type = Application::REGULAR_KEY;

    /**
     * @var string|\DateTime|null
     */
    public $received;

and json for FormRequest in this case I hande data about company use event listeners and other approach

{
    "application_app_types": 1,
    "application_signature_type": "bankid",
    "application_received": "2019-10-31 12:00",
    "company_billing_type": "common",
    "company_billing_method": "e_invoice",
    "company_bank_account_number": "23123214214124"
}

and json for ApiRequest in case I have ready data about Company and I don't need use listener or accessor or something else, just add type CompanyClass tha's all

{
    "Company": {
        "BillingMethod": "card",
        "BillingType": "spec",
        "BankAccountNumber": "string"
    },
    "SignatureType": "bankid",
    "Received": "2019-08-29T08:24:41.479Z",
    "Type": "credit"
}

In this case I don't need create to separaet model, just one, abstract class and two empty child with differ configuration

@shubaivan
Copy link
Author

@goetas and I suggest use pre deserilizer where cast json to one format bad idea, becase there can be many entry points and each can have its own json format. I agree it sounds bad, but it could be

@goetas
Copy link
Collaborator

goetas commented Oct 31, 2019

In CDB\Collection\DTO\FormRequest the signatureType property is ignored as it is defined in CDB\Collection\DTO\ApiRequest

@shubaivan
Copy link
Author

shubaivan commented Oct 31, 2019

@goetas property signatureType defined in parent class CommonRequest but in child ApiRequest and FormRequest have different configuration, like the others property have different configuration to

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

No branches or pull requests

2 participants