GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 5512e8...78b9a3 )
by Bruno
01:27
created

PlaceholdersRepository::getReplacement()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 47
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 47
rs 8.5125
c 0
b 0
f 0
cc 6
eloc 26
nc 6
nop 2
1
<?php
2
namespace Ciandt\Behat\PlaceholdersExtension\Config;
3
4
use Symfony\Component\Yaml\Yaml;
5
use Ciandt\Behat\PlaceholdersExtension\Utils\PlaceholderUtils;
6
use Ciandt\Behat\PlaceholdersExtension\PlaceholderContainer\PlaceholderContainer;
7
use Ciandt\Behat\PlaceholdersExtension\Exception\MissingSectionException;
8
use Ciandt\Behat\PlaceholdersExtension\Exception\UndefinedPlaceholderException;
9
use Exception;
10
11
/**
12
 * Description of ConfigsRepository
13
 *
14
 * @author bwowk
15
 */
16
class PlaceholdersRepository
17
{
18
    const PLACEHOLDER_REGEX = '/\${(?P<placeholder>[a-zA-Z0-9_-]+)}/';
19
    
20
    private $configs;
21
    
22
    private $beforeScenarioSubscriber;
23
    
24
    private $placeholders = array();
25
26
    /**
27
     * @var string
28
     */
29
    private $environment;
30
31
    public function __construct($configs_mapping, $beforeScenarioSubscriber)
32
    {
33
        $this->configs = $this->loadConfigFiles($configs_mapping);
34
        $this->beforeScenarioSubscriber = $beforeScenarioSubscriber;
35
    }
36
37
    /**
38
     *
39
     * @return string[]
40
     * @todo read configs and also bring alternative @config:section tags
41
     */
42
    public function getTags()
43
    {
44
        return array_keys($this->configs);
45
    }
46
47
    /**
48
     * reads the YAML placeholder definitions and returns an associative array
49
     *
50
     * @param type $config_files
0 ignored issues
show
Bug introduced by
There is no parameter named $config_files. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
51
     * @todo use %paths.base% value
52
     * @return array
53
     */
54
    private function loadConfigFiles($configs_mapping)
55
    {
56
        $placeholder_maps = array();
57
        foreach ($configs_mapping as $tag => $file_path) {
58
            $placeholder_maps[$tag]['config'] = Yaml::parse(file_get_contents($file_path));
59
            $placeholder_maps[$tag]['path'] = $file_path;
60
        }
61
        return $placeholder_maps;
62
    }
63
64 View Code Duplication
    private function getConfig($key)
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...
65
    {
66
        if (key_exists($key, $this->configs)) {
67
            return $this->configs[$key]['config'];
68
        }
69
        return null;
70
    }
71
72 View Code Duplication
    private function getFilePath($key)
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...
73
    {
74
         if (key_exists($key, $this->configs)) {
75
            return $this->configs[$key]['path'];
76
        }
77
        return null;
78
    }
79
       
80
    public function getEnvironment()
81
    {
82
        return $this->environment;
83
    }
84
85
    public function setEnvironment($environment)
86
    {
87
        $this->environment = $environment;
88
    }
89
    
90
    private function getScenarioTags(){
91
        return $this->beforeScenarioSubscriber->getScenarioTags();
92
    }
93
94
    public function getReplacement($placeholder, $replaced = array()) {
95
        
96
        // if the current placeholder was already replaced before, this is a cyclic dependecy
97
        if (in_array($placeholder, $replaced)){
98
            $tree = implode('>', $replaced);
99
            throw new Exception("Cyclic placeholder dependecy detected. Trying to replace $placeholder again when already replaced: $tree");
100
        }
101
        
102
        // if there's a runtime placeholder defined for that key, return it right away
103
        if (array_key_exists($placeholder, $this->placeholders)) {
104
            return $this->placeholders[$placeholder];
105
        }
106
        
107
        $tags = $this->getScenarioTags();
108
        
109
        //@todo abort if there's no config tag
110
        $configTag = PlaceholderUtils::getConfigTag($tags);
111
        $configKey = PlaceholderUtils::getConfigKey($configTag);
112
        $section = PlaceholderUtils::getSectionKey($configTag);
113
        $placeholders = $this->getSectionPlaceholders($configKey, $section);
114
        
115
        $variantTags = PlaceholderUtils::filterVariantTags($tags, false);
116
        $variant = end($variantTags);
117
        $environment = $this->getEnvironment();
118
        $configPath = $this->getFilePath($configKey);
119
        $keys = array('$' . $variant, '$' . $environment, $placeholder);
120
        $treePosition = "$configPath>$section>placeholders";
121
122
        $replacement = $this->recursivePlaceholderSearch($keys, $placeholders, $treePosition);
123
        
124
        if (is_null($replacement)){
125
            throw new UndefinedPlaceholderException("No $placeholder placeholder was defined on runtime or on $treePosition>$placeholder for variant $variant and environment $environment");
126
        } 
127
        
128
        //if the replaced string doesn't have placeholders itself
129
        if (preg_match_all(self::PLACEHOLDER_REGEX, $replacement, $matches, PREG_SET_ORDER) == 0){
130
            return $replacement;
131
        }
132
        
133
        //if it does have, replace them before returning
134
        foreach ($matches as $match) {
0 ignored issues
show
Bug introduced by
The expression $matches of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
135
            $replaced[] = $placeholder;
136
            $replacement = str_replace('${' . $match['placeholder'] . '}', $this->getReplacement($match['placeholder'], $replaced), $replacement);
137
        }
138
        return $replacement;
139
        
140
    }
141
    
142
    private function recursivePlaceholderSearch($keys, $values, $treePosition)
143
    {
144
        if (empty($keys) || is_scalar($values)) {
145
            return $values;
146
        }
147
        $key = array_pop($keys);
148
        if (key_exists($key, $values)) {
149
            $specificValue = $this->recursivePlaceholderSearch($keys, $values[$key], "$treePosition>$key");
150
            if ($specificValue) {
151
                return $specificValue;
152
            }
153
        } if (key_exists('$default', $values)) {
154
            $defaultValue = $this->recursivePlaceholderSearch($keys, $values['$default'], $treePosition . '>$default');
155
            if ($defaultValue) {
156
                return $defaultValue;
157
            }
158
        } 
159
        
160
        return null;
161
    }
162
    
163
    private function getSectionPlaceholders($configKey, $section){
164
        $config = $this->getConfig($configKey);
165
        if (!isset($config) || !key_exists($section, $config)){
166
            throw new MissingSectionException(
167
                    $configKey,
168
                    $this->getFilePath($configKey),
169
                    $section);
170
        }
171
        return $config[$section]['placeholders'];
172
    }
173
    
174
    public function setPlaceholder($key, $value, $environment = '$default', $variant = '$default') {
175
        if (!isset($this->placeholders[$key])) {
176
            $this->placeholders[$key] = array();
177
        }
178
        if (!isset($this->placeholders[$key][$environment])) {
179
            $this->placeholders[$key][$environment] = array();
180
        }
181
        $this->placeholders[$key][$environment][$variant] = $value;
182
    }
183
184
}
185