Completed
Push — master ( c5a3b4...fa0d52 )
by Arne
01:49
created

ArchivR::getStorageDriverFactory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Archivr;
4
5
use Archivr\StorageDriver\StorageDriverFactory;
6
use Archivr\Exception\ConfigurationException;
7
use Archivr\LockAdapter\LockAdapterFactory;
8
use Archivr\SynchronizationProgressListener\SynchronizationProgressListenerInterface;
9
10
class ArchivR
11
{
12
    /**
13
     * @var Configuration
14
     */
15
    protected $configuration;
16
17
    /**
18
     * @var StorageDriverFactory
19
     */
20
    protected $storageDriverFactory;
21
22
    /**
23
     * @var LockAdapterFactory
24
     */
25
    protected $lockAdapterFactory;
26
27
    /**
28
     * @var Vault[]
29
     */
30
    protected $vaults = [];
31
32
    public function __construct(Configuration $configuration)
33
    {
34
        $this->configuration = $configuration;
35
    }
36
37
    public function getConfiguration(): Configuration
38
    {
39
        return $this->configuration;
40
    }
41
42
    public function getStorageDriverFactory(): StorageDriverFactory
43
    {
44
        if ($this->storageDriverFactory === null)
45
        {
46
            $this->setStorageDriverFactory(new StorageDriverFactory());
47
        }
48
49
        return $this->storageDriverFactory;
50
    }
51
52
    public function setStorageDriverFactory(StorageDriverFactory $storageDriverFactory)
53
    {
54
        $this->storageDriverFactory = $storageDriverFactory;
55
    }
56
57
    public function getLockAdapterFactory(): LockAdapterFactory
58
    {
59
        if ($this->lockAdapterFactory === null)
60
        {
61
            $this->setLockAdapterFactory(new LockAdapterFactory());
62
        }
63
64
        return $this->lockAdapterFactory;
65
    }
66
67
    public function setLockAdapterFactory(LockAdapterFactory $lockAdapterFactory)
68
    {
69
        $this->lockAdapterFactory = $lockAdapterFactory;
70
    }
71
72
    public function buildOperationList(): OperationList
73
    {
74
        $return = new OperationList();
75
76
        foreach ($this->getVaults() as $vault)
77
        {
78
            $return->append($vault->getOperationList());
79
        }
80
81
        return $return;
82
    }
83
84
    /**
85
     * @return Vault[]
86
     */
87
    public function getVaults(): array
88
    {
89
        return array_map(function(VaultConfiguration $vaultConfiguration) {
90
91
            return $this->getVault($vaultConfiguration->getTitle());
92
93
        }, $this->configuration->getVaultConfigurations());
94
    }
95
96
    public function getVault(string $vaultTitle): Vault
97
    {
98
        if (!isset($this->vaults[$vaultTitle]))
99
        {
100
            $vaultConfiguration = $this->getConfiguration()->getVaultConfigurationByTitle($vaultTitle);
101
102
            $storageDriver = $this->getStorageDriverFactory()->create($vaultConfiguration->getVaultAdapter(), $vaultConfiguration);
103
            $lockAdapter = $this->getLockAdapterFactory()->create($vaultConfiguration->getLockAdapter(), $vaultConfiguration, $storageDriver);
104
105
            $vault = new Vault($vaultTitle, $this->configuration->getLocalPath(), $storageDriver);
106
            $vault->setLockAdapter($lockAdapter);
107
            $vault->setExclusions($this->configuration->getExclusions());
108
            $vault->setIdentity($this->configuration->getIdentity());
109
110
            $this->vaults[$vaultTitle] = $vault;
111
        }
112
113
        return $this->vaults[$vaultTitle];
114
    }
115
116
    public function synchronize(array $vaultTitles = [], bool $preferLocal = false, SynchronizationProgressListenerInterface $progressListener = null): OperationResultList
117
    {
118
        $lastRevision = 0;
119
120
        // fallback to all vaults
121
        $vaultTitles = $vaultTitles ?: array_map(function(Vault $vault) { return $vault->getTitle(); }, $this->getVaults());
122
123
        // acquire all locks and retrieve highest existing revision
124
        foreach ($this->getVaults() as $vault)
125
        {
126
            // lock is only required for vaults that we want to synchronize with
127
            if (in_array($vault->getTitle(), $vaultTitles))
128
            {
129
                $this->waitForLock($vault, Vault::LOCK_SYNC);
130
            }
131
132
            // highest revision should be build across all vaults
133
            $synchronizationList = $vault->loadSynchronizationList();
134
            if ($synchronizationList->getLastSynchronization())
135
            {
136
                $lastRevision = max($lastRevision, $synchronizationList->getLastSynchronization()->getRevision());
137
            }
138
        }
139
140
        // new revision is one plus the highest existing revision across all vaults
141
        $newRevision = $lastRevision + 1;
142
143
        // actual synchronization
144
        $return = new OperationResultList();
145
        foreach ($vaultTitles as $vaultTitle)
146
        {
147
            $return->append($this->getVault($vaultTitle)->synchronize($newRevision, $preferLocal, $progressListener));
148
        }
149
150
        // release lock at the last moment to further reduce change of deadlocks
151
        foreach ($vaultTitles as $vaultTitle)
152
        {
153
            $this->getVault($vaultTitle)->getLockAdapter()->releaseLock(Vault::LOCK_SYNC);
154
        }
155
156
        return $return;
157
    }
158
159
    /**
160
     * @return Synchronization[][]
161
     */
162
    public function buildSynchronizationHistory(): array
163
    {
164
        $return = [];
165
166
        foreach ($this->getVaults() as $vault)
167
        {
168
            $list = $vault->loadSynchronizationList();
169
170
            foreach ($list as $synchronization)
171
            {
172
                /** @var Synchronization $synchronization */
173
174
                $return[$synchronization->getRevision()][$vault->getTitle()] = $synchronization;
175
            }
176
        }
177
178
        ksort($return);
179
180
        return $return;
181
    }
182
183 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...
184
    {
185
        $vault = $fromVault ? $this->getVault($fromVault) : $this->getAnyVault();
186
187
        $this->waitForLock($vault, Vault::LOCK_SYNC);
188
189
        $operationResultList = $vault->restore($toRevision, $progressListener);
190
191
        $vault->getLockAdapter()->releaseLock(Vault::LOCK_SYNC);
192
193
        return $operationResultList;
194
    }
195
196 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...
197
    {
198
        $vault = $fromVault ? $this->getVault($fromVault) : $this->getAnyVault();
199
200
        $this->waitForLock($vault, Vault::LOCK_SYNC);
201
202
        $operationResultList = $vault->dump($targetPath, $revision, $progressListener);
203
204
        $vault->getLockAdapter()->releaseLock(Vault::LOCK_SYNC);
205
206
        return $operationResultList;
207
    }
208
209
    protected function getAnyVault(): Vault
210
    {
211
        $vaults = array_values($this->getVaults());
212
213
        if (empty($vaults))
214
        {
215
            throw new ConfigurationException('No vaults defined.');
216
        }
217
218
        return $vaults[0];
219
    }
220
221
    protected function waitForLock(Vault $vault, string $name)
222
    {
223
        while (!$vault->getLockAdapter()->acquireLock($name))
224
        {
225
            sleep(5);
226
        }
227
    }
228
}
229