Completed
Push — master ( cb7793...7b1e0a )
by Arne
01:36
created

ArchivR::getConnectionAdapterFactoryContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Archivr;
4
5
use Archivr\ConnectionAdapter\ConnectionAdapterFactoryContainer;
6
use Archivr\ConnectionAdapter\ConnectionAdapterInterface;
7
use Archivr\ConnectionAdapter\FlysystemConnectionAdapter;
8
use Archivr\Exception\ConfigurationException;
9
use Archivr\Exception\Exception;
10
use Archivr\LockAdapter\ConnectionBasedLockAdapter;
11
use Archivr\LockAdapter\LockAdapterFactoryContainer;
12
use Archivr\LockAdapter\LockAdapterInterface;
13
use League\Flysystem\Adapter\Local;
14
use League\Flysystem\Filesystem;
15
16
class ArchivR
17
{
18
    use TildeExpansionTrait;
19
20
    /**
21
     * @var Configuration
22
     */
23
    protected $configuration;
24
25
    /**
26
     * @var ConnectionAdapterFactoryContainer
27
     */
28
    protected $connectionAdapterFactoryContainer;
29
30
    /**
31
     * @var LockAdapterFactoryContainer
32
     */
33
    protected $lockAdapterFactoryContainer;
34
35
    /**
36
     * @var Vault[]
37
     */
38
    protected $vaults = [];
39
40
    public function __construct(Configuration $configuration)
41
    {
42
        $this->configuration = $configuration;
43
        $this->connectionAdapterFactoryContainer = new ConnectionAdapterFactoryContainer([
44
45
            'path' => function(ConnectionConfiguration $connectionConfiguration)
46
            {
47
                $path = $connectionConfiguration->getSetting('path');
48
                $path = $this->expandTildePath($path);
49
50
                if (!is_dir($path) || !is_writable($path))
51
                {
52
                    throw new ConfigurationException(sprintf('Path "%s" does not exist or is not writable.', $path));
53
                }
54
55
                $adapter = new Local($path);
56
                $filesystem = new Filesystem($adapter);
57
58
                return new FlysystemConnectionAdapter($filesystem);
59
            },
60
        ]);
61
        $this->lockAdapterFactoryContainer = new LockAdapterFactoryContainer([
62
63
            'connection' => function(ConnectionConfiguration $connectionConfiguration)
64
            {
65
                $connection = $this->getConnection($connectionConfiguration->getTitle());
66
67
                return new ConnectionBasedLockAdapter($connection);
68
            }
69
        ]);
70
    }
71
72
    public function getConfiguration(): Configuration
73
    {
74
        return $this->configuration;
75
    }
76
77
    public function getConnectionAdapterFactoryContainer(): AbstractServiceFactoryContainer
78
    {
79
        return $this->connectionAdapterFactoryContainer;
80
    }
81
82
    public function getLockAdapterFactoryContainer(): AbstractServiceFactoryContainer
83
    {
84
        return $this->lockAdapterFactoryContainer;
85
    }
86
87 View Code Duplication
    public function getConnection(string $vaultTitle): ConnectionAdapterInterface
88
    {
89
        $connectionConfiguration = $this->configuration->getConnectionConfigurationByTitle($vaultTitle);
90
91
        if ($connectionConfiguration === null)
92
        {
93
            throw new Exception(sprintf('Unknown connection title: "%s".', $vaultTitle));
94
        }
95
96
        $connection = $this->connectionAdapterFactoryContainer->get($connectionConfiguration->getVaultAdapter(), $connectionConfiguration);
97
98
        if ($connection === null)
99
        {
100
            throw new ConfigurationException(sprintf('Unknown connection adapter: "%s".', $connectionConfiguration->getVaultAdapter()));
101
        }
102
103
        return $connection;
104
    }
105
106 View Code Duplication
    public function getLockAdapter(string $vaultTitle): LockAdapterInterface
107
    {
108
        $connectionConfiguration = $this->configuration->getConnectionConfigurationByTitle($vaultTitle);
109
110
        if ($connectionConfiguration === null)
111
        {
112
            throw new Exception(sprintf('Unknown connection title: "%s".', $vaultTitle));
113
        }
114
115
        $lockAdapter = $this->lockAdapterFactoryContainer->get($connectionConfiguration->getLockAdapter(), $connectionConfiguration);
116
117
        if ($lockAdapter === null)
118
        {
119
            throw new ConfigurationException(sprintf('Unknown lock adapter: "%s".', $connectionConfiguration->getLockAdapter()));
120
        }
121
122
        return $lockAdapter;
123
    }
124
125
    public function buildOperationCollection(): OperationCollection
126
    {
127
        $return = new OperationCollection();
128
129
        foreach ($this->getVaults() as $vault)
130
        {
131
            $return->append($vault->getOperationCollection());
132
        }
133
134
        return $return;
135
    }
136
137
    /**
138
     * @return Vault[]
139
     */
140
    public function getVaults(): array
141
    {
142
        return array_map(function(ConnectionConfiguration $connectionConfiguration) {
143
144
            return $this->getVault($connectionConfiguration->getTitle());
145
146
        }, $this->configuration->getConnectionConfigurations());
147
    }
148
149
    public function getVault(string $vaultTitle): Vault
150
    {
151
        if (!isset($this->vaults[$vaultTitle]))
152
        {
153
            $vault = new Vault(
154
                $vaultTitle,
155
                $this->configuration->getLocalPath(),
156
                $this->getConnection($vaultTitle)
157
            );
158
            $vault->setLockAdapter($this->getLockAdapter($vaultTitle));
159
            $vault->setExclusions($this->configuration->getExclusions());
160
161
            $this->vaults[$vaultTitle] = $vault;
162
        }
163
164
        return $this->vaults[$vaultTitle];
165
    }
166
167
    public function synchronize(array $vaultTitles = [], SynchronizationProgressListenerInterface $progressListener = null): OperationResultCollection
168
    {
169
        $lastRevision = 0;
170
171
        // fallback to all vaults
172
        $vaultTitles = $vaultTitles ?: array_map(function(Vault $vault) { return $vault->getTitle(); }, $this->getVaults());
173
174
        // acquire all locks and retrieve highest existing revision
175
        foreach ($this->getVaults() as $vault)
176
        {
177
            // lock is only required for vaults that we want to synchronize with
178
            if (in_array($vault->getTitle(), $vaultTitles))
179
            {
180
                while (!$vault->getLockAdapter()->acquireLock(Vault::LOCK_SYNC))
181
                {
182
                    sleep(5);
183
                }
184
            }
185
186
            // highest revision should be build across all vaults
187
            $synchronizationList = $vault->loadSynchronizationList();
188
            if ($synchronizationList && $synchronizationList->getLastSynchronization())
189
            {
190
                $lastRevision = max($lastRevision, $synchronizationList->getLastSynchronization()->getRevision());
191
            }
192
        }
193
194
        // new revision is one plus the highest existing revision across all vaults
195
        $newRevision = $lastRevision + 1;
196
197
        // actual synchronization
198
        $return = new OperationResultCollection();
199
        foreach ($vaultTitles as $vaultTitle)
200
        {
201
            $return->append($this->getVault($vaultTitle)->synchronize($newRevision, $this->configuration->getIdentity(), $progressListener));
202
        }
203
204
        // release lock at the last moment to further reduce change of deadlocks
205
        foreach ($vaultTitles as $vaultTitle)
206
        {
207
            $this->getVault($vaultTitle)->getLockAdapter()->releaseLock(Vault::LOCK_SYNC);
208
        }
209
210
        return $return;
211
    }
212
213
    /**
214
     * @return Synchronization[][]
215
     */
216
    public function buildSynchronizationHistory(): array
217
    {
218
        $return = [];
219
220
        foreach ($this->getVaults() as $vault)
221
        {
222
            $list = $vault->loadSynchronizationList();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $list is correct as $vault->loadSynchronizationList() (which targets Archivr\Vault::loadSynchronizationList()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
223
224
            if (!$list)
225
            {
226
                continue;
227
            }
228
229
            foreach ($list as $synchronization)
230
            {
231
                /** @var Synchronization $synchronization */
232
233
                $return[$synchronization->getRevision()][$vault->getTitle()] = $synchronization;
234
            }
235
        }
236
237
        ksort($return);
238
239
        return $return;
240
    }
241
}
242