Completed
Push — master ( 6fed26...e3ac15 )
by Guilh
08:12
created

RestYamlCollectionLoader::addParentNamePrefix()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.2
cc 4
eloc 8
nc 3
nop 2
crap 4
1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
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 FOS\RestBundle\Routing\Loader;
13
14
use FOS\RestBundle\Routing\RestRouteCollection;
15
use Symfony\Component\Config\FileLocatorInterface;
16
use Symfony\Component\Config\Resource\FileResource;
17
use Symfony\Component\Routing\Loader\YamlFileLoader;
18
use Symfony\Component\Routing\RouteCollection;
19
use Symfony\Component\Yaml\Exception\ParseException;
20
use Symfony\Component\Yaml\Yaml;
21
22
/**
23
 * RestYamlCollectionLoader YAML file collections loader.
24
 */
25
class RestYamlCollectionLoader extends YamlFileLoader
26
{
27
    protected $collectionParents = [];
28
    private $processor;
29
    private $includeFormat;
30
    private $formats;
31
    private $defaultFormat;
32
33
    /**
34
     * Initializes yaml loader.
35
     *
36
     * @param FileLocatorInterface $locator
37
     * @param RestRouteProcessor   $processor
38
     * @param bool                 $includeFormat
39
     * @param string[]             $formats
40
     * @param string               $defaultFormat
41
     */
42 29 View Code Duplication
    public function __construct(
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...
43
        FileLocatorInterface $locator,
44
        RestRouteProcessor $processor,
45
        $includeFormat = true,
46
        array $formats = [],
47
        $defaultFormat = null
48
    ) {
49 29
        parent::__construct($locator);
50
51 29
        $this->processor = $processor;
52 29
        $this->includeFormat = $includeFormat;
53 29
        $this->formats = $formats;
54 29
        $this->defaultFormat = $defaultFormat;
55 29
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 17
    public function load($file, $type = null)
61
    {
62 17
        $path = $this->locator->locate($file);
63
64
        try {
65 17
            $config = Yaml::parse(file_get_contents($path));
66 17
        } catch (ParseException $e) {
67 1
            throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
68
        }
69
70 16
        $collection = new RouteCollection();
71 16
        $collection->addResource(new FileResource($path));
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->locator->locate($file) on line 62 can also be of type array; however, Symfony\Component\Config...Resource::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
72
73
        // empty file
74 16
        if (null === $config) {
75 1
            return $collection;
76
        }
77
78
        // not an array
79 15
        if (!is_array($config)) {
80 1
            throw new \InvalidArgumentException(sprintf('The file "%s" must contain a Yaml mapping (an array).', $path));
81
        }
82
83
        // process routes and imports
84 14
        foreach ($config as $name => $config) {
85 14
            if (isset($config['resource'])) {
86 8
                $resource = $config['resource'];
87 8
                $prefix = isset($config['prefix']) ? $config['prefix'] : null;
88 8
                $namePrefix = isset($config['name_prefix']) ? $config['name_prefix'] : null;
89 8
                $parent = isset($config['parent']) ? $config['parent'] : null;
90 8
                $type = isset($config['type']) ? $config['type'] : null;
91 8
                $host = isset($config['host']) ? $config['host'] : null;
92 8
                $requirements = isset($config['requirements']) ? $config['requirements'] : [];
93 8
                $defaults = isset($config['defaults']) ? $config['defaults'] : [];
94 8
                $options = isset($config['options']) ? $config['options'] : [];
95 8
                $currentDir = dirname($path);
96
97 8
                $parents = [];
98 8 View Code Duplication
                if (!empty($parent)) {
99 4
                    if (!isset($this->collectionParents[$parent])) {
100 1
                        throw new \InvalidArgumentException(sprintf('Cannot find parent resource with name %s', $parent));
101
                    }
102
103 3
                    $parents = $this->collectionParents[$parent];
104 3
                }
105
106 7
                $imported = $this->processor->importResource($this, $resource, $parents, $prefix, $namePrefix, $type, $currentDir);
107
108 7
                if ($imported instanceof RestRouteCollection) {
109 7
                    $parents[] = ($prefix ? $prefix.'/' : '').$imported->getSingularName();
110 7
                    $prefix = null;
111 7
                    $namePrefix = null;
112
113 7
                    $this->collectionParents[$name] = $parents;
114 7
                }
115
116 7
                $imported->addRequirements($requirements);
117 7
                $imported->addDefaults($defaults);
118 7
                $imported->addOptions($options);
119
120 7
                if (!empty($host)) {
121
                    $imported->setHost($host);
122
                }
123
124 7
                $imported->addPrefix($prefix);
125
126
                // Add name prefix from parent config files
127 7
                $imported = $this->addParentNamePrefix($imported, $namePrefix);
128
129 7
                $collection->addCollection($imported);
130 13
            } elseif (isset($config['pattern']) || isset($config['path'])) {
131
                // the YamlFileLoader of the Routing component only checks for
132
                // the path option
133 6
                if (!isset($config['path'])) {
134 1
                    $config['path'] = $config['pattern'];
135
136 1
                    @trigger_error(sprintf('The "pattern" option at "%s" in file "%s" is deprecated. Use the "path" option instead.', $name, $path), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
137 1
                }
138
139 6
                if ($this->includeFormat) {
140
                    // append format placeholder if not present
141 5
                    if (false === strpos($config['path'], '{_format}')) {
142 5
                        $config['path'] .= '.{_format}';
143 5
                    }
144
145
                    // set format requirement if configured globally
146 5 View Code Duplication
                    if (!isset($config['requirements']['_format']) && !empty($this->formats)) {
147 5
                        $config['requirements']['_format'] = implode('|', array_keys($this->formats));
148 5
                    }
149 5
                }
150
151
                // set the default format if configured
152 6
                if (null !== $this->defaultFormat) {
153 1
                    $config['defaults']['_format'] = $this->defaultFormat;
154 1
                }
155
156 6
                $this->parseRoute($collection, $name, $config, $path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->locator->locate($file) on line 62 can also be of type array; however, Symfony\Component\Routin...ileLoader::parseRoute() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
157 6
            } else {
158
                throw new \InvalidArgumentException(sprintf('Unable to parse the "%s" route.', $name));
159
            }
160 13
        }
161
162 13
        return $collection;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168 7
    public function supports($resource, $type = null)
169
    {
170 7
        return is_string($resource) &&
171 7
            'yml' === pathinfo($resource, PATHINFO_EXTENSION) &&
172 7
            'rest' === $type;
173
    }
174
175
    /**
176
     * Adds a name prefix to the route name of all collection routes.
177
     *
178
     * @param RouteCollection $collection Route collection
179
     * @param array           $namePrefix NamePrefix to add in each route name of the route collection
180
     *
181
     * @return RouteCollection
182
     */
183 7
    public function addParentNamePrefix(RouteCollection $collection, $namePrefix)
184
    {
185 7
        if (!isset($namePrefix) || ($namePrefix = trim($namePrefix)) === '') {
186 7
            return $collection;
187
        }
188
189 1
        $iterator = $collection->getIterator();
190
191 1
        foreach ($iterator as $key1 => $route1) {
192 1
            $collection->add($namePrefix.$key1, $route1);
193 1
            $collection->remove($key1);
194 1
        }
195
196 1
        return $collection;
197
    }
198
}
199