EntityHydrator::completeRequired()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Knp\FriendlyContexts\Doctrine;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\Persistence\ObjectManager;
7
use Doctrine\DBAL\Types\Type as DBALType;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Knp\FriendlyContexts\Guesser\GuesserManager;
10
use Knp\FriendlyContexts\Utils\TextFormater;
11
use Knp\FriendlyContexts\Utils\UniqueCache;
12
use Symfony\Component\PropertyAccess\PropertyAccess;
13
14
class EntityHydrator
15
{
16
    public function __construct(TextFormater $formater, GuesserManager $guesserManager, EntityResolver $resolver, UniqueCache $cache)
17
    {
18
        $this->formater       = $formater;
0 ignored issues
show
Bug Best Practice introduced by
The property formater does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
19
        $this->guesserManager = $guesserManager;
0 ignored issues
show
Bug Best Practice introduced by
The property guesserManager does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
20
        $this->resolver       = $resolver;
0 ignored issues
show
Bug Best Practice introduced by
The property resolver does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
21
        $this->cache          = $cache;
0 ignored issues
show
Bug Best Practice introduced by
The property cache does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
22
    }
23
24
    public function hydrate(ObjectManager $em, $entity, $values)
25
    {
26
        foreach ($values as $property => $value) {
27
            if (false !== $mapping = $this->resolver->getMetadataFromProperty($em, $entity, $property)) {
28
                $this->formatFromMapping($mapping, $property, $value);
29
            }
30
31
            try {
32
                PropertyAccess::createPropertyAccessor()
33
                    ->setValue(
34
                        $entity,
35
                        $this->formater->toCamelCase($property),
36
                        $value
37
                    )
38
                ;
39
            } catch (\Exception $e) {
40
                if (!($value instanceof ArrayCollection)) {
41
                    throw $e;
42
                }
43
44
                PropertyAccess::createPropertyAccessor()
45
                    ->setValue(
46
                        $entity,
47
                        $this->formater->toCamelCase($property),
48
                        $value->toArray()
49
                    )
50
                ;
51
            }
52
        }
53
54
        return $this;
55
    }
56
57
    public function completeRequired(ObjectManager $em, $entity)
58
    {
59
        $this->completeFields($em, $entity);
60
    }
61
62
    public function completeFields(ObjectManager $em, $entity)
63
    {
64
        $accessor = PropertyAccess::createPropertyAccessor();
65
66
        $metadata = $this->resolver->getMetadataFromObject($em, $entity);
67
68
        foreach ($metadata->getColumnNames() as $columnName) {
69
            $property = $metadata->getFieldName($columnName);
0 ignored issues
show
Bug introduced by
The method getFieldName() does not exist on Doctrine\Common\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

69
            /** @scrutinizer ignore-call */ 
70
            $property = $metadata->getFieldName($columnName);

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...
70
            if (false === $metadata->isNullable($property)) {
71
                try {
72
                    if (null === $accessor->getValue($entity, $property)) {
73
                        $accessor->setValue(
74
                            $entity,
75
                            $property,
76
                            $this->complete($metadata->getFieldMapping($property), $metadata->getName())
77
                        );
78
                    }
79
                } catch (\Exception $ex) {
80
                    unset($ex);
81
                }
82
            }
83
        }
84
85
        return $this;
86
    }
87
88
    protected function complete($mapping, $className)
89
    {
90
        if (false === $guesser = $this->guesserManager->find($mapping)) {
91
            throw new \Exception(sprintf('There is no fake solution for "%s" typed fields', $mapping['type']));
92
        }
93
94
        if (isset($mapping['unique']) && true === $mapping['unique']) {
95
            return $this->cache->generate($className, $mapping['fieldName'], function () use ($guesser, $mapping) {
96
                return $guesser->fake($mapping);
97
            });
98
        }
99
100
        return $guesser->fake($mapping);
101
    }
102
103
    protected function format($mapping, $value)
104
    {
105
        if (false === $guesser = $this->guesserManager->find($mapping)) {
106
107
            return $value;
108
        }
109
110
        return $guesser->transform($value, $mapping);
111
    }
112
113
    protected function formatFromMapping($mapping, &$property, &$value)
114
    {
115
        $property = $mapping['fieldName'];
116
        $collectionRelation = in_array($mapping['type'], [ClassMetadata::ONE_TO_MANY, ClassMetadata::MANY_TO_MANY]);
117
        $arrayRelation = in_array($mapping['type'], [DBALType::TARRAY, DBALType::SIMPLE_ARRAY, DBALType::JSON_ARRAY]);
118
119
        if ($collectionRelation || $arrayRelation) {
120
            $result = array_map(
121
                function ($e) use ($mapping) {
122
                    return $this->format($mapping, $e);
123
                },
124
                    $this->formater->listToArray($value)
125
                );
126
127
            $value = $collectionRelation ? new ArrayCollection($result) : $result;
128
        } else {
129
            $value = $this->format($mapping, $value);
130
        }
131
    }
132
}
133