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

OptimizedJsonRepository::addFilesystemResource()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4286
cc 3
eloc 6
nc 4
nop 2
crap 3
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 76
    protected function insertReference($path, $reference)
75
    {
76 76
        $this->json[$path] = $reference;
77 76
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 7
    protected function removeReferences($glob)
83
    {
84 7
        $removed = 0;
85
86 7
        foreach ($this->getReferencesForGlob($glob.'{,/**/*}') as $path => $reference) {
87 7
            ++$removed;
88
89 7
            unset($this->json[$path]);
90 7
        }
91
92 7
        return $removed;
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 52
    protected function getReferencesForPath($path)
99
    {
100 52
        if (!array_key_exists($path, $this->json)) {
101 13
            return array();
102
        }
103
104 48
        $reference = $this->json[$path];
105
106
        // We're only interested in the first entry of eventual arrays
107 48
        if (is_array($reference)) {
108
            $reference = reset($reference);
109
        }
110
111 48 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 47
            $reference = Path::makeAbsolute($reference, $this->baseDirectory);
113
114
            // Ignore non-existing files. Not sure this is the right
115
            // thing to do.
116 47
            if (!file_exists($reference)) {
117
                return array();
118
            }
119 47
        }
120
121 48
        return array($path => $reference);
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127 22 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 22
        if (!Glob::isDynamic($glob)) {
130 16
            return $this->getReferencesForPath($glob);
131
        }
132
133 13
        return $this->getReferencesForRegex(
134 13
            Glob::getStaticPrefix($glob),
135 13
            Glob::toRegEx($glob),
136
            $flags
137 13
        );
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143 25
    protected function getReferencesForRegex($staticPrefix, $regex, $flags = 0)
144
    {
145 25
        $result = array();
146 25
        $foundMappingsWithPrefix = false;
147
148 25
        foreach ($this->json as $path => $reference) {
149 25
            if (0 === strpos($path, $staticPrefix)) {
150 21
                $foundMappingsWithPrefix = true;
151
152 21
                if (!preg_match($regex, $path)) {
153 8
                    continue;
154
                }
155
156
                // We're only interested in the first entry of eventual arrays
157 20
                if (is_array($reference)) {
158
                    $reference = reset($reference);
159
                }
160
161 20 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 20
                    $reference = Path::makeAbsolute($reference, $this->baseDirectory);
163
164
                    // Ignore non-existing files. Not sure this is the right
165
                    // thing to do.
166 20
                    if (!file_exists($reference)) {
167
                        continue;
168
                    }
169 20
                }
170
171 20
                $result[$path] = $reference;
172
173 20
                if ($flags & self::STOP_ON_FIRST) {
174 4
                    return $result;
175
                }
176
177 17
                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 21
            if ($foundMappingsWithPrefix) {
184 15
                break;
185
            }
186 24
        }
187
188 24
        return $result;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194 11 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 11
        $basePath = rtrim($path, '/');
197
198 11
        return $this->getReferencesForRegex(
199 11
            $basePath.'/',
200 11
            '~^'.preg_quote($basePath, '~').'/[^/]+$~',
201
            $flags
202 11
        );
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208 76
    protected function addFilesystemResource($path, FilesystemResource $resource)
209
    {
210
        // Read children before attaching the resource to this repository
211 76
        $children = $resource->listChildren();
212
213 76
        parent::addFilesystemResource($path, $resource);
214
215
        // Recursively add all child resources
216 76
        $basePath = '/' === $path ? $path : $path.'/';
217
218 76
        foreach ($children as $name => $child) {
219 38
            $this->addFilesystemResource($basePath.$name, $child);
220 76
        }
221 76
    }
222
}
223