Issues (163)

src/Handler/ArrayCollectionHandler.php (4 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer\Handler;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Doctrine\ODM\MongoDB\PersistentCollection as MongoPersistentCollection;
0 ignored issues
show
The type Doctrine\ODM\MongoDB\PersistentCollection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Doctrine\ODM\PHPCR\PersistentCollection as PhpcrPersistentCollection;
11
use Doctrine\ORM\PersistentCollection as OrmPersistentCollection;
12
use Doctrine\Persistence\ManagerRegistry;
13
use JMS\Serializer\DeserializationContext;
14
use JMS\Serializer\GraphNavigatorInterface;
15
use JMS\Serializer\Metadata\PropertyMetadata;
16
use JMS\Serializer\SerializationContext;
17
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
18
use JMS\Serializer\Visitor\SerializationVisitorInterface;
19
20
final class ArrayCollectionHandler implements SubscribingHandlerInterface
21
{
22 329
    public const COLLECTION_TYPES = [
23
        'ArrayCollection',
24 329
        ArrayCollection::class,
25 329
        OrmPersistentCollection::class,
26
        MongoPersistentCollection::class,
27 329
        PhpcrPersistentCollection::class,
28
    ];
29 329
30 329
    /**
31
     * @var bool
32 329
     */
33
    private $initializeExcluded;
34
35
    /**
36
     * @var ManagerRegistry|null
37
     */
38
    private $managerRegistry;
39 329
40 329
    public function __construct(
41 329
        bool $initializeExcluded = true,
42 329
        ?ManagerRegistry $managerRegistry = null
43 329
    ) {
44 329
        $this->initializeExcluded = $initializeExcluded;
45 329
        $this->managerRegistry = $managerRegistry;
46
    }
47
48 329
    /**
49 329
     * {@inheritdoc}
50 329
     */
51 329
    public static function getSubscribingMethods()
52 329
    {
53
        $methods = [];
54
        $formats = ['json', 'xml'];
55
56
        foreach (self::COLLECTION_TYPES as $type) {
57 329
            foreach ($formats as $format) {
58
                $methods[] = [
59
                    'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
60 9
                    'type' => $type,
61
                    'format' => $format,
62
                    'method' => 'serializeCollection',
63 9
                ];
64
65 9
                $methods[] = [
66
                    'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
67 9
                    'type' => $type,
68
                    'format' => $format,
69
                    'method' => 'deserializeCollection',
70
                ];
71
            }
72
        }
73
74
        return $methods;
75 9
    }
76
77 9
    /**
78 9
     * @return array|\ArrayObject
79
     */
80
    public function serializeCollection(SerializationVisitorInterface $visitor, Collection $collection, array $type, SerializationContext $context)
81 6
    {
82
        // We change the base type, and pass through possible parameters.
83
        $type['name'] = 'array';
84 6
85
        $context->stopVisiting($collection);
86 6
87
        if (false === $this->initializeExcluded) {
88
            $exclusionStrategy = $context->getExclusionStrategy();
89
            if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) {
0 ignored issues
show
It seems like $context->getMetadataFac...get_class($collection)) can also be of type Metadata\ClassHierarchyMetadata and null; however, parameter $metadata of JMS\Serializer\Exclusion...face::shouldSkipClass() does only seem to accept JMS\Serializer\Metadata\ClassMetadata, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
            if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass(/** @scrutinizer ignore-type */ $context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) {
Loading history...
90
                $context->startVisiting($collection);
91
92
                return $visitor->visitArray([], $type);
93
            }
94
        }
95
96
        $result = $visitor->visitArray($collection->toArray(), $type);
97
98
        $context->startVisiting($collection);
99
100
        return $result;
101
    }
102
103
    /**
104
     * @param mixed $data
105
     */
106
    public function deserializeCollection(
107
        DeserializationVisitorInterface $visitor,
108
        $data,
109
        array $type,
110
        DeserializationContext $context
111
    ): Collection {
112
        // See above.
113
        $type['name'] = 'array';
114
115
        $elements = new ArrayCollection($visitor->visitArray($data, $type));
116
117
        if (null === $this->managerRegistry) {
118
            return $elements;
119
        }
120
121
        $propertyMetadata = $context->getMetadataStack()->top();
122
        if (!$propertyMetadata instanceof PropertyMetadata) {
123
            return $elements;
124
        }
125
126
        $objectManager = $this->managerRegistry->getManagerForClass($propertyMetadata->class);
127
        if (null === $objectManager) {
128
            return $elements;
129
        }
130
131
        $classMetadata = $objectManager->getClassMetadata($propertyMetadata->class);
132
        $currentObject = $visitor->getCurrentObject();
0 ignored issues
show
The method getCurrentObject() does not exist on JMS\Serializer\Visitor\D...izationVisitorInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to JMS\Serializer\Visitor\D...izationVisitorInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

132
        /** @scrutinizer ignore-call */ 
133
        $currentObject = $visitor->getCurrentObject();
Loading history...
133
134
        if (
135
            array_key_exists('name', $propertyMetadata->type)
136
            && in_array($propertyMetadata->type['name'], self::COLLECTION_TYPES)
137
            && $classMetadata->isCollectionValuedAssociation($propertyMetadata->name)
138
        ) {
139
            $existingCollection = $classMetadata->getFieldValue($currentObject, $propertyMetadata->name);
0 ignored issues
show
The method getFieldValue() does not exist on Doctrine\Persistence\Mapping\ClassMetadata. Did you maybe mean getFieldNames()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
            /** @scrutinizer ignore-call */ 
140
            $existingCollection = $classMetadata->getFieldValue($currentObject, $propertyMetadata->name);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
140
            if (!$existingCollection instanceof OrmPersistentCollection) {
141
                return $elements;
142
            }
143
144
            foreach ($elements as $element) {
145
                if (!$existingCollection->contains($element)) {
146
                    $existingCollection->add($element);
147
                }
148
            }
149
150
            foreach ($existingCollection as $collectionElement) {
151
                if (!$elements->contains($collectionElement)) {
152
                    $existingCollection->removeElement($collectionElement);
153
                }
154
            }
155
156
            return $existingCollection;
157
        }
158
159
        return $elements;
160
    }
161
}
162