Completed
Push — master ( fa0d52...fef7a6 )
by Arne
01:59
created

ArchivR::waitForLock()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 2
1
<?php
2
3
namespace Archivr;
4
5
use Archivr\Exception\ConfigurationException;
6
use Archivr\SynchronizationProgressListener\SynchronizationProgressListenerInterface;
7
8
class ArchivR
9
{
10
    /**
11
     * @var Configuration
12
     */
13
    protected $configuration;
14
15
    /**
16
     * @var Vault[]
17
     */
18
    protected $vaults = [];
19
20
    public function __construct(Configuration $configuration)
21
    {
22
        $this->configuration = $configuration;
23
    }
24
25
    public function getConfiguration(): Configuration
26
    {
27
        return $this->configuration;
28
    }
29
30
    public function buildOperationList(): OperationList
31
    {
32
        $return = new OperationList();
33
34
        foreach ($this->getVaults() as $vault)
35
        {
36
            $return->append($vault->getOperationList());
37
        }
38
39
        return $return;
40
    }
41
42
    /**
43
     * @return Vault[]
44
     */
45
    public function getVaults(): array
46
    {
47
        return array_map(function(VaultConfiguration $vaultConfiguration) {
48
49
            return $this->getVault($vaultConfiguration->getTitle());
50
51
        }, $this->configuration->getVaultConfigurations());
52
    }
53
54
    public function getVault(string $vaultTitle): Vault
55
    {
56
        if (!isset($this->vaults[$vaultTitle]))
57
        {
58
            $vaultConfiguration = $this->getConfiguration()->getVaultConfigurationByTitle($vaultTitle);
59
60
            $this->vaults[$vaultTitle] = new Vault($this->configuration, $vaultConfiguration);
61
        }
62
63
        return $this->vaults[$vaultTitle];
64
    }
65
66
    public function synchronize(array $vaultTitles = [], bool $preferLocal = false, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
67
    {
68
        $lastRevision = 0;
69
70
        // fallback to all vaults
71
        $vaultTitles = $vaultTitles ?: array_map(function(Vault $vault) { return $vault->getVaultConfiguration()->getTitle(); }, $this->getVaults());
72
73
        // acquire all locks and retrieve highest existing revision
74
        foreach ($this->getVaults() as $vault)
75
        {
76
            // lock is only required for vaults that we want to synchronize with
77
            if (in_array($vault->getVaultConfiguration()->getTitle(), $vaultTitles))
78
            {
79
                $vault->getLockAdapter()->acquireLock(Vault::LOCK_SYNC);
80
            }
81
82
            // highest revision should be build across all vaults
83
            $synchronizationList = $vault->loadSynchronizationList();
84
            if ($synchronizationList->getLastSynchronization())
85
            {
86
                $lastRevision = max($lastRevision, $synchronizationList->getLastSynchronization()->getRevision());
87
            }
88
        }
89
90
        // new revision is one plus the highest existing revision across all vaults
91
        $newRevision = $lastRevision + 1;
92
93
        // actual synchronization
94
        $return = new OperationResultList();
95
        foreach ($vaultTitles as $vaultTitle)
96
        {
97
            $return->append($this->getVault($vaultTitle)->synchronize($newRevision, $preferLocal, $progressListener));
98
        }
99
100
        // release lock at the last moment to further reduce change of deadlocks
101
        foreach ($vaultTitles as $vaultTitle)
102
        {
103
            $this->getVault($vaultTitle)->getLockAdapter()->releaseLock(Vault::LOCK_SYNC);
104
        }
105
106
        return $return;
107
    }
108
109
    /**
110
     * @return Synchronization[][]
111
     */
112
    public function buildSynchronizationHistory(): array
113
    {
114
        $return = [];
115
116
        foreach ($this->getVaults() as $vault)
117
        {
118
            $vaultConfig = $vault->getVaultConfiguration();
119
            $list = $vault->loadSynchronizationList();
120
121
            foreach ($list as $synchronization)
122
            {
123
                /** @var Synchronization $synchronization */
124
125
                $return[$synchronization->getRevision()][$vaultConfig->getTitle()] = $synchronization;
126
            }
127
        }
128
129
        ksort($return);
130
131
        return $return;
132
    }
133
134 View Code Duplication
    public function restore(int $toRevision = null, string $fromVault = null, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
    {
136
        $vault = $fromVault ? $this->getVault($fromVault) : $this->getAnyVault();
137
        $lockAdapter = $vault->getLockAdapter();
138
139
        $lockAdapter->acquireLock(Vault::LOCK_SYNC);
140
141
        $operationResultList = $vault->restore($toRevision, $progressListener);
142
143
        $lockAdapter->releaseLock(Vault::LOCK_SYNC);
144
145
        return $operationResultList;
146
    }
147
148 View Code Duplication
    public function dump(string $targetPath, int $revision = null, string $fromVault = null, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
    {
150
        $vault = $fromVault ? $this->getVault($fromVault) : $this->getAnyVault();
151
        $lockAdapter = $vault->getLockAdapter();
152
153
        $lockAdapter->acquireLock(Vault::LOCK_SYNC);
154
155
        $operationResultList = $vault->dump($targetPath, $revision, $progressListener);
156
157
        $lockAdapter->releaseLock(Vault::LOCK_SYNC);
158
159
        return $operationResultList;
160
    }
161
162
    protected function getAnyVault(): Vault
163
    {
164
        $vaults = array_values($this->getVaults());
165
166
        if (empty($vaults))
167
        {
168
            throw new ConfigurationException('No vaults defined.');
169
        }
170
171
        return $vaults[0];
172
    }
173
}
174