Failed Conditions
Pull Request — 1.0 (#79)
by Bernhard
02:54
created

OptimizedJsonRepository::getReferencesForRegex()   C

Complexity

Conditions 9
Paths 7

Size

Total Lines 47
Code Lines 21

Duplication

Lines 9
Ratio 19.15 %

Code Coverage

Tests 21
CRAP Score 9.1582

Importance

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