Completed
Push — master ( fde887...02d242 )
by Petr
03:30
created

ObtainWood::setWaitstate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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