Completed
Push — master ( ba8ed9...770316 )
by Jeroen
06:11
created

FixturesBundle/Parser/Property/Method.php (1 issue)

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
     *
31
     * @return mixed
32
     *
33
     * @throws \Exception
34
     */
35
    public function parse($value, $providers, $references = [], $additional = [])
36
    {
37
        preg_match_all(self::REGEX, $value, $matches);
38
39
        foreach ($matches[0] as $pattern) {
40
            preg_match_all('/[^,\(\)<>]+/', $pattern, $arguments);
41
            $arguments = $arguments[0];
42
            $method = array_shift($arguments);
43
            $arguments = array_map(function ($arg) {
44
                return trim(trim($arg), '\'""');
45
            }, $arguments);
46
47
            foreach ($providers as $provider) {
48
                /*
49
                 * Call method from provider with/without arguments
50
                 * 1: Arguments are passed through from fixture
51
                 * 2: Search if method needs arguments en find them through typehint and additional params
52
                 * 3: Magic methods without arguments
53
                 */
54
                if (method_exists($provider, $method)) {
55
                    $refl = new \ReflectionMethod($provider, $method);
56
57
                    if (count($arguments) < $refl->getNumberOfRequiredParameters()) {
58
                        $parameters = $refl->getParameters();
59
                        $parametersNeeded = array_slice($parameters, count($arguments));
60
                        $arguments = array_merge($arguments, $this->findArguments($parametersNeeded, $additional));
61
62
                        if (count($parameters) !== count($arguments)) {
63
                            throw new \Exception('Can not match all arguments for provider ' . get_class($provider));
64
                        }
65
                    }
66
67
                    $value = $this->processValue($pattern, $refl->invokeArgs($provider, $arguments), $value, $matches[0]);
68
69
                    break;
70
                } elseif (is_callable([$provider, $method])) {
71
                    $value = $this->processValue($pattern, call_user_func_array(array($provider, $method), $arguments), $value, $matches[0]);
72
73
                    break;
74
                }
75
            }
76
        }
77
78
        return $value;
79
    }
80
81
    private function processValue($pattern, $result, $value, $patterns)
82
    {
83
        if (!is_string($result) && !is_int($result) && count($patterns) > 1 && strlen(str_replace($pattern, '', $value)) > 0) {
84
            throw new \Exception(sprintf('Collision during processing of pattern "%s" on value "%s"', $pattern, $value));
85
        }
86
87
        if (!is_string($result) && !is_int($result)) {
88
            return $result;
89
        }
90
91
        return str_replace($pattern, $result, $value);
92
    }
93
94
    /**
95
     * @param $parameters
96
     * @param $additional
97
     *
98
     * @return array
99
     */
100
    private function findArguments($parameters, $additional)
101
    {
102
        $arguments = [];
103
        if (count($parameters) == 0) {
104
            return $arguments;
105
        }
106
107
        foreach ($parameters as $parameter) {
108
            $argument = $this->typeHintChecker($parameter, $additional);
109
            if ($argument !== null) {
110
                $arguments[] = $argument;
111
112
                continue;
113
            }
114
115
            $argument = $this->getArgumentByName($parameter, $additional);
116
            if ($argument !== null) {
117
                $arguments[] = $argument;
118
            }
119
        }
120
121
        return $arguments;
122
    }
123
124
    /**
125
     * @param \ReflectionParameter $parameter
126
     * @param $parameters
127
     *
128
     * @return null|object
129
     */
130
    private function typeHintChecker(\ReflectionParameter $parameter, $parameters)
131
    {
132
        $class = $parameter->getClass();
133
        $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...
134
        if (!$class instanceof \ReflectionClass) {
135
            return null;
136
        }
137
138
        $typeHint = $class->getName();
139
        foreach ($parameters as $item) {
140
            if ($item instanceof $typeHint) {
141
                return $item;
142
            }
143
        }
144
145
        return null;
146
    }
147
148
    /**
149
     * @param \ReflectionParameter $parameter
150
     * @param $parameters
151
     *
152
     * @return null|mixed
153
     */
154
    private function getArgumentByName(\ReflectionParameter $parameter, $parameters)
155
    {
156
        foreach ($parameters as $name => $item) {
157
            $paramName = $parameter->getName();
158
            if ($name === $paramName) {
159
                return $item;
160
            }
161
        }
162
163
        return null;
164
    }
165
}
166