CascadeSaveService   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 10
eloc 56
c 2
b 0
f 0
dl 0
loc 121
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
B saveAssociations() 0 76 6
A saveAssociation() 0 20 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\DoctrineEntityRepository\Persistence;
6
7
use Arp\DoctrineEntityRepository\Exception\EntityRepositoryException;
8
use Arp\DoctrineEntityRepository\Persistence\Exception\PersistenceException;
9
use Arp\Entity\EntityInterface;
10
use Doctrine\ORM\EntityManagerInterface;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
13
/**
14
 * @author  Alex Patterson <[email protected]>
15
 * @package Arp\DoctrineEntityRepository\Persistence
16
 */
17
class CascadeSaveService extends AbstractCascadeService
18
{
19
    /**
20
     * @param EntityManagerInterface $entityManager
21
     * @param string                 $entityName
22
     * @param EntityInterface        $entity
23
     * @param array<mixed>           $options
24
     * @param array<mixed>           $collectionOptions
25
     *
26
     * @throws PersistenceException
27
     * @throws EntityRepositoryException
28
     */
29
    public function saveAssociations(
30
        EntityManagerInterface $entityManager,
31
        string $entityName,
32
        EntityInterface $entity,
33
        array $options = [],
34
        array $collectionOptions = []
35
    ): void {
36
        $options = array_replace_recursive($this->options, $options);
37
        $collectionOptions = array_replace_recursive($this->collectionOptions, $collectionOptions);
38
39
        /** @var ClassMetadata<EntityInterface> $classMetadata */
40
        $classMetadata = $this->getClassMetadata($entityManager, $entityName);
41
        $mappings = $classMetadata->getAssociationMappings();
42
43
        $this->logger->info(
44
            sprintf('Processing cascade save operations for for entity class \'%s\'', $entityName)
45
        );
46
47
        foreach ($mappings as $mapping) {
48
            if (
49
                !isset(
50
                    $mapping['targetEntity'],
51
                    $mapping['fieldName'],
52
                    $mapping['type'],
53
                    $mapping['isCascadePersist']
54
                )
55
                || true !== $mapping['isCascadePersist']
56
            ) {
57
                // We only want to save associations that are configured to cascade persist
58
                continue;
59
            }
60
61
            $this->logger->info(
62
                sprintf(
63
                    'The entity field \'%s::%s\' is configured for cascade operations for target entity \'%s\'',
64
                    $entityName,
65
                    $mapping['fieldName'],
66
                    $mapping['targetEntity']
67
                )
68
            );
69
70
            /** @var ClassMetadata<EntityInterface> $targetMetadata */
71
            $targetMetadata = $this->getClassMetadata($entityManager, $mapping['targetEntity']);
72
73
            $targetEntityOrCollection = $this->resolveTargetEntityOrCollection(
74
                $entity,
75
                $mapping['fieldName'],
76
                $classMetadata,
77
                $targetMetadata
78
            );
79
80
            if (!$this->isValidAssociation($targetEntityOrCollection, $mapping)) {
0 ignored issues
show
Bug introduced by
It seems like $targetEntityOrCollection can also be of type Arp\Entity\EntityInterface; however, parameter $entityOrCollection of Arp\DoctrineEntityReposi...e::isValidAssociation() does only seem to accept iterable, 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

80
            if (!$this->isValidAssociation(/** @scrutinizer ignore-type */ $targetEntityOrCollection, $mapping)) {
Loading history...
81
                $errorMessage = sprintf(
82
                    'The entity field \'%s::%s\' value could not be resolved',
83
                    $entityName,
84
                    $mapping['fieldName']
85
                );
86
87
                $this->logger->error($errorMessage);
88
89
                throw new PersistenceException($errorMessage);
90
            }
91
92
            $this->logger->info(
93
                sprintf(
94
                    'Performing cascading save operations for field \'%s::%s\'',
95
                    $entityName,
96
                    $mapping['fieldName']
97
                )
98
            );
99
100
            $this->saveAssociation(
101
                $entityManager,
102
                $mapping['targetEntity'],
103
                $targetEntityOrCollection,
104
                (is_iterable($targetEntityOrCollection) ? $collectionOptions : $options)
105
            );
106
        }
107
    }
108
109
    /**
110
     * @param EntityManagerInterface                          $entityManager
111
     * @param class-string                                    $entityName
112
     * @param EntityInterface|iterable<EntityInterface>|mixed $entityOrCollection
113
     * @param array<mixed>                                    $options
114
     *
115
     * @throws PersistenceException
116
     * @throws EntityRepositoryException
117
     */
118
    public function saveAssociation(
119
        EntityManagerInterface $entityManager,
120
        string $entityName,
121
        $entityOrCollection,
122
        array $options = []
123
    ): void {
124
        if ($entityOrCollection instanceof EntityInterface) {
125
            $this->getTargetRepository($entityManager, $entityName)->save($entityOrCollection, $options);
126
        } elseif (is_iterable($entityOrCollection)) {
127
            $this->getTargetRepository($entityManager, $entityName)->saveCollection($entityOrCollection, $options);
128
        } else {
129
            $errorMessage = sprintf(
130
                'Unable to cascade save target entity \'%s\': The entity or collection is of an invalid type \'%s\'',
131
                $entityName,
132
                (is_object($entityOrCollection) ? get_class($entityOrCollection) : gettype($entityOrCollection))
133
            );
134
135
            $this->logger->error($errorMessage);
136
137
            throw new PersistenceException($errorMessage);
138
        }
139
    }
140
}
141