MimeMessageNormalizer.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Serializer\Normalizer;
  11. use Symfony\Component\Mime\Address;
  12. use Symfony\Component\Mime\Header\HeaderInterface;
  13. use Symfony\Component\Mime\Header\Headers;
  14. use Symfony\Component\Mime\Header\UnstructuredHeader;
  15. use Symfony\Component\Mime\Message;
  16. use Symfony\Component\Mime\Part\AbstractPart;
  17. use Symfony\Component\Serializer\SerializerAwareInterface;
  18. use Symfony\Component\Serializer\SerializerInterface;
  19. /**
  20. * Normalize Mime message classes.
  21. *
  22. * It forces the use of a PropertyNormalizer instance for normalization
  23. * of all data objects composing a Message.
  24. *
  25. * Emails using resources for any parts are not serializable.
  26. */
  27. final class MimeMessageNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
  28. {
  29. private $serializer;
  30. private $normalizer;
  31. private $headerClassMap;
  32. private $headersProperty;
  33. public function __construct(PropertyNormalizer $normalizer)
  34. {
  35. $this->normalizer = $normalizer;
  36. $this->headerClassMap = (new \ReflectionClassConstant(Headers::class, 'HEADER_CLASS_MAP'))->getValue();
  37. $this->headersProperty = new \ReflectionProperty(Headers::class, 'headers');
  38. $this->headersProperty->setAccessible(true);
  39. }
  40. public function setSerializer(SerializerInterface $serializer)
  41. {
  42. $this->serializer = $serializer;
  43. $this->normalizer->setSerializer($serializer);
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function normalize($object, ?string $format = null, array $context = [])
  49. {
  50. if ($object instanceof Headers) {
  51. $ret = [];
  52. foreach ($this->headersProperty->getValue($object) as $name => $header) {
  53. $ret[$name] = $this->serializer->normalize($header, $format, $context);
  54. }
  55. return $ret;
  56. }
  57. if ($object instanceof AbstractPart) {
  58. $ret = $this->normalizer->normalize($object, $format, $context);
  59. $ret['class'] = \get_class($object);
  60. return $ret;
  61. }
  62. return $this->normalizer->normalize($object, $format, $context);
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function denormalize($data, string $type, ?string $format = null, array $context = [])
  68. {
  69. if (Headers::class === $type) {
  70. $ret = [];
  71. foreach ($data as $headers) {
  72. foreach ($headers as $header) {
  73. $ret[] = $this->serializer->denormalize($header, $this->headerClassMap[strtolower($header['name'])] ?? UnstructuredHeader::class, $format, $context);
  74. }
  75. }
  76. return new Headers(...$ret);
  77. }
  78. if (AbstractPart::class === $type) {
  79. $type = $data['class'];
  80. unset($data['class']);
  81. }
  82. return $this->normalizer->denormalize($data, $type, $format, $context);
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. public function supportsNormalization($data, string $format = null)
  88. {
  89. return $data instanceof Message || $data instanceof Headers || $data instanceof HeaderInterface || $data instanceof Address || $data instanceof AbstractPart;
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function supportsDenormalization($data, string $type, ?string $format = null)
  95. {
  96. return is_a($type, Message::class, true) || Headers::class === $type || AbstractPart::class === $type;
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function hasCacheableSupportsMethod(): bool
  102. {
  103. return __CLASS__ === static::class;
  104. }
  105. }