Failed Conditions
Pull Request — 1.0 (#79)
by Bernhard
12:18
created

OptimizedJsonRepository::getReferencesForRegex()   C

Complexity

Conditions 9
Paths 7

Size

Total Lines 49
Code Lines 23

Duplication

Lines 11
Ratio 22.45 %

Code Coverage

Tests 24
CRAP Score 9.0368

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 11
loc 49
ccs 24
cts 26
cp 0.9231
rs 5.7447
cc 9
eloc 23
nc 7
nop 3
crap 9.0368
1
<?php
2
3
/*
4
 * This file is part of the puli/repository package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Repository;
13
14
use Psr\Log\LogLevel;
15
use Puli\Repository\Api\EditableRepository;
16
use Puli\Repository\Api\Resource\FilesystemResource;
17
use Webmozart\Glob\Glob;
18
use Webmozart\PathUtil\Path;
19
20
/**
21
 * A repository backed by a JSON file optimized for reading.
22
 *
23
 * The generated JSON file is described by res/schema/repository-schema-1.0.json.
24
 *
25
 * Resources can be added with the method {@link add()}:
26
 *
27
 * ```php
28
 * use Puli\Repository\OptimizedJsonRepository;
29
 *
30
 * $repo = new OptimizedJsonRepository('/path/to/repository.json', '/path/to/project');
31
 * $repo->add('/css', new DirectoryResource('/path/to/project/res/css'));
32
 * ```
33
 *
34
 * When adding a resource, the added filesystem path is stored in the JSON file
35
 * under the key of the Puli path. The path is stored relatively to the base
36
 * directory passed to the constructor. Directories will be expanded and all
37
 * nested files will be added to the mapping file as well:
38
 *
39
 * ```json
40
 * {
41
 *     "/css": "res/css",
42
 *     "/css/style.css": "res/css/style.css"
43
 * }
44
 * ```
45
 *
46
 * Mapped resources can be read with the method {@link get()}:
47
 *
48
 * ```php
49
 * $cssPath = $repo->get('/css')->getFilesystemPath();
50
 * ```
51
 *
52
 * You can also access nested files:
53
 *
54
 * ```php
55
 * echo $repo->get('/css/style.css')->getBody();
56
 * ```
57
 *
58
 * Since nested files are searched during {@link add()} and added to the JSON
59
 * file, this repository does not detect any files that you add to a directory
60
 * after adding that directory to the repository. This means that accessing
61
 * files is very fast, but also that the usage of this repository implementation
62
 * can be cumbersome in development environments. There you are recommended to
63
 * use {@link JsonRepository} instead.
64
 *
65
 * @since  1.0
66
 *
67
 * @author Bernhard Schussek <[email protected]>
68
 * @author Titouan Galopin <[email protected]>
69
 */
70
class OptimizedJsonRepository extends AbstractJsonRepository implements EditableRepository
71
{
72
    /**
73
     * {@inheritdoc}
74
     */
75 6
    public function clear()
76
    {
77 6
        if (null === $this->json) {
78 2
            $this->load();
79 2
        }
80
81
        // Subtract root which is not deleted
82 6
        $removed = count($this->json) - 1;
83
84 6
        $this->json = array();
85
86 6
        $this->flush();
87
88 6
        $this->clearVersions();
89 6
        $this->storeVersion($this->get('/'));
90
91 6
        return $removed;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 166
    protected function insertReference($path, $reference)
98
    {
99 166
        $this->json[$path] = $reference;
100 166
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 136
    protected function removeReferences($glob)
106
    {
107 20
        $removed = 0;
108
109 20
        foreach ($this->getReferencesForGlob($glob.'{,/**/*}') as $path => $reference) {
110 20
            ++$removed;
111
112 20
            $this->removeVersions($path);
113
114 136
            unset($this->json[$path]);
115 92
        }
116
117 20
        return $removed;
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 108
    protected function getReferencesForPath($path)
124
    {
125 108
        if (!array_key_exists($path, $this->json)) {
126 26
            return array();
127
        }
128
129 100
        $reference = $this->json[$path];
130
131
        // We're only interested in the first entry of eventual arrays
132 100
        if (is_array($reference)) {
133
            $reference = reset($reference);
134
        }
135
136 100 View Code Duplication
        if ($this->isFilesystemReference($reference)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
137 90
            $absoluteReference = Path::makeAbsolute($reference, $this->baseDirectory);
138
139 90
            if (!file_exists($absoluteReference)) {
140 2
                $this->logReferenceNotFound($path, $reference, $absoluteReference);
141
142 2
                return array();
143
            }
144
145 88
            $reference = $absoluteReference;
146 88
        }
147
148 98
        return array($path => $reference);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154 48 View Code Duplication
    protected function getReferencesForGlob($glob, $flags = 0)
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...
155
    {
156 48
        if (!Glob::isDynamic($glob)) {
157 26
            return $this->getReferencesForPath($glob);
158
        }
159
160 36
        return $this->getReferencesForRegex(
161 36
            Glob::getStaticPrefix($glob),
162 36
            Glob::toRegEx($glob),
163
            $flags
164 36
        );
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 62
    protected function getReferencesForRegex($staticPrefix, $regex, $flags = 0)
171
    {
172 62
        $result = array();
173 62
        $foundMappingsWithPrefix = false;
174
175 62
        foreach ($this->json as $path => $reference) {
176 62
            if (0 === strpos($path, $staticPrefix)) {
177 54
                $foundMappingsWithPrefix = true;
178
179 54
                if (!preg_match($regex, $path)) {
180 16
                    continue;
181
                }
182
183
                // We're only interested in the first entry of eventual arrays
184 52
                if (is_array($reference)) {
185
                    $reference = reset($reference);
186
                }
187
188 52 View Code Duplication
                if ($this->isFilesystemReference($reference)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
189 52
                    $absoluteReference = Path::makeAbsolute($reference, $this->baseDirectory);
190
191 52
                    if (!file_exists($absoluteReference)) {
192 8
                        $this->logReferenceNotFound($path, $reference, $absoluteReference);
193
194 8
                        continue;
195
                    }
196
197 44
                    $reference = $absoluteReference;
198 44
                }
199
200 44
                $result[$path] = $reference;
201
202 44
                if ($flags & self::STOP_ON_FIRST) {
203 8
                    return $result;
204
                }
205
206 38
                continue;
207
            }
208
209
            // We did not find anything but previously found mappings with the
210
            // static prefix
211
            // The mappings are sorted alphabetically, so we can safely abort
212 56
            if ($foundMappingsWithPrefix) {
213 44
                break;
214
            }
215 60
        }
216
217 60
        return $result;
218
    }
219
220
    /**
221
     * {@inheritdoc}
222
     */
223 26 View Code Duplication
    protected function getReferencesInDirectory($path, $flags = 0)
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...
224
    {
225 26
        $basePath = rtrim($path, '/');
226
227 26
        return $this->getReferencesForRegex(
228 26
            $basePath.'/',
229 26
            '~^'.preg_quote($basePath, '~').'/[^/]+$~',
230
            $flags
231 26
        );
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237 166
    protected function addFilesystemResource($path, FilesystemResource $resource)
238
    {
239
        // Read children before attaching the resource to this repository
240 166
        $children = $resource->listChildren();
241
242 166
        parent::addFilesystemResource($path, $resource);
243
244
        // Recursively add all child resources
245 166
        $basePath = '/' === $path ? $path : $path.'/';
246
247 166
        foreach ($children as $name => $child) {
248 72
            $this->addFilesystemResource($basePath.$name, $child);
249 166
        }
250 166
    }
251
}
252