CascadeDeleteService::deleteAssociations()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 78
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 44
c 3
b 0
f 0
dl 0
loc 78
rs 8.5937
cc 6
nc 4
nop 5

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 CascadeDeleteService extends AbstractCascadeService
18
{
19
    /**
20
     * @param EntityManagerInterface $entityManager
21
     * @param string                 $entityName
22
     * @param EntityInterface        $entity
23
     * @param array<mixed>           $deleteOptions
24
     * @param array<mixed>           $deleteCollectionOptions
25
     *
26
     * @throws EntityRepositoryException
27
     * @throws PersistenceException
28
     */
29
    public function deleteAssociations(
30
        EntityManagerInterface $entityManager,
31
        string $entityName,
32
        EntityInterface $entity,
33
        array $deleteOptions = [],
34
        array $deleteCollectionOptions = []
35
    ): void {
36
        $deleteOptions = array_replace_recursive($this->options, $deleteOptions);
37
        $deleteCollectionOptions = array_replace_recursive($this->collectionOptions, $deleteCollectionOptions);
38
39
        /** @var ClassMetadata<EntityInterface> $classMetadata */
40
        $classMetadata = $this->getClassMetadata($entityManager, $entityName);
41
42
        /** @var array<string, mixed> $mappings */
43
        $mappings = $classMetadata->getAssociationMappings();
44
45
        $this->logger->info(
46
            sprintf('Processing cascade delete operations for for entity class \'%s\'', $entityName)
47
        );
48
49
        foreach ($mappings as $mapping) {
50
            if (
51
                !isset(
52
                    $mapping['targetEntity'],
53
                    $mapping['fieldName'],
54
                    $mapping['type'],
55
                    $mapping['isCascadeRemove']
56
                )
57
                || true !== $mapping['isCascadeRemove']
58
            ) {
59
                // We only want to save associations that are configured to cascade delete/remove
60
                continue;
61
            }
62
63
            $this->logger->info(
64
                sprintf(
65
                    'The entity field \'%s::%s\' is configured for cascade delete operations for target entity \'%s\'',
66
                    $entityName,
67
                    $mapping['fieldName'],
68
                    $mapping['targetEntity']
69
                )
70
            );
71
72
            /** @var ClassMetadata<EntityInterface> $targetMetadata */
73
            $targetMetadata = $this->getClassMetadata($entityManager, $mapping['targetEntity']);
74
75
            $targetEntityOrCollection = $this->resolveTargetEntityOrCollection(
76
                $entity,
77
                $mapping['fieldName'],
78
                $classMetadata,
79
                $targetMetadata
80
            );
81
82
            if (!$this->isValidAssociation($targetEntityOrCollection, $mapping)) {
83
                $errorMessage = sprintf(
84
                    'The entity field \'%s::%s\' value could not be resolved',
85
                    $entityName,
86
                    $mapping['fieldName']
87
                );
88
89
                $this->logger->error($errorMessage);
90
91
                throw new PersistenceException($errorMessage);
92
            }
93
94
            $this->logger->info(
95
                sprintf(
96
                    'Performing cascading delete operations for field \'%s::%s\'',
97
                    $entityName,
98
                    $mapping['fieldName']
99
                )
100
            );
101
102
            $this->deleteAssociation(
103
                $entityManager,
104
                $mapping['targetEntity'],
105
                $targetEntityOrCollection,
106
                (is_iterable($targetEntityOrCollection) ? $deleteCollectionOptions : $deleteOptions)
107
            );
108
        }
109
    }
110
111
    /**
112
     * @param EntityManagerInterface                          $entityManager
113
     * @param class-string                                    $targetEntityName
114
     * @param EntityInterface|iterable<EntityInterface>|mixed $entityOrCollection
115
     * @param array<mixed>                                    $options
116
     *
117
     * @throws PersistenceException
118
     * @throws EntityRepositoryException
119
     */
120
    public function deleteAssociation(
121
        EntityManagerInterface $entityManager,
122
        string $targetEntityName,
123
        $entityOrCollection,
124
        array $options = []
125
    ): void {
126
        $targetRepository = $this->getTargetRepository($entityManager, $targetEntityName);
127
128
        if (is_iterable($entityOrCollection)) {
129
            $targetRepository->deleteCollection($entityOrCollection, $options);
130
        } elseif ($entityOrCollection instanceof EntityInterface) {
131
            $targetRepository->delete($entityOrCollection, $options);
132
        } else {
133
            $errorMessage = sprintf(
134
                'Unable to cascade save target entity \'%s\': The entity or collection is of an invalid type \'%s\'',
135
                $targetEntityName,
136
                (is_object($entityOrCollection) ? get_class($entityOrCollection) : gettype($entityOrCollection))
137
            );
138
139
            $this->logger->error($errorMessage);
140
141
            throw new PersistenceException($errorMessage);
142
        }
143
    }
144
}
145