Completed
Push — master ( c81e64...88abf3 )
by Joachim
14:04 queued 11:13
created

StockMovementSubscriber::update()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 42
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 42
ccs 0
cts 19
cp 0
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 20
nc 8
nop 1
crap 56
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Loevgaard\DandomainStockBundle\EventListener;
6
7
use Doctrine\Common\EventSubscriber;
8
use Doctrine\ORM\EntityManager;
9
use Doctrine\ORM\Event\OnFlushEventArgs;
10
use Doctrine\ORM\Events;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
use Doctrine\ORM\ORMException;
13
use Doctrine\ORM\UnitOfWork;
14
use Loevgaard\DandomainFoundation\Entity\Generated\OrderLineInterface;
15
use Loevgaard\DandomainStock\Entity\Generated\StockMovementInterface;
16
use Loevgaard\DandomainStock\Entity\StockMovement;
17
use Loevgaard\DandomainStock\Exception\CurrencyMismatchException;
18
use Loevgaard\DandomainStock\Exception\StockMovementProductMismatchException;
19
use Loevgaard\DandomainStock\Exception\UndefinedPriceForCurrencyException;
20
use Loevgaard\DandomainStock\Exception\UnsetCurrencyException;
21
use Loevgaard\DandomainStock\Exception\UnsetProductException;
22
23
class StockMovementSubscriber implements EventSubscriber
24
{
25
    /**
26
     * @var array
27
     */
28
    private $orderStateIds;
29
30
    /**
31
     * @param array $orderStateIds An array of external ids for order states (use the id in the Dandomain interface)
32
     */
33 5
    public function __construct(array $orderStateIds)
34
    {
35 5
        $this->orderStateIds = $orderStateIds;
36 5
    }
37
38 1
    public function getSubscribedEvents()
39
    {
40
        return [
41 1
            Events::onFlush,
42
        ];
43
    }
44
45
    /**
46
     * @param OnFlushEventArgs $args
47
     * @throws CurrencyMismatchException
48
     * @throws ORMException
49
     * @throws StockMovementProductMismatchException
50
     * @throws UndefinedPriceForCurrencyException
51
     * @throws UnsetCurrencyException
52
     * @throws UnsetProductException
53
     */
54
    public function onFlush(OnFlushEventArgs $args)
55
    {
56
        $em = $args->getEntityManager();
57
        $uow = $em->getUnitOfWork();
58
59
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
60
            /** @var OrderLineInterface $entity */
61
            if(!$this->isValidOrderLine($entity)) {
62
                continue;
63
            }
64
65
            $stockMovement = $this->stockMovementFromOrderLine($entity);
66
67
            $this->persistStockMovement($stockMovement, $em, $uow);
68
        }
69
70
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
71
            /** @var OrderLineInterface $entity */
72
            if(!$this->isValidOrderLine($entity)) {
73
                continue;
74
            }
75
76
            $stockMovement = $this->stockMovementFromOrderLine($entity);
77
            $effectiveStockMovement = $entity->computeEffectiveStockMovement();
78
            if ($effectiveStockMovement) {
79
                $stockMovement = $effectiveStockMovement->diff($stockMovement);
80
                $stockMovement->setType(StockMovement::TYPE_REGULATION);
81
            }
82
83
            $this->persistStockMovement($stockMovement, $em, $uow);
84
        }
85
86
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
87
            /** @var OrderLineInterface $entity */
88
            if(!$this->isValidOrderLine($entity)) {
89
                continue;
90
            }
91
92
            $effectiveStockMovement = $entity->computeEffectiveStockMovement();
93
94
            if ($effectiveStockMovement) {
95
                $stockMovement = $effectiveStockMovement->inverse();
96
                $stockMovement
97
                    ->setType(StockMovement::TYPE_REGULATION) // we set the type as regulation since it is not a sale now
98
                    ->setOrderLineRemoved(true)
99
                    ->setOrderLine(null);
100
101
                $this->persistStockMovement($stockMovement, $em, $uow);
102
            }
103
104
            foreach ($entity->getStockMovements() as $stockMovement) {
105
                $stockMovement
106
                    ->setOrderLineRemoved(true)
107
                    ->setOrderLine(null);
108
109
                $md = $this->metaData($em, $stockMovement);
110
                $uow->recomputeSingleEntityChangeSet($md, $stockMovement);
111
            }
112
        }
113
    }
114
115
    private function isValidOrderLine($entity) : bool
116
    {
117
        return $entity instanceof OrderLineInterface
0 ignored issues
show
Bug introduced by
The class Loevgaard\DandomainFound...ated\OrderLineInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
118
            && $entity->getOrder()
119
            && $entity->getOrder()->getState()
120
            && in_array($entity->getOrder()->getState()->getExternalId(), $this->orderStateIds);
121
    }
122
123
    /**
124
     * @param OrderLineInterface $orderLine
125
     * @return StockMovement
126
     * @throws CurrencyMismatchException
127
     * @throws UndefinedPriceForCurrencyException
128
     * @throws UnsetProductException
129
     */
130
    private function stockMovementFromOrderLine(OrderLineInterface $orderLine) : StockMovement
131
    {
132
        $stockMovement = new StockMovement();
133
        $stockMovement->populateFromOrderLine($orderLine);
134
135
        return $stockMovement;
136
    }
137
138
    private function metaData(EntityManager $entityManager, $entity) : ClassMetadata
139
    {
140
        return $entityManager->getClassMetadata(get_class($entity));
141
    }
142
143
    /**
144
     * @param StockMovementInterface $stockMovement
145
     * @param EntityManager $entityManager
146
     * @param UnitOfWork $unitOfWork
147
     * @return boolean
148
     * @throws ORMException
149
     */
150
    private function persistStockMovement(StockMovementInterface $stockMovement, EntityManager $entityManager, UnitOfWork $unitOfWork) : bool
151
    {
152
        // if the quantity is 0 we don't want to add a stock movement since this will just pollute the stock movement table
153
        if($stockMovement->getQuantity() === 0) {
154
            return false;
155
        }
156
157
        $stockMovement->validate();
158
        $entityManager->persist($stockMovement);
159
        $md = $this->metaData($entityManager, $stockMovement);
160
        $unitOfWork->computeChangeSet($md, $stockMovement);
161
162
        return true;
163
    }
164
}
165