ObtainWood::execute()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 27
rs 8.439
c 1
b 0
f 0
cc 6
eloc 17
nc 4
nop 0
1
<?php
2
3
namespace Rottenwood\KingdomBundle\Command\Game;
4
5
use Doctrine\DBAL\LockMode;
6
use Doctrine\ORM\EntityManager;
7
use Rottenwood\KingdomBundle\Command\Infrastructure\AbstractGameCommand;
8
use Rottenwood\KingdomBundle\Command\Infrastructure\CommandResponse;
9
use Rottenwood\KingdomBundle\Entity\Infrastructure\Item;
10
use Rottenwood\KingdomBundle\Entity\Items\ResourceWood;
11
use Rottenwood\KingdomBundle\Entity\Room;
12
use Rottenwood\KingdomBundle\Entity\RoomResource;
13
use Rottenwood\KingdomBundle\Entity\RoomTypes\Grass;
14
use Rottenwood\KingdomBundle\Service\UserService;
15
16
/**
17
 * Добыча древесины
18
 * Применение в js: Kingdom.Websocket.command('obtainWood')
19
 */
20
class ObtainWood extends AbstractGameCommand
21
{
22
23
    private $quantityToObtain = 1;
24
    private $waitState = 5;
25
26
    /** {@inheritDoc} */
27
    public function execute(): CommandResponse
28
    {
29
        $resourceRepository = $this->container->get('kingdom.room_resource_repository');
30
        $em = $resourceRepository->getEntityManager();
31
        $userService = $this->container->get('kingdom.user_service');
32
        $room = $this->user->getRoom();
33
        $resources = $resourceRepository->findByRoom($room);
34
35
        $result = [];
36
        foreach ($resources as $resource) {
37
            $resourceItem = $resource->getItem();
38
            $resourceQuantity = $resource->getQuantity();
39
40
            if ($resourceItem instanceof ResourceWood && $resourceQuantity > 0) {
41
                $result = $this->obtain($resource, $em, $result, $userService, $resourceItem, $room);
42
            } elseif ($resourceItem instanceof ResourceWood && $resourceQuantity === 0) {
43
                //TODO[Rottenwood]: Отвечать за удаление ресурсов из комнат должен листнер на postflush
44
                $em->remove($resource);
45
            }
46
        }
47
48
        $em->flush();
49
50
        $this->result->setData($result);
51
52
        return $this->result;
53
    }
54
55
    /**
56
     * Добыча ресурсов
57
     * @param RoomResource  $resource
58
     * @param EntityManager $em
59
     * @param array         $result
60
     * @param UserService   $userService
61
     * @param Item          $resourceItem
62
     * @param Room          $room
63
     * @return array
64
     */
65
    public function obtain(
66
        RoomResource $resource,
67
        EntityManager $em,
68
        array $result,
69
        UserService $userService,
70
        Item $resourceItem,
71
        Room $room
72
    ): array
73
    {
74
        if ($this->user->isBusy()) {
75
            $this->result->setWaitstate($this->user->getWaitstate());
76
77
            return [];
78
        }
79
80
        $userService->addWaitstate($this->user, $this->waitState);
81
        $this->reduceQuantity($em, $resource->getId(), $userService);
82
83
        $result['obtained'] = $this->quantityToObtain;
84
85
        $resourceQuantity = $resource->getQuantity();
86
        $result['resources'][$resourceItem->getId()] = $resourceQuantity;
87
88
        if ($resourceQuantity <= 0) {
89
            /** @var Grass[] $grassTypes */
90
            $grassTypes = $em->getRepository(Grass::class)->findAll();
91
            $grassType = $grassTypes[array_rand($grassTypes)];
92
            $room->setType($grassType);
93
            $result['typeChanged'] = true;
94
95
            $em->remove($resource);
96
        }
97
98
        return $result;
99
    }
100
101
    /**
102
     * Транзакция с локированием добываемого ресурса
103
     * @param EntityManager $em
104
     * @param int           $resourceId
105
     * @param UserService   $userService
106
     * @return void
107
     * @throws \Doctrine\DBAL\ConnectionException
108
     * @throws \Exception
109
     */
110
    private function reduceQuantity(EntityManager $em, int $resourceId, UserService $userService)
111
    {
112
        $em->getConnection()->beginTransaction();
113
114
        try {
115
            /** @var RoomResource $resourceToUpdate */
116
            $resourceToUpdate = $em->find(RoomResource::class, $resourceId, LockMode::PESSIMISTIC_READ);
117
            $resourceToUpdate->reduceQuantity($this->quantityToObtain);
118
119
            $userService->takeItems($this->user, $resourceToUpdate->getItem(), $this->quantityToObtain);
120
121
            $em->persist($resourceToUpdate);
122
            $em->flush();
123
            $em->getConnection()->commit();
124
        } catch (\Exception $e) {
125
            $em->getConnection()->rollback();
126
            throw $e;
127
        }
128
    }
129
}
130