Skip to content

[Serializer] Name Converter #4692

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

Merged
merged 6 commits into from
Mar 13, 2015
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 102 additions & 23 deletions components/serializer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,38 +162,117 @@ needs three parameters:
2. The name of the class this information will be decoded to
3. The encoder used to convert that information into an array

Using Camelized Method Names for Underscored Attributes
-------------------------------------------------------
Converting Property Names when Serializing and Deserializing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add an anchor above this line, to make sure it's BC? (oh dear, doc starts to worry about BC too :(...

.. _using-camelized-method-names-for-underscored-attributes:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the anchor when speaking about snake_case and CamelCase.

------------------------------------------------------------

.. versionadded:: 2.3
The :method:`GetSetMethodNormalizer::setCamelizedAttributes<Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer::setCamelizedAttributes>`
method was introduced in Symfony 2.3.
.. versionadded:: 2.7
The :class:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface`
interface was introduced in Symfony 2.7.

Sometimes property names from the serialized content are underscored (e.g.
``first_name``). Normally, these attributes will use get/set methods like
``getFirst_name``, when ``getFirstName`` method is what you really want. To
change that behavior use the
:method:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer::setCamelizedAttributes`
method on the normalizer definition::
Sometimes serialized attributes must be named differently than properties
or getter and setter methods of PHP classes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would prefer "...differently than properties or getter / setter methods of PHP classes"


$encoder = new JsonEncoder();
$normalizer = new GetSetMethodNormalizer();
$normalizer->setCamelizedAttributes(array('first_name'));
The Serializer Component provides a handy way to translate or map PHP field
names to serialized names: The Name Converter System.

$serializer = new Serializer(array($normalizer), array($encoder));
Given you have the following object::

class Company
{
public name;
public address;
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove one blank line.

And in the serialized form, all attributes must be prefixed by ``org_`` like
the following::

{"org_name": "Les-Tilleuls.coop", "org_address": "Euratechnologies, 2 rue Hegel, 59160 Lomme, France"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's OK to use a real company name and address. What about using ACME as the rest of the documentation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you gimme details for the Acme org (the fake address used)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the following?

{ "org_name": "Acme Inc.", "org_address": "123 Main Street" }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use an address in the docs, something like "426 Jordy Lodge, Cartwrightshire, SC 88120-6700" will do (just a random address generated by Faker).

Or @javiereguiluz's proposal (which is maybe even better)


A custom Name Converter can handle such cases::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name converter (lowercased)


use Symfony\Component\Serializer\NameConverter\NameConverterInterface;

class OrgPrefixNameConverter implements NameConverterInterface
{
public function normalize($propertyName)
{
return 'org_'.$propertyName;
}

public function denormalize($propertyName)
{
// remove org_ prefix
return 'org_' === substr($propertyName, 0, 4) ? substr($propertyName, 4) : $propertyName;
}
}

$json = <<<EOT
The custom normalizer can be used by passing it as second parameter of any
class extending :class:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never like using "code names" much in docs. I think just using human language makes things easier to read. If "[...] by passing it as second parameter of any normalizer, including [...]" is correct, I'm in favor of using that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, the name converter system will only work if the custom serializer extends the abstract class. It will not work if it directly implements the interface, so "any" isn't true.

including :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer`
and :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer`::

use Symfony\Component\Serializer\Encoder\JsonEncoder
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;

$nameConverter = new OrgPrefixNameConverter();
$normalizer = new PropertyNormalizer(null, $nameConverter);

$serializer = new Serializer(array(new JsonEncoder()), array($normalizer));

$obj = new Company();
$obj->name = 'Les-Tilleuls.coop';
$obj->address = 'Euratechnologies, 2 rue Hegel, 59160 Lomme, France';

$json = $serializer->serialize($obj);
// {"org_name": "Les-Tilleuls.coop", "org_address": "Euratechnologies, 2 rue Hegel, 59160 Lomme, France"}
$objCopy = $serializer->deserialize($json);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add some comments showing the result.

// Same data as $obj

.. _using-camelized-method-names-for-underscored-attributes:

CamelCase to snake_case
~~~~~~~~~~~~~~~~~~~~~~~

.. versionadded:: 2.7
The :class:`Symfony\\Component\\Serializer\\NameConverter\\CamelCaseToUnderscoreNameConverter`
interface was introduced in Symfony 2.7.

In many formats, it's common to use underscores to separate words (also know
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor typo: also know -> also known

as snake_case). However, PSR-1 specifies that the preferred style for PHP
properties and methods is CamelCase.

Symfony provides a built-in Name Converter designed to translate between
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should Name Converter be spelled as name converter in this phrase? To me these words look like common words in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question for native English speakers: I think that the translate word is too related to translating (human) languages. Could it be better to use switch, transform, etc. or is it OK to keep using translate?

snake_case and CamelCased styles during serialization and deserialization
processes::

use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;

$normalizer = new GetSetMethodNormalizer(null, new CamelCaseToSnakeCaseNameConverter());

class Person
{
"name": "foo",
"age": "19",
"first_name": "bar"
private $firstName;

public function __construct($firstName)
{
$this->firstName = $firstName;
}

public function getFirstName()
{
return $this->firstName;
}
}
EOT;

$person = $serializer->deserialize($json, 'Acme\Person', 'json');
$kevin = new Person('Kévin');
$normalizer->normalize($kevin);
// ['first_name' => 'Kévin'];

As a final result, the deserializer uses the ``first_name`` attribute as if
it were ``firstName`` and uses the ``getFirstName`` and ``setFirstName`` methods.
$anne = $normalizer->denormalize(array('first_name' => 'Anne'), 'Person');
// Person object with firstName: 'Anne'

Serializing Boolean Attributes
------------------------------
Expand Down