1 | <?php |
||
37 | class ImportCommand extends ImportCommandAbstract |
||
38 | { |
||
39 | /** |
||
40 | * @var HttpClient |
||
41 | */ |
||
42 | private $client; |
||
43 | |||
44 | /** |
||
45 | * @var FrontMatter |
||
46 | */ |
||
47 | private $frontMatter; |
||
48 | |||
49 | /** |
||
50 | * @var Parser |
||
51 | */ |
||
52 | private $parser; |
||
53 | |||
54 | /** |
||
55 | * @var VarCloner |
||
56 | */ |
||
57 | private $cloner; |
||
58 | |||
59 | /** |
||
60 | * @var Dumper |
||
61 | */ |
||
62 | private $dumper; |
||
63 | |||
64 | /** |
||
65 | * Count of errors |
||
66 | * @var array |
||
67 | */ |
||
68 | private $errors = []; |
||
69 | |||
70 | /** |
||
71 | 5 | * @param HttpClient $client Grv HttpClient guzzle http client |
|
72 | * @param Finder $finder symfony/finder instance |
||
73 | * @param FrontMatter $frontMatter frontmatter parser |
||
74 | * @param Parser $parser yaml/json parser |
||
75 | * @param VarCloner $cloner var cloner for dumping reponses |
||
76 | * @param Dumper $dumper dumper for outputing responses |
||
77 | */ |
||
78 | public function __construct( |
||
79 | 5 | HttpClient $client, |
|
80 | Finder $finder, |
||
81 | 5 | FrontMatter $frontMatter, |
|
82 | 5 | Parser $parser, |
|
83 | 5 | VarCloner $cloner, |
|
84 | 5 | Dumper $dumper |
|
85 | 5 | ) { |
|
86 | 5 | parent::__construct( |
|
87 | 5 | $finder |
|
88 | ); |
||
89 | $this->client = $client; |
||
90 | $this->frontMatter = $frontMatter; |
||
91 | $this->parser = $parser; |
||
92 | $this->cloner = $cloner; |
||
93 | $this->dumper = $dumper; |
||
94 | 5 | } |
|
95 | |||
96 | 5 | /** |
|
97 | 5 | * Configures the current command. |
|
98 | 5 | * |
|
99 | 5 | * @return void |
|
100 | 5 | */ |
|
101 | 5 | protected function configure() |
|
137 | |||
138 | /** |
||
139 | * Executes the current command. |
||
140 | 5 | * |
|
141 | * @param Finder $finder Finder |
||
142 | 5 | * @param InputInterface $input User input on console |
|
143 | 5 | * @param OutputInterface $output Output of the command |
|
144 | 5 | * |
|
145 | 5 | * @return void |
|
146 | 5 | */ |
|
147 | 5 | protected function doImport(Finder $finder, InputInterface $input, OutputInterface $output) |
|
148 | 5 | { |
|
149 | $host = $input->getArgument('host'); |
||
150 | 5 | $rewriteHost = $input->getOption('rewrite-host'); |
|
151 | 4 | $rewriteTo = $input->getOption('rewrite-to'); |
|
152 | if ($rewriteTo === $this->getDefinition()->getOption('rewrite-to')->getDefault()) { |
||
153 | $rewriteTo = $host; |
||
154 | } |
||
155 | $sync = $input->getOption('sync-requests'); |
||
156 | |||
157 | $this->importPaths($finder, $output, $host, $rewriteHost, $rewriteTo, $sync); |
||
158 | |||
159 | // Error exit |
||
160 | if (empty($this->errors)) { |
||
161 | // No errors |
||
162 | $output->writeln("\n".'<info>No errors</info>'); |
||
163 | $output->writeln('0'); |
||
164 | exit(0); |
||
165 | 5 | } else { |
|
166 | // Yes, there was errors |
||
167 | $output->writeln("\n".'<info>There was errors: '.count($this->errors).'</info>'); |
||
168 | foreach ($this->errors as $file => $error) { |
||
169 | $output->writeln("<error>{$file}: {$error}</error>"); |
||
170 | } |
||
171 | $output->writeln('1'); |
||
172 | exit(1); |
||
173 | 5 | } |
|
174 | 5 | } |
|
175 | 5 | ||
176 | /** |
||
177 | 5 | * @param Finder $finder finder primmed with files to import |
|
178 | * @param OutputInterface $output output interfac |
||
179 | 5 | * @param string $host host to import into |
|
180 | 1 | * @param string $rewriteHost string to replace with value from $rewriteTo during loading |
|
181 | * @param string $rewriteTo string to replace value from $rewriteHost with during loading |
||
182 | * @param boolean $sync send requests syncronously |
||
183 | 4 | * |
|
184 | * @return void |
||
185 | 4 | * |
|
186 | 4 | * @throws MissingTargetException |
|
187 | 4 | */ |
|
188 | 4 | protected function importPaths( |
|
189 | 4 | Finder $finder, |
|
190 | 4 | OutputInterface $output, |
|
191 | 4 | $host, |
|
192 | 4 | $rewriteHost, |
|
193 | $rewriteTo, |
||
194 | 4 | $sync = false |
|
195 | 4 | ) { |
|
196 | $promises = []; |
||
197 | /** @var SplFileInfo $file */ |
||
198 | foreach ($finder as $file) { |
||
199 | $doc = $this->frontMatter->parse($file->getContents()); |
||
200 | |||
201 | $output->writeln("<info>Loading data from ${file}</info>"); |
||
202 | |||
203 | if (!array_key_exists('target', $doc->getData())) { |
||
204 | throw new MissingTargetException('Missing target in \'' . $file . '\''); |
||
205 | } |
||
206 | |||
207 | $targetUrl = sprintf('%s%s', $host, $doc->getData()['target']); |
||
208 | |||
209 | $promises[] = $this->importResource( |
||
210 | $targetUrl, |
||
211 | (string) $file, |
||
212 | $output, |
||
213 | $doc, |
||
214 | $rewriteHost, |
||
215 | $rewriteTo, |
||
216 | $sync |
||
217 | ); |
||
218 | } |
||
219 | |||
220 | try { |
||
221 | Promise\unwrap($promises); |
||
222 | } catch (ClientException $e) { |
||
223 | // silently ignored since we already output an error when the promise fails |
||
224 | } |
||
225 | } |
||
226 | 4 | ||
227 | 4 | /** |
|
228 | * @param string $targetUrl target url to import resource into |
||
229 | * @param string $file path to file being loaded |
||
230 | 3 | * @param OutputInterface $output output of the command |
|
231 | 3 | * @param Document $doc document to load |
|
232 | 3 | * @param string $rewriteHost string to replace with value from $host during loading |
|
233 | 4 | * @param string $rewriteTo string to replace value from $rewriteHost with during loading |
|
234 | * @param boolean $sync send requests syncronously |
||
235 | * |
||
236 | 1 | * @return Promise\Promise|null |
|
237 | 1 | */ |
|
238 | 1 | protected function importResource( |
|
239 | 1 | $targetUrl, |
|
240 | 1 | $file, |
|
241 | 1 | OutputInterface $output, |
|
242 | 1 | Document $doc, |
|
243 | 1 | $rewriteHost, |
|
244 | 1 | $rewriteTo, |
|
245 | $sync = false |
||
246 | 1 | ) { |
|
247 | 1 | $content = str_replace($rewriteHost, $rewriteTo, $doc->getContent()); |
|
248 | 1 | $uploadFile = $this->validateUploadFile($doc, $file); |
|
249 | 1 | ||
250 | 1 | $successFunc = function (ResponseInterface $response) use ($output) { |
|
251 | 1 | $output->writeln( |
|
252 | 1 | '<comment>Wrote ' . $response->getHeader('Link')[0] . '</comment>' |
|
253 | ); |
||
254 | 1 | }; |
|
255 | 1 | ||
256 | 1 | $errFunc = function (RequestException $e) use ($output, $file) { |
|
257 | 1 | $this->errors[$file] = $e->getMessage(); |
|
258 | 1 | $output->writeln( |
|
259 | 1 | '<error>' . str_pad( |
|
260 | 1 | sprintf( |
|
261 | 1 | 'Failed to write <%s> from \'%s\' with message \'%s\'', |
|
262 | 4 | $e->getRequest()->getUri(), |
|
263 | $file, |
||
264 | 4 | $e->getMessage() |
|
265 | 4 | ), |
|
266 | 4 | 140, |
|
267 | 4 | ' ' |
|
268 | ) . '</error>' |
||
269 | 4 | ); |
|
270 | if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { |
||
271 | 4 | $this->dumper->dump( |
|
272 | 4 | $this->cloner->cloneVar( |
|
273 | 4 | $this->parser->parse($e->getResponse()->getBody(), false, false, true) |
|
274 | 4 | ), |
|
275 | function ($line, $depth) use ($output) { |
||
276 | if ($depth > 0) { |
||
277 | $output->writeln( |
||
278 | '<error>' . str_pad(str_repeat(' ', $depth) . $line, 140, ' ') . '</error>' |
||
279 | ); |
||
280 | } |
||
281 | } |
||
282 | ); |
||
283 | } |
||
284 | }; |
||
285 | |||
286 | $data = [ |
||
287 | 'json' => $this->parseContent($content, $file), |
||
288 | 'upload' => $uploadFile |
||
289 | ]; |
||
290 | $promise = $this->client->requestAsync( |
||
291 | 'PUT', |
||
292 | $targetUrl, |
||
293 | $data |
||
294 | ); |
||
295 | 4 | ||
296 | // If there is a file to be uploaded, and it exists in remote, we delete it first. |
||
297 | // TODO This part, $uploadFile, promise should be removed once Graviton/File service is resolved in new Story. |
||
298 | $fileRepeatFunc = false; |
||
299 | if ($uploadFile) { |
||
|
|||
300 | $fileRepeatFunc = function () use ($targetUrl, $successFunc, $errFunc, $output, $file, $data) { |
||
301 | unset($this->errors[$file]); |
||
302 | $output->writeln('<info>File deleting: '.$targetUrl.'</info>'); |
||
303 | $deleteRequest = $this->client->requestAsync('DELETE', $targetUrl); |
||
304 | $insert = function () use ($targetUrl, $successFunc, $errFunc, $output, $data) { |
||
305 | $output->writeln('<info>File inserting: '.$targetUrl.'</info>'); |
||
306 | $promiseInsert = $this->client->requestAsync('PUT', $targetUrl, $data); |
||
307 | $promiseInsert->then($successFunc, $errFunc); |
||
308 | 4 | }; |
|
309 | 3 | $deleteRequest |
|
310 | 3 | ->then($insert, $errFunc)->wait(); |
|
311 | }; |
||
312 | } |
||
313 | |||
314 | $promiseError = $fileRepeatFunc ? $fileRepeatFunc : $errFunc; |
||
315 | if ($sync) { |
||
316 | $promise->then($successFunc, $promiseError)->wait(); |
||
317 | } else { |
||
318 | $promise->then($successFunc, $promiseError); |
||
319 | 4 | } |
|
320 | 1 | ||
321 | 1 | ||
322 | |||
323 | return $promise; |
||
324 | } |
||
325 | 4 | ||
326 | /** |
||
327 | * parse contents of a file depending on type |
||
328 | * |
||
329 | * @param string $content contents part of file |
||
330 | * @param string $file full path to file |
||
331 | * |
||
332 | * @return mixed |
||
333 | * @throws UnknownFileTypeException |
||
334 | * @throws JsonParseException |
||
335 | */ |
||
336 | protected function parseContent($content, $file) |
||
337 | 4 | { |
|
338 | if (substr($file, -5) == '.json') { |
||
339 | 4 | $data = json_decode($content); |
|
340 | 3 | if (json_last_error() !== JSON_ERROR_NONE) { |
|
341 | throw new JsonParseException( |
||
342 | sprintf( |
||
343 | '%s in %s', |
||
344 | 1 | json_last_error_msg(), |
|
345 | 1 | $file |
|
346 | 1 | ) |
|
347 | ); |
||
348 | } |
||
349 | } elseif (substr($file, -4) == '.yml') { |
||
350 | 1 | $data = $this->parser->parse($content); |
|
351 | } else { |
||
352 | throw new UnknownFileTypeException($file); |
||
353 | } |
||
354 | |||
355 | return $data; |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * Checks if file exists and return qualified fileName location |
||
360 | * |
||
361 | * @param Document $doc Data source for import data |
||
362 | * @param string $originFile Original full filename used toimport |
||
363 | * @return bool|mixed |
||
364 | */ |
||
365 | private function validateUploadFile(Document $doc, $originFile) |
||
382 | } |
||
383 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: