1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Handler; 6 7use JMS\Serializer\GraphNavigatorInterface; 8use JMS\Serializer\JsonSerializationVisitor; 9use JMS\Serializer\Visitor\SerializationVisitorInterface; 10use JMS\Serializer\XmlSerializationVisitor; 11use Symfony\Component\Form\Form; 12use Symfony\Component\Form\FormError; 13use Symfony\Component\Translation\TranslatorInterface; 14 15final class FormErrorHandler implements SubscribingHandlerInterface 16{ 17 /** 18 * @var TranslatorInterface|null 19 */ 20 private $translator; 21 22 /** 23 * @var string 24 */ 25 private $translationDomain; 26 27 28 /** 29 * {@inheritdoc} 30 */ 31 public static function getSubscribingMethods() 32 { 33 $methods = []; 34 foreach (['xml', 'json'] as $format) { 35 $methods[] = [ 36 'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION, 37 'type' => 'Symfony\Component\Form\Form', 38 'format' => $format, 39 ]; 40 $methods[] = [ 41 'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION, 42 'type' => 'Symfony\Component\Form\FormError', 43 'format' => $format, 44 ]; 45 } 46 47 return $methods; 48 } 49 50 public function __construct(?TranslatorInterface $translator = null, string $translationDomain = 'validators') 51 { 52 $this->translator = $translator; 53 $this->translationDomain = $translationDomain; 54 } 55 56 /** 57 * @param array $type 58 */ 59 public function serializeFormToXml(XmlSerializationVisitor $visitor, Form $form, array $type): \DOMElement 60 { 61 $formNode = $visitor->getDocument()->createElement('form'); 62 63 $formNode->setAttribute('name', $form->getName()); 64 65 $formNode->appendChild($errorsNode = $visitor->getDocument()->createElement('errors')); 66 foreach ($form->getErrors() as $error) { 67 $errorNode = $visitor->getDocument()->createElement('entry'); 68 $errorNode->appendChild($this->serializeFormErrorToXml($visitor, $error, [])); 69 $errorsNode->appendChild($errorNode); 70 } 71 72 foreach ($form->all() as $child) { 73 if ($child instanceof Form) { 74 if (null !== $node = $this->serializeFormToXml($visitor, $child, [])) { 75 $formNode->appendChild($node); 76 } 77 } 78 } 79 80 return $formNode; 81 } 82 83 /** 84 * @param array $type 85 */ 86 public function serializeFormToJson(JsonSerializationVisitor $visitor, Form $form, array $type): \ArrayObject 87 { 88 return $this->convertFormToArray($visitor, $form); 89 } 90 91 /** 92 * @param array $type 93 */ 94 public function serializeFormErrorToXml(XmlSerializationVisitor $visitor, FormError $formError, array $type): \DOMCdataSection 95 { 96 return $visitor->getDocument()->createCDATASection($this->getErrorMessage($formError)); 97 } 98 99 /** 100 * @param array $type 101 */ 102 public function serializeFormErrorToJson(JsonSerializationVisitor $visitor, FormError $formError, array $type): string 103 { 104 return $this->getErrorMessage($formError); 105 } 106 107 private function getErrorMessage(FormError $error): ?string 108 { 109 if (null === $this->translator) { 110 return $error->getMessage(); 111 } 112 113 if (null !== $error->getMessagePluralization()) { 114 return $this->translator->transChoice($error->getMessageTemplate(), $error->getMessagePluralization(), $error->getMessageParameters(), $this->translationDomain); 115 } 116 117 return $this->translator->trans($error->getMessageTemplate(), $error->getMessageParameters(), $this->translationDomain); 118 } 119 120 private function convertFormToArray(SerializationVisitorInterface $visitor, Form $data): \ArrayObject 121 { 122 $form = new \ArrayObject(); 123 $errors = []; 124 foreach ($data->getErrors() as $error) { 125 $errors[] = $this->getErrorMessage($error); 126 } 127 128 if ($errors) { 129 $form['errors'] = $errors; 130 } 131 132 $children = []; 133 foreach ($data->all() as $child) { 134 if ($child instanceof Form) { 135 $children[$child->getName()] = $this->convertFormToArray($visitor, $child); 136 } 137 } 138 139 if ($children) { 140 $form['children'] = $children; 141 } 142 143 return $form; 144 } 145} 146