1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Handler;
6
7use JMS\Serializer\DeserializationContext;
8use JMS\Serializer\GraphNavigatorInterface;
9use JMS\Serializer\SerializationContext;
10use JMS\Serializer\Visitor\DeserializationVisitorInterface;
11use JMS\Serializer\Visitor\SerializationVisitorInterface;
12
13final class IteratorHandler implements SubscribingHandlerInterface
14{
15    private const SUPPORTED_FORMATS = ['json', 'xml'];
16
17    /**
18     * {@inheritdoc}
19     */
20    public static function getSubscribingMethods()
21    {
22        $methods = [];
23
24        foreach (self::SUPPORTED_FORMATS as $format) {
25            $methods[] = [
26                'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
27                'type' => \ArrayIterator::class,
28                'format' => $format,
29                'method' => 'serializeIterator',
30            ];
31
32            $methods[] = [
33                'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
34                'type' => \ArrayIterator::class,
35                'format' => $format,
36                'method' => 'deserializeIterator',
37            ];
38        }
39
40        foreach (self::SUPPORTED_FORMATS as $format) {
41            $methods[] = [
42                'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
43                'type' => \Generator::class,
44                'format' => $format,
45                'method' => 'serializeIterator',
46            ];
47
48            $methods[] = [
49                'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
50                'type' => \Generator::class,
51                'format' => $format,
52                'method' => 'deserializeGenerator',
53            ];
54        }
55
56        return $methods;
57    }
58
59    /**
60     * @return mixed[]|\ArrayObject
61     */
62    public function serializeIterator(
63        SerializationVisitorInterface $visitor,
64        \Iterator $iterator,
65        array $type,
66        SerializationContext $context
67    ) {
68        $type['name'] = 'array';
69
70        $context->stopVisiting($iterator);
71        $result = $visitor->visitArray(iterator_to_array($iterator), $type);
72        $context->startVisiting($iterator);
73
74        return $result;
75    }
76
77    /**
78     * @param mixed $data
79     */
80    public function deserializeIterator(
81        DeserializationVisitorInterface $visitor,
82        $data,
83        array $type,
84        DeserializationContext $context
85    ): \Iterator {
86        $type['name'] = 'array';
87
88        return new \ArrayIterator($visitor->visitArray($data, $type));
89    }
90
91
92    /**
93     * @param mixed $data
94     */
95    public function deserializeGenerator(
96        DeserializationVisitorInterface $visitor,
97        $data,
98        array $type,
99        DeserializationContext $context
100    ): \Generator {
101        return (static function () use (&$visitor, &$data, &$type): \Generator {
102            $type['name'] = 'array';
103            foreach ($visitor->visitArray($data, $type) as $key => $item) {
104                yield $key => $item;
105            }
106        })();
107    }
108}
109