122 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is part of the Symfony package.
 | 
						|
 *
 | 
						|
 * (c) Fabien Potencier <fabien@symfony.com>
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view the LICENSE
 | 
						|
 * file that was distributed with this source code.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Symfony\Component\Serializer\Normalizer;
 | 
						|
 | 
						|
use Symfony\Component\Mime\Address;
 | 
						|
use Symfony\Component\Mime\Header\HeaderInterface;
 | 
						|
use Symfony\Component\Mime\Header\Headers;
 | 
						|
use Symfony\Component\Mime\Header\UnstructuredHeader;
 | 
						|
use Symfony\Component\Mime\Message;
 | 
						|
use Symfony\Component\Mime\Part\AbstractPart;
 | 
						|
use Symfony\Component\Mime\RawMessage;
 | 
						|
use Symfony\Component\Serializer\Exception\LogicException;
 | 
						|
use Symfony\Component\Serializer\SerializerAwareInterface;
 | 
						|
use Symfony\Component\Serializer\SerializerInterface;
 | 
						|
 | 
						|
/**
 | 
						|
 * Normalize Mime message classes.
 | 
						|
 *
 | 
						|
 * It forces the use of a PropertyNormalizer instance for normalization
 | 
						|
 * of all data objects composing a Message.
 | 
						|
 *
 | 
						|
 * Emails using resources for any parts are not serializable.
 | 
						|
 */
 | 
						|
final class MimeMessageNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
 | 
						|
{
 | 
						|
    private NormalizerInterface&DenormalizerInterface $serializer;
 | 
						|
    private array $headerClassMap;
 | 
						|
    private \ReflectionProperty $headersProperty;
 | 
						|
 | 
						|
    public function __construct(private readonly PropertyNormalizer $normalizer)
 | 
						|
    {
 | 
						|
        $this->headerClassMap = (new \ReflectionClassConstant(Headers::class, 'HEADER_CLASS_MAP'))->getValue();
 | 
						|
        $this->headersProperty = new \ReflectionProperty(Headers::class, 'headers');
 | 
						|
    }
 | 
						|
 | 
						|
    public function getSupportedTypes(?string $format): array
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            Message::class => true,
 | 
						|
            Headers::class => true,
 | 
						|
            HeaderInterface::class => true,
 | 
						|
            Address::class => true,
 | 
						|
            AbstractPart::class => true,
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    public function setSerializer(SerializerInterface $serializer): void
 | 
						|
    {
 | 
						|
        if (!$serializer instanceof NormalizerInterface || !$serializer instanceof DenormalizerInterface) {
 | 
						|
            throw new LogicException(\sprintf('The passed serializer should implement both NormalizerInterface and DenormalizerInterface, "%s" given.', get_debug_type($serializer)));
 | 
						|
        }
 | 
						|
        $this->serializer = $serializer;
 | 
						|
        $this->normalizer->setSerializer($serializer);
 | 
						|
    }
 | 
						|
 | 
						|
    public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
 | 
						|
    {
 | 
						|
        if ($data instanceof Headers) {
 | 
						|
            $ret = [];
 | 
						|
            foreach ($this->headersProperty->getValue($data) as $name => $header) {
 | 
						|
                $ret[$name] = $this->serializer->normalize($header, $format, $context);
 | 
						|
            }
 | 
						|
 | 
						|
            return $ret;
 | 
						|
        }
 | 
						|
 | 
						|
        $ret = $this->normalizer->normalize($data, $format, $context);
 | 
						|
 | 
						|
        if ($data instanceof AbstractPart) {
 | 
						|
            $ret['class'] = $data::class;
 | 
						|
            unset($ret['seekable'], $ret['cid'], $ret['handle']);
 | 
						|
        }
 | 
						|
 | 
						|
        if ($data instanceof RawMessage && \array_key_exists('message', $ret) && null === $ret['message']) {
 | 
						|
            unset($ret['message']);
 | 
						|
        }
 | 
						|
 | 
						|
        return $ret;
 | 
						|
    }
 | 
						|
 | 
						|
    public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
 | 
						|
    {
 | 
						|
        if (Headers::class === $type) {
 | 
						|
            $ret = [];
 | 
						|
            foreach ($data as $headers) {
 | 
						|
                foreach ($headers as $header) {
 | 
						|
                    $ret[] = $this->serializer->denormalize($header, $this->headerClassMap[strtolower($header['name'])] ?? UnstructuredHeader::class, $format, $context);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return new Headers(...$ret);
 | 
						|
        }
 | 
						|
 | 
						|
        if (AbstractPart::class === $type) {
 | 
						|
            $type = $data['class'];
 | 
						|
            unset($data['class']);
 | 
						|
            $data['headers'] = $this->serializer->denormalize($data['headers'], Headers::class, $format, $context);
 | 
						|
        }
 | 
						|
 | 
						|
        return $this->normalizer->denormalize($data, $type, $format, $context);
 | 
						|
    }
 | 
						|
 | 
						|
    public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
 | 
						|
    {
 | 
						|
        return $data instanceof Message || $data instanceof Headers || $data instanceof HeaderInterface || $data instanceof Address || $data instanceof AbstractPart;
 | 
						|
    }
 | 
						|
 | 
						|
    public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
 | 
						|
    {
 | 
						|
        return is_a($type, Message::class, true) || Headers::class === $type || AbstractPart::class === $type;
 | 
						|
    }
 | 
						|
}
 |