1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer; 6 7use JMS\Serializer\Exception\RuntimeException; 8use Metadata\MetadataFactoryInterface; 9 10class SerializationContext extends Context 11{ 12 /** @var \SplObjectStorage */ 13 private $visitingSet; 14 15 /** @var \SplStack */ 16 private $visitingStack; 17 18 /** 19 * @var string 20 */ 21 private $initialType; 22 23 /** 24 * @var bool 25 */ 26 private $serializeNull = false; 27 28 public static function create(): self 29 { 30 return new self(); 31 } 32 33 public function initialize(string $format, VisitorInterface $visitor, GraphNavigatorInterface $navigator, MetadataFactoryInterface $factory): void 34 { 35 parent::initialize($format, $visitor, $navigator, $factory); 36 37 $this->visitingSet = new \SplObjectStorage(); 38 $this->visitingStack = new \SplStack(); 39 } 40 41 /** 42 * Set if NULLs should be serialized (TRUE) ot not (FALSE) 43 */ 44 public function setSerializeNull(bool $bool): self 45 { 46 $this->serializeNull = $bool; 47 48 return $this; 49 } 50 51 /** 52 * Returns TRUE when NULLs should be serialized 53 * Returns FALSE when NULLs should not be serialized 54 */ 55 public function shouldSerializeNull(): bool 56 { 57 return $this->serializeNull; 58 } 59 60 /** 61 * @param mixed $object 62 */ 63 public function startVisiting($object): void 64 { 65 if (!\is_object($object)) { 66 return; 67 } 68 $this->visitingSet->attach($object); 69 $this->visitingStack->push($object); 70 } 71 72 /** 73 * @param mixed $object 74 */ 75 public function stopVisiting($object): void 76 { 77 if (!\is_object($object)) { 78 return; 79 } 80 $this->visitingSet->detach($object); 81 $poppedObject = $this->visitingStack->pop(); 82 83 if ($object !== $poppedObject) { 84 throw new RuntimeException('Context visitingStack not working well'); 85 } 86 } 87 88 /** 89 * @param mixed $object 90 */ 91 public function isVisiting($object): bool 92 { 93 if (!\is_object($object)) { 94 return false; 95 } 96 97 return $this->visitingSet->contains($object); 98 } 99 100 public function getPath(): ?string 101 { 102 $path = []; 103 foreach ($this->visitingStack as $obj) { 104 $path[] = \get_class($obj); 105 } 106 107 if (!$path) { 108 return null; 109 } 110 111 return implode(' -> ', $path); 112 } 113 114 public function getDirection(): int 115 { 116 return GraphNavigatorInterface::DIRECTION_SERIALIZATION; 117 } 118 119 public function getDepth(): int 120 { 121 return $this->visitingStack->count(); 122 } 123 124 public function getObject(): ?object 125 { 126 return !$this->visitingStack->isEmpty() ? $this->visitingStack->top() : null; 127 } 128 129 public function getVisitingStack(): \SplStack 130 { 131 return $this->visitingStack; 132 } 133 134 135 public function getVisitingSet(): \SplObjectStorage 136 { 137 return $this->visitingSet; 138 } 139 140 /** 141 * @return $this 142 */ 143 public function setInitialType(string $type): self 144 { 145 $this->initialType = $type; 146 $this->setAttribute('initial_type', $type); 147 return $this; 148 } 149 150 public function getInitialType(): ?string 151 { 152 return $this->initialType 153 ? $this->initialType 154 : $this->hasAttribute('initial_type') ? $this->getAttribute('initial_type') : null; 155 } 156} 157