ArrayCollectionHandler   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Test Coverage

Coverage 87.88%

Importance

Changes 0
Metric Value
eloc 63
dl 0
loc 143
ccs 29
cts 33
cp 0.8788
rs 10
c 0
b 0
f 0
wmc 20

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribingMethods() 0 24 3
C deserializeCollection() 0 54 12
A __construct() 0 6 1
A serializeCollection() 0 21 4
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
Bug introduced by
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\Type\Type;
18
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
19
use JMS\Serializer\Visitor\SerializationVisitorInterface;
20
21
/**
22 329
 * @phpstan-import-type TypeArray from Type
23
 */
24 329
final class ArrayCollectionHandler implements SubscribingHandlerInterface
25 329
{
26
    public const COLLECTION_TYPES = [
27 329
        'ArrayCollection',
28
        ArrayCollection::class,
29 329
        OrmPersistentCollection::class,
30 329
        MongoPersistentCollection::class,
31
        PhpcrPersistentCollection::class,
32 329
    ];
33
34
    /**
35
     * @var bool
36
     */
37
    private $initializeExcluded;
38
39 329
    /**
40 329
     * @var ManagerRegistry|null
41 329
     */
42 329
    private $managerRegistry;
43 329
44 329
    public function __construct(
45 329
        bool $initializeExcluded = true,
46
        ?ManagerRegistry $managerRegistry = null
47
    ) {
48 329
        $this->initializeExcluded = $initializeExcluded;
49 329
        $this->managerRegistry = $managerRegistry;
50 329
    }
51 329
52 329
    /**
53
     * {@inheritdoc}
54
     */
55
    public static function getSubscribingMethods()
56
    {
57 329
        $methods = [];
58
        $formats = ['json', 'xml'];
59
60 9
        foreach (self::COLLECTION_TYPES as $type) {
61
            foreach ($formats as $format) {
62
                $methods[] = [
63 9
                    'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
64
                    'type' => $type,
65 9
                    'format' => $format,
66
                    'method' => 'serializeCollection',
67 9
                ];
68
69
                $methods[] = [
70
                    'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
71
                    'type' => $type,
72
                    'format' => $format,
73
                    'method' => 'deserializeCollection',
74
                ];
75 9
            }
76
        }
77 9
78 9
        return $methods;
79
    }
80
81 6
    /**
82
     * @param TypeArray $type
0 ignored issues
show
Bug introduced by
The type JMS\Serializer\Handler\TypeArray 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...
83
     *
84 6
     * @return array|\ArrayObject
85
     */
86 6
    public function serializeCollection(SerializationVisitorInterface $visitor, Collection $collection, array $type, SerializationContext $context)
87
    {
88
        // We change the base type, and pass through possible parameters.
89
        $type['name'] = 'array';
90
91
        $context->stopVisiting($collection);
92
93
        if (false === $this->initializeExcluded) {
94
            $exclusionStrategy = $context->getExclusionStrategy();
95
            if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) {
0 ignored issues
show
Bug introduced by
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

95
            if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass(/** @scrutinizer ignore-type */ $context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) {
Loading history...
96
                $context->startVisiting($collection);
97
98
                return $visitor->visitArray([], $type);
99
            }
100
        }
101
102
        $result = $visitor->visitArray($collection->toArray(), $type);
103
104
        $context->startVisiting($collection);
105
106
        return $result;
107
    }
108
109
    /**
110
     * @param mixed $data
111
     * @param TypeArray $type
112
     */
113
    public function deserializeCollection(
114
        DeserializationVisitorInterface $visitor,
115
        $data,
116
        array $type,
117
        DeserializationContext $context
118
    ): Collection {
119
        // See above.
120
        $type['name'] = 'array';
121
122
        $elements = new ArrayCollection($visitor->visitArray($data, $type));
123
124
        if (null === $this->managerRegistry) {
125
            return $elements;
126
        }
127
128
        $propertyMetadata = $context->getMetadataStack()->top();
129
        if (!$propertyMetadata instanceof PropertyMetadata) {
130
            return $elements;
131
        }
132
133
        $objectManager = $this->managerRegistry->getManagerForClass($propertyMetadata->class);
134
        if (null === $objectManager) {
135
            return $elements;
136
        }
137
138
        $classMetadata = $objectManager->getClassMetadata($propertyMetadata->class);
139
        $currentObject = $visitor->getCurrentObject();
0 ignored issues
show
Bug introduced by
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

139
        /** @scrutinizer ignore-call */ 
140
        $currentObject = $visitor->getCurrentObject();
Loading history...
140
141
        if (
142
            array_key_exists('name', $propertyMetadata->type)
143
            && in_array($propertyMetadata->type['name'], self::COLLECTION_TYPES)
144
            && $classMetadata->isCollectionValuedAssociation($propertyMetadata->name)
145
        ) {
146
            $existingCollection = $classMetadata->getFieldValue($currentObject, $propertyMetadata->name);
0 ignored issues
show
Bug introduced by
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

146
            /** @scrutinizer ignore-call */ 
147
            $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...
147
            if (!$existingCollection instanceof OrmPersistentCollection) {
148
                return $elements;
149
            }
150
151
            foreach ($elements as $element) {
152
                if (!$existingCollection->contains($element)) {
153
                    $existingCollection->add($element);
154
                }
155
            }
156
157
            foreach ($existingCollection as $collectionElement) {
158
                if (!$elements->contains($collectionElement)) {
159
                    $existingCollection->removeElement($collectionElement);
160
                }
161
            }
162
163
            return $existingCollection;
164
        }
165
166
        return $elements;
167
    }
168
}
169