Completed
Push — master ( 65b5b4...2290e5 )
by Arne
05:25
created

Storeman::buildSynchronizationHistory()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Storeman::releaseLocks() 0 10 3
1
<?php
2
3
namespace Storeman;
4
5
use Storeman\Config\Configuration;
6
use Storeman\SynchronizationProgressListener\SynchronizationProgressListenerInterface;
7
8
/**
9
 * This class coordinates executions with multiple vaults involved.
10
 */
11
class Storeman
12
{
13
    /**
14
     * @var Container
15
     */
16
    protected $container;
17
18
    public function __construct(Container $container = null)
19
    {
20
        $this->container = $container ?: new Container();
21
        $this->container->injectStoreman($this);
22
    }
23
24
    /**
25
     * Returns the DI container of this storeman instance.
26
     * Some service names resolve to different implementations depending on the current vault which can be set as a context.
27
     * E.g. "storageAdapter" resolves to the storage adapter implementation configured for the current vault.
28
     *
29
     * @param Vault $vault
30
     * @return Container
31
     */
32
    public function getContainer(Vault $vault = null): Container
33
    {
34
        return $this->container->selectVault($vault);
35
    }
36
37
    /**
38
     * Returns the configuration.
39
     *
40
     * @return Configuration
41
     */
42
    public function getConfiguration(): Configuration
43
    {
44
        return $this->container->get('configuration');
45
    }
46
47
    /**
48
     * Returns a container of the configured vaults.
49
     *
50
     * @return VaultContainer
51
     */
52
    public function getVaultContainer(): VaultContainer
53
    {
54
        return $this->container->getVaultContainer();
55
    }
56
57
    public function synchronize(array $vaultTitles = null, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
58
    {
59
        /** @var Vault[] $vaults */
60
        $vaults = ($vaultTitles === null) ? $this->getVaultContainer() : $this->getVaultContainer()->getVaultsByTitles($vaultTitles);
61
62
        $this->acquireLocks($vaults, Vault::LOCK_SYNC);
0 ignored issues
show
Documentation introduced by
$vaults is of type array<integer,object<Storeman\Vault>>, but the function expects a object<Traversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
63
64
        $newRevision = ($this->getLastRevision() ?: 0) + 1;
65
66
        $return = new OperationResultList();
67
        foreach ($vaults as $vault)
68
        {
69
            $return->append($vault->synchronize($newRevision, $progressListener));
70
        }
71
72
        $this->releaseLocks($vaults, Vault::LOCK_SYNC);
0 ignored issues
show
Documentation introduced by
$vaults is of type array<integer,object<Storeman\Vault>>, but the function expects a object<Traversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
73
74
        return $return;
75
    }
76
77
    public function restore(int $toRevision = null, string $fromVault = null, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
78
    {
79
        $vault = $this->getVaultForDownload($toRevision, $fromVault);
80
81
        if ($vault === null)
82
        {
83
            return new OperationResultList();
84
        }
85
86
        $operationResultList = $vault->restore($toRevision, $progressListener);
87
88
        return $operationResultList;
89
    }
90
91
    public function dump(string $targetPath, int $revision = null, string $fromVault = null, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
92
    {
93
        $vault = $this->getVaultForDownload($revision, $fromVault);
94
95
        if ($vault === null)
96
        {
97
            return new OperationResultList();
98
        }
99
100
        $operationResultList = $vault->dump($targetPath, $revision, $progressListener);
101
102
        return $operationResultList;
103
    }
104
105
    /**
106
     * Returns the highest revision number across all vaults.
107
     *
108
     * @return int
109
     */
110
    public function getLastRevision(): ?int
111
    {
112
        $max = 0;
113
114
        foreach ($this->getVaultContainer() as $vault)
115
        {
116
            /** @var Vault $vault */
117
118
            if ($lastSynchronization = $vault->getVaultLayout()->getLastSynchronization())
119
            {
120
                $max = max($max, $lastSynchronization->getRevision());
121
            }
122
        }
123
124
        return $max ?: null;
125
    }
126
127
    /**
128
     * @param Vault[] $vaults
129
     * @param string $lockName
130
     */
131
    protected function acquireLocks(\Traversable $vaults, string $lockName)
132
    {
133
        foreach ($vaults as $vault)
134
        {
135
            if (!$vault->getLockAdapter()->acquireLock($lockName))
136
            {
137
                throw new Exception("Failed to acquire lock for vault {$vault->getVaultConfiguration()->getTitle()}");
138
            }
139
        }
140
    }
141
142
    /**
143
     * @param Vault[] $vaults
144
     * @param string $lockName
145
     */
146
    protected function releaseLocks(\Traversable $vaults, string $lockName)
147
    {
148
        foreach ($vaults as $vault)
149
        {
150
            if (!$vault->getLockAdapter()->releaseLock($lockName))
151
            {
152
                throw new Exception("Failed to release lock for vault {$vault->getVaultConfiguration()->getTitle()}");
153
            }
154
        }
155
    }
156
157
    protected function getVaultForDownload(?int $revision, ?string $vaultTitle): ?Vault
158
    {
159
        $revision = $revision ?: $this->getLastRevision();
160
        if ($revision === null)
161
        {
162
            return null;
163
        }
164
165
        $vaultContainer = $this->getVaultContainer();
166
167
        if ($vaultTitle)
168
        {
169
            $vault = $vaultContainer->getVaultByTitle($vaultTitle);
170
        }
171
        else
172
        {
173
            $vaults = $vaultContainer->getVaultsHavingRevision($revision);
174
            $vault = $vaultContainer->getPrioritizedVault($vaults);
175
        }
176
177
        if ($vault === null)
178
        {
179
            throw new Exception("Cannot find requested revision #{$revision} in any configured vault.");
180
        }
181
182
        return $vault;
183
    }
184
}
185