Passed
Push — master ( 6c8cca...faca34 )
by Gaetano
05:35
created

ReferenceExecutor::dumpVar()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 19
ccs 0
cts 0
cp 0
crap 12
rs 9.9666
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Kaliop\eZMigrationBundle\API\EnumerableReferenceResolverInterface;
6
use Kaliop\eZMigrationBundle\API\Exception\InvalidStepDefinitionException;
7
use Kaliop\eZMigrationBundle\API\ReferenceResolverBagInterface;
8
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Symfony\Component\DependencyInjection\ContainerInterface;
11
use Symfony\Component\VarDumper\Cloner\VarCloner;
12
use Symfony\Component\VarDumper\Dumper\CliDumper;
13
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
14
use Symfony\Component\Yaml\Yaml;
15
16
class ReferenceExecutor extends AbstractExecutor
17
{
18
    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...cutor\ReferenceExecutor.
Loading history...
19
20
    protected $supportedStepTypes = array('reference');
21
    protected $supportedActions = array('set', 'load', 'save', 'dump');
22
23
    protected $container;
24 96
    /** @var ReferenceResolverBagInterface $referenceResolver */
25
    protected $referenceResolver;
26 96
27 96
    public function __construct(ContainerInterface $container, ReferenceResolverBagInterface $referenceResolver)
28 96
    {
29
        $this->container = $container;
30
        $this->referenceResolver = $referenceResolver;
31
    }
32
33
    /**
34
     * @param MigrationStep $step
35 18
     * @return mixed
36
     * @throws \Exception
37 18
     */
38
    public function execute(MigrationStep $step)
39 18
    {
40
        parent::execute($step);
41
42
        if (!isset($step->dsl['mode'])) {
43 18
            throw new InvalidStepDefinitionException("Invalid step definition: missing 'mode'");
44
        }
45 18
46
        $action = $step->dsl['mode'];
47
48
        if (!in_array($action, $this->supportedActions)) {
49 18
            throw new InvalidStepDefinitionException("Invalid step definition: value '$action' is not allowed for 'mode'");
50
        }
51 18
52
        $this->skipStepIfNeeded($step);
53
54 18
        return $this->$action($step->dsl, $step->context);
55
    }
56 18
57
    protected function set($dsl, $context)
58
    {
59 18
        if (!isset($dsl['identifier'])) {
60
            throw new InvalidStepDefinitionException("Invalid step definition: miss 'identifier' for setting reference");
61
        }
62
        if (!isset($dsl['value'])) {
63 18
            throw new InvalidStepDefinitionException("Invalid step definition: miss 'value' for setting reference");
64
        }
65 18
66
        if (!isset($dsl['resolve_references']) || $dsl['resolve_references']) {
67 1
            // this makes sense since we started supporting embedded refs...
68
            $value = $this->referenceResolver->resolveReference($dsl['value']);
69
        } else {
70 18
            $value = $dsl['value'];
71 18
        }
72
73 18
        if (0 === strpos($value, '%env(') && ')%' === substr($value, -2) && '%env()%' !== $value) {
74
            /// @todo find out how to use Sf components to resolve this value instead of doing it by ourselves...
75
            $env = substr($value, 5, -2);
76 1
            // we use getenv because $_ENV gets cleaned up (by whom?)
77
            $val = getenv($env);
78 1
            if ($val === false) {
79
                throw new \Exception("Env var $env seems not to be defined");
80
            }
81 1
            $value = $val;
82 1
        } else {
83
            /// @todo add support for eZ dynamic parameters too
84 1
85
            if (preg_match('/.*%.+%.*$/', $value)) {
86 1
                // we use the same parameter resolving rule as symfony, even though this means abusing the ContainerInterface
87 1
                $value = $this->container->getParameterBag()->resolveString($value);
0 ignored issues
show
Bug introduced by
The method getParameterBag() does not exist on Symfony\Component\Depend...tion\ContainerInterface. Did you maybe mean getParameter()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
                $value = $this->container->/** @scrutinizer ignore-call */ getParameterBag()->resolveString($value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
88
            }
89
        }
90 1
91
        $overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false;
0 ignored issues
show
Unused Code introduced by
The assignment to $overwrite is dead and can be removed.
Loading history...
92
        $this->referenceResolver->addReference($dsl['identifier'], $value, $overwrite);
93 1
94
        return $value;
95 1
    }
96
97 1
    protected function load($dsl, $context)
98
    {
99
        if (!isset($dsl['file'])) {
100 1
            throw new InvalidStepDefinitionException("Invalid step definition: miss 'file' for loading references");
101
        }
102 1
        $fileName = $this->referenceResolver->resolveReference($dsl['file']);
103 1
        $fileName = str_replace('{ENV}', $this->container->get('kernel')->getEnvironment(), $fileName);
104
105
        $overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false;
0 ignored issues
show
Unused Code introduced by
The assignment to $overwrite is dead and can be removed.
Loading history...
106
107
        if (!is_file($fileName) && is_file(dirname($context['path']) . '/references/' . $fileName)) {
108 1
            $fileName = dirname($context['path']) . '/references/' . $fileName;
109
        }
110
111
        if (!is_file($fileName)) {
112 1
            throw new InvalidStepDefinitionException("Invalid step definition: invalid file '$fileName' for loading references");
113 1
        }
114
        $data = file_get_contents($fileName);
115
116
        $ext = pathinfo($fileName, PATHINFO_EXTENSION);
117 1
        switch ($ext) {
118 1
            case 'json':
119
                $data = json_decode($data, true);
120
                break;
121
            case 'yml':
122 1
            case 'yaml':
123
                $data = Yaml::parse($data);
124
                break;
125
            default:
126
                throw new InvalidStepDefinitionException("Invalid step definition: unsupported file extension '$ext' for loading references from");
127
        }
128 1
129
        if (!is_array($data)) {
130 1
            throw new \Exception("Invalid step definition: file does not contain an array of key/value pairs");
131
        }
132
133 1
        foreach ($data as $refName => $value) {
134 1
            if (preg_match('/%.+%$/', $value)) {
135
                $value = $this->container->getParameter(trim($value, '%'));
136 1
            }
137
138 1
            if (!$this->referenceResolver->addReference($refName, $value, $overwrite)) {
139
                throw new \Exception("Failed adding to Reference Resolver the reference: $refName");
140
            }
141
        }
142 1
143
        return $data;
144
    }
145
146 1
    /**
147
     * @todo find a smart way to allow saving the references file next to the current migration
148 1
     */
149
    protected function save($dsl, $context)
150 1
    {
151
        if (!isset($dsl['file'])) {
152
            throw new InvalidStepDefinitionException("Invalid step definition: miss 'file' for saving references");
153 1
        }
154
        $fileName = $this->referenceResolver->resolveReference($dsl['file']);
155 1
        $fileName = str_replace('{ENV}', $this->container->get('kernel')->getEnvironment(), $fileName);
156 1
157
        $overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false;
0 ignored issues
show
Unused Code introduced by
The assignment to $overwrite is dead and can be removed.
Loading history...
158
159
        if (is_file($fileName) && !$overwrite) {
160
            throw new \Exception("Invalid step definition: file '$fileName' for saving references already exists");
161 1
        }
162
163 1
        if (! $this->referenceResolver instanceof EnumerableReferenceResolverInterface) {
164
            throw new \Exception("Can not save references as resolver is not enumerable");
165
        }
166 10
167
        $data = $this->referenceResolver->listReferences();
168 10
169
        $ext = pathinfo($fileName, PATHINFO_EXTENSION);
170
        switch ($ext) {
171 10
            case 'json':
172
                $data = json_encode($data, JSON_PRETTY_PRINT);
173
                break;
174 10
            case 'yml':
175 1
            case 'yaml':
176
            /// @todo use Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE option if it is supported
177 10
                $data = Yaml::dump($data);
178
                break;
179 10
            default:
180 10
                throw new InvalidStepDefinitionException("Invalid step definition: unsupported file extension '$ext' for saving references to");
181
        }
182 10
183
        file_put_contents($fileName, $data);
184
185
        return $data;
186
    }
187
188
    protected function dump($dsl, $context)
189
    {
190
        if (!isset($dsl['identifier'])) {
191
            throw new InvalidStepDefinitionException("Invalid step definition: miss 'identifier' for dumping reference");
192
        }
193
        if (!$this->referenceResolver->isReference($dsl['identifier'])) {
194
            throw new \Exception("Invalid step definition: identifier '{$dsl['identifier']}' is not a reference");
195
        }
196
        if (isset($context['output']) && $context['output'] instanceof OutputInterface && $context['output']->isQuiet()) {
197
            return $this->referenceResolver->resolveReference($dsl['identifier']);
198
        }
199
200
        if (isset($dsl['label'])) {
201
            $label = $dsl['label'];
202
        } else {
203
            $label = $this->dumpVar($dsl['identifier']);
204
        }
205
        $value = $this->dumpVar($this->referenceResolver->resolveReference($dsl['identifier']));
206
207
        if (isset($context['output']) && $context['output'] instanceof OutputInterface) {
208
            $context['output']->write($label . $value, false, OutputInterface::OUTPUT_RAW|OutputInterface::VERBOSITY_NORMAL);
209
        } else {
210
            echo $label . $value;
211
        }
212
213
        return $value;
214
    }
215
216
    /**
217
     * Similar to VarDumper::dump(), but returns the output
218
     * @param mixed $var
219
     * @return string
220
     * @throws \ErrorException
221
     */
222
    protected function dumpVar($var)
223
    {
224
        $cloner = new VarCloner();
225
        $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper();
226
        $output = '';
227
228
        $dumper->dump(
229
            $cloner->cloneVar($var),
230
            function ($line, $depth) use (&$output) {
231
                // A negative depth means "end of dump"
232
                if ($depth >= 0) {
233
                    // Adds a two spaces indentation to the line
234
                    /// @todo should we use NBSP for html dumping?
235
                    $output .= str_repeat('  ', $depth) . $line . "\n";
236
                }
237
            }
238
        );
239
240
        return $output;
241
    }
242
}
243