Completed
Push — master ( 1250b5...ac33b4 )
by Pavel
04:37
created

DoctrineObjectNormalizer::getAssociationValue()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 4
cts 5
cp 0.8
rs 9.4285
cc 3
eloc 5
nc 2
nop 2
crap 3.072
1
<?php
2
3
namespace ScayTrase\Api\Cruds\Adaptors\DoctrineOrm;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\Persistence\ManagerRegistry;
7
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
8
use Doctrine\Common\Persistence\ObjectManager;
9
use Doctrine\ORM\EntityManagerInterface;
10
use Doctrine\ORM\Mapping\ClassMetadata;
11
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
12
13
class DoctrineObjectNormalizer extends ObjectNormalizer
14
{
15
    /** @var ManagerRegistry */
16
    private $registry;
17
18 6
    public function setRegistry(ManagerRegistry $registry)
19
    {
20 6
        $this->registry = $registry;
21 6
    }
22
23 6
    public function supportsNormalization($data, $format = null)
24
    {
25 6
        return is_object($data) && null !== $this->registry->getManagerForClass(get_class($data));
26
    }
27
28 5
    protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
29
    {
30 5
        $rawValue = parent::getAttributeValue($object, $attribute, $format, $context);
31
32 5
        if (null === $rawValue) {
33 3
            return null;
34
        }
35
36 5
        $metadata = $this->getObjectMetadata($object, $attribute);
37 5
        if (null === $metadata) {
38 5
            return $rawValue;
39
        }
40
41 5
        $assocMetadata = $this->getAssocMetadata($metadata, $attribute);
42
43 5
        if ($metadata->isSingleValuedAssociation($attribute)) {
44 4
            return $this->getAssociationValue($assocMetadata, $rawValue);
45
        }
46
47 5
        $result = [];
48 5
        foreach ($rawValue as $item) {
49 1
            $result[] = $this->getAssociationValue($assocMetadata, $item);
50 5
        }
51
52 5
        return $result;
53
    }
54
55
    protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
56
    {
57
        if (null === $value) {
58
            return parent::setAttributeValue($object, $attribute, $value, $format, $context);
59
        }
60
61
        $rawValue = $value;
62
63
        $metadata = $this->getObjectMetadata($object, $attribute);
64
        if (null === $metadata) {
65
            return $rawValue;
66
        }
67
68
        $assocMetadata = $this->getAssocMetadata($metadata, $attribute);
69
70
        $manager = $this->registry->getManagerForClass($assocMetadata->getName());
71
        if ($metadata->isSingleValuedAssociation($attribute)) {
72
            $value = $this->getObjectByValue($manager, $assocMetadata, $rawValue);
0 ignored issues
show
Bug introduced by
It seems like $manager defined by $this->registry->getMana...socMetadata->getName()) on line 70 can be null; however, ScayTrase\Api\Cruds\Adap...zer::getObjectByValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
73
74
            return parent::setAttributeValue($object, $attribute, $value, $format, $context);
75
        }
76
77
        $objects = [];
78
        foreach ($rawValue as $item) {
79
            $objects[] = $this->getObjectByValue($manager, $assocMetadata, $item);
0 ignored issues
show
Bug introduced by
It seems like $manager defined by $this->registry->getMana...socMetadata->getName()) on line 70 can be null; however, ScayTrase\Api\Cruds\Adap...zer::getObjectByValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
80
        }
81
82
        return parent::setAttributeValue($object, $attribute, new ArrayCollection($objects), $format, $context);
83
    }
84
85
    /**
86
     * @param ObjectManager          $manager
87
     * @param ClassMetadataInterface $assocMetadata
88
     * @param                        $rawValue
89
     *
90
     * @return object
91
     */
92
    protected function getObjectByValue(ObjectManager $manager, ClassMetadataInterface $assocMetadata, $rawValue)
93
    {
94
        if ($manager instanceof EntityManagerInterface) {
95
            return $manager->getReference($assocMetadata->getName(), $rawValue);
96
        }
97
98
        return $manager->find($assocMetadata->getName(), $rawValue);
99
    }
100
101
    /**
102
     * @param $assocMetadata
103
     * @param $rawValue
104
     *
105
     * @return mixed
106
     */
107 4
    private function getAssociationValue(ClassMetadataInterface $assocMetadata, $rawValue)
108
    {
109 4
        $identifier = $assocMetadata->getIdentifierValues($rawValue);
110
111 4
        if (!$assocMetadata instanceof ClassMetadata || $assocMetadata->isIdentifierComposite) {
112
            return $identifier;
113
        }
114
115 4
        return array_shift($identifier);
116
    }
117
118 5
    private function getObjectMetadata($object, $attribute)
119
    {
120 5
        $class = get_class($object);
121
122 5
        $manager = $this->registry->getManagerForClass($class);
123 5
        if (null === $manager) {
124
            return null;
125
        }
126
127 5
        $metadata = $manager->getClassMetadata($class);
128 5
        if (!$metadata->hasAssociation($attribute)) {
129 5
            return null;
130
        }
131
132 5
        return $metadata;
133
    }
134
135 5
    private function getAssocMetadata(ClassMetadataInterface $metadata, $attribute)
136
    {
137 5
        $assoc        = $metadata->getAssociationTargetClass($attribute);
138 5
        $assocManager = $this->registry->getManagerForClass($assoc);
139
140 5
        if (null === $assocManager) {
141
            throw new \LogicException(
142
                $metadata->getName().
143
                '::$'.
144
                $attribute.
145
                ' references non-existent managed entity'
146
            );
147
        }
148
149 5
        return $assocManager->getClassMetadata($assoc);
150
    }
151
}
152