Completed
Push — master ( 91fdab...75a7b9 )
by
unknown
13:37
created

FixturesBundle/Parser/Property/Method.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\FixturesBundle\Parser\Property;
4
5
class Method implements PropertyParserInterface
6
{
7
    const REGEX = '/<[a-zA-Z0-9]+\([^\)]*\)>/';
8
9
    /**
10
     * Check if this parser is applicable
11
     *
12
     * @return bool
13
     */
14
    public function canParse($value)
15
    {
16
        if (is_string($value) && preg_match(self::REGEX, $value)) {
17
            return true;
18
        }
19
20
        return false;
21
    }
22
23
    /**
24
     * Parse provided value into new data
25
     *
26
     * @param $value
27
     * @param $providers
28
     * @param array $references
29
     * @param array $additional
30
     * @return mixed
31
     * @throws \Exception
32
     */
33
    public function parse($value, $providers, $references = [], $additional = [])
34
    {
35
        preg_match_all(self::REGEX, $value, $matches);
36
37
        foreach ($matches[0] as $pattern) {
38
            preg_match_all('/[^,\(\)<>]+/', $pattern, $arguments);
39
            $arguments = $arguments[0];
40
            $method = array_shift($arguments);
41
            $arguments = array_map(function ($arg) {
42
                return trim(trim($arg), '\'""');
43
            }, $arguments);
44
45
            foreach ($providers as $provider) {
46
                /**
47
                 * Call method from provider with/without arguments
48
                 * 1: Arguments are passed through from fixture
49
                 * 2: Search if method needs arguments en find them through typehint and additional params
50
                 * 3: Magic methods without arguments
51
                 */
52
                if (method_exists($provider, $method)) {
53
                    $refl = new \ReflectionMethod($provider, $method);
54
55
                    if (count($arguments) < $refl->getNumberOfRequiredParameters()) {
56
                        $parameters = $refl->getParameters();
57
                        $parametersNeeded = array_slice($parameters, count($arguments));
58
                        $arguments = array_merge($arguments, $this->findArguments($parametersNeeded, $additional));
59
60
                        if (count($parameters) !== count($arguments)) {
61
                            throw new \Exception('Can not match all arguments for provider ' . get_class($provider));
62
                        }
63
                    }
64
65
                    $value = $this->processValue($pattern, $refl->invokeArgs($provider, $arguments), $value, $matches[0]);
66
                    break;
67
                } elseif (is_callable([$provider, $method])) {
68
                    $value = $this->processValue($pattern, call_user_func_array(array($provider, $method), $arguments), $value, $matches[0]);
69
                    break;
70
                }
71
            }
72
        }
73
74
        return $value;
75
    }
76
77
    private function processValue($pattern, $result, $value, $patterns)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
78
    {
79
        if (!is_string($result) && !is_int($result) && count($patterns) > 1 && strlen(str_replace($pattern, '', $value)) > 0) {
80
            throw new \Exception(sprintf('Collision during processing of pattern "%s" on value "%s"', $pattern, $value));
81
        }
82
83
        if (!is_string($result) && !is_int($result)) {
84
            return $result;
85
        }
86
87
        return str_replace($pattern, $result, $value);
88
89
    }
90
91
    /**
92
     * @param $parameters
93
     * @param $additional
94
     * @return array
95
     */
96
    private function findArguments($parameters, $additional)
97
    {
98
        $arguments = [];
99
        if (count($parameters) == 0) {
100
            return $arguments;
101
        }
102
103
        foreach ($parameters as $parameter) {
104
            $argument = $this->typeHintChecker($parameter, $additional);
105
            if ($argument !== null) {
106
                $arguments[] = $argument;
107
                continue;
108
            }
109
110
            $argument = $this->getArgumentByName($parameter, $additional);
111
            if ($argument !== null) {
112
                $arguments[] = $argument;
113
            }
114
        }
115
116
        return $arguments;
117
    }
118
119
    /**
120
     * @param \ReflectionParameter $parameter
121
     * @param $parameters
122
     * @return null|object
123
     */
124
    private function typeHintChecker(\ReflectionParameter $parameter, $parameters)
125
    {
126
        $class = $parameter->getClass();
127
        $typeHint = null;
0 ignored issues
show
$typeHint is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
128
        if (!$class instanceof \ReflectionClass) {
129
            return null;
130
        }
131
132
        $typeHint = $class->getName();
133
        foreach ($parameters as $item) {
134
            if ($item instanceof $typeHint) {
135
                return $item;
136
            }
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * @param \ReflectionParameter $parameter
144
     * @param $parameters
145
     * @return null|mixed
146
     */
147
    private function getArgumentByName(\ReflectionParameter $parameter, $parameters)
148
    {
149
        foreach ($parameters as $name => $item) {
150
            $paramName = $parameter->getName();
151
            if ($name === $paramName) {
152
                return $item;
153
            }
154
        }
155
156
        return null;
157
    }
158
}
159