Completed
Branch master (e35419)
by Gaetano
06:40
created

HTTPExecutor::call()   A

Complexity

Conditions 6
Paths 17

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 17
nop 2
dl 0
loc 27
ccs 0
cts 14
cp 0
crap 42
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Symfony\Component\DependencyInjection\ContainerInterface;
6
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
7
use Kaliop\eZMigrationBundle\API\EmbeddedReferenceResolverBagInterface;
8
use Psr\Http\Message\ResponseInterface;
9
10
class HTTPExecutor extends AbstractExecutor
11
{
12
    use IgnorableStepExecutorTrait;
0 ignored issues
show
Bug introduced by
The trait Kaliop\eZMigrationBundle...orableStepExecutorTrait requires the property $dsl which is not provided by Kaliop\eZMigrationBundle...e\Executor\HTTPExecutor.
Loading history...
13
14
    protected $supportedStepTypes = array('http');
15
    protected $supportedActions = array('call');
16
17
    /** @var EmbeddedReferenceResolverBagInterface $referenceResolver */
18
    protected $referenceResolver;
19
20
    protected $container;
21
22
    /**
23
     * @param ContainerInterface $container
24
     * @param EmbeddedReferenceResolverBagInterface $referenceResolver has to implement EmbeddedReferenceResolverInterface as well!
25
     */
26 80
    public function __construct(ContainerInterface $container, EmbeddedReferenceResolverBagInterface $referenceResolver)
27
    {
28 80
        $this->referenceResolver = $referenceResolver;
29 80
        $this->container = $container;
30 80
    }
31
32
    /**
33
     * @param MigrationStep $step
34
     * @return mixed
35
     * @throws \Exception
36
     */
37
    public function execute(MigrationStep $step)
38
    {
39
        parent::execute($step);
40
41
        if (!isset($step->dsl['mode'])) {
42
            throw new \Exception("Invalid step definition: missing 'mode'");
43
        }
44
45
        $action = $step->dsl['mode'];
46
47
        if (!in_array($action, $this->supportedActions)) {
48
            throw new \Exception("Invalid step definition: value '$action' is not allowed for 'mode'");
49
        }
50
51
        $this->skipStepIfNeeded($step);
52
53
        return $this->$action($step->dsl, $step->context);
54
    }
55
56
    /**
57
     * @param array $dsl
58
     * @param array $context
59
     * @return true
60
     * @throws \Exception
61
     */
62
    protected function call($dsl, $context)
63
    {
64
        if (!isset($dsl['uri'])) {
65
            throw new \Exception("Can not execute http call without 'uri' in the step definition");
66
        }
67
68
        $method = isset($dsl['method']) ? $dsl['method'] : 'GET';
69
70
        $uri = $this->resolveReferencesInText($dsl['uri']);
71
72
        $headers = isset($dsl['headers']) ? $this->resolveReferencesInTextRecursively($dsl['headers']) : array();
73
74
        $body = isset($dsl['body']) ? $this->resolveReferencesInText($dsl['body']) : null;
75
76
        if (isset($dsl['client'])) {
77
            $client = $this->container->get('httplug.client.'.$dsl['client']);
78
        } else {
79
            $client = $this->container->get('httplug.client');
80
        }
81
82
        $request = $this->container->get('httplug.message_factory')->createRequest($method, $uri, $headers, $body);
83
84
        $response = $client->sendRequest($request);
85
86
        $this->setReferences($response, $dsl);
87
88
        return $response;
89
    }
90
91
    /**
92
     * @param ResponseInterface $response
93
     * @param array $dsl
94
     * @return bool
95
     * @todo use jmespath syntax to allow setting refs to response headers
96
     */
97
    protected function setReferences(ResponseInterface $response, $dsl)
98
    {
99
        if (!array_key_exists('references', $dsl)) {
100
            return false;
101
        }
102
103
        foreach ($dsl['references'] as $reference) {
104
            switch ($reference['attribute']) {
105
                case 'status_code':
106
                    $value = $response->getStatusCode();
107
                    break;
108
                case 'reason_phrase':
109
                    $value = $response->getReasonPhrase();
110
                    break;
111
                case 'protocol_version':
112
                    $value = $response->getProtocolVersion();
113
                    break;
114
                case 'body':
115
                    $value = $response->getBody()->__toString();
116
                    break;
117
                case 'body_size':
118
                    $value = $response->getBody()->getSize();
119
                    break;
120
                default:
121
                    throw new \InvalidArgumentException('HTTP executor does not support setting references for attribute ' . $reference['attribute']);
122
            }
123
124
            $overwrite = false;
125
            if (isset($reference['overwrite'])) {
126
                $overwrite = $reference['overwrite'];
127
            }
128
            $this->referenceResolver->addReference($reference['identifier'], $value, $overwrite);
129
        }
130
131
        return true;
132
    }
133
134
    /**
135
     * @todo should be moved into the reference resolver classes
136
     */
137
    protected function resolveReferencesRecursively($match)
138
    {
139
        if (is_array($match)) {
140
            foreach ($match as $condition => $values) {
141
                $match[$condition] = $this->resolveReferencesRecursively($values);
142
            }
143
            return $match;
144
        } else {
145
            return $this->referenceResolver->resolveReference($match);
146
        }
147
    }
148
149
    /**
150
     * Replaces any references inside a string
151
     *
152
     * @param string
153
     * @return string
154
     * @throws \Exception
155
     */
156
    protected function resolveReferencesInText($text)
157
    {
158
        return $this->referenceResolver->ResolveEmbeddedReferences($text);
159
    }
160
161
    protected function resolveReferencesInTextRecursively($textOrArray)
162
    {
163
        if (is_array($textOrArray)) {
164
            foreach ($textOrArray as $condition => $values) {
165
                $textOrArray[$condition] = $this->resolveReferencesInTextRecursively($values);
166
            }
167
            return $textOrArray;
168
        } else {
169
            return $this->resolveReferencesInText($textOrArray);
170
        }
171
    }
172
}
173