Completed
Push — master ( 708efe...072588 )
by Nikola
04:22
created

FetchCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 13
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * This file is part of the Exchange Rate Bundle, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Bundle\ExchangeRate\Command;
11
12
use RunOpenCode\Bundle\ExchangeRate\Event\FetchEvents;
13
use RunOpenCode\Bundle\ExchangeRate\Exception\InvalidArgumentException;
14
use RunOpenCode\ExchangeRate\Contract\ManagerInterface;
15
use RunOpenCode\ExchangeRate\Contract\RateInterface;
16
use RunOpenCode\ExchangeRate\Contract\SourceInterface;
17
use RunOpenCode\ExchangeRate\Contract\SourcesRegistryInterface;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Style\SymfonyStyle;
23
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
24
use Symfony\Component\EventDispatcher\GenericEvent;
25
26
/**
27
 * Class FetchCommand
28
 *
29
 * Fetch rates from sources.
30
 *
31
 * @package RunOpenCode\Bundle\ExchangeRate\Command
32
 */
33
class FetchCommand extends Command
34
{
35
    /**
36
     * @var EventDispatcherInterface
37
     */
38
    protected $eventDispatcher;
39
40
    /**
41
     * @var ManagerInterface
42
     */
43
    protected $manager;
44
45
    /**
46
     * @var SourcesRegistryInterface
47
     */
48
    protected $sourcesRegistry;
49
50
    /**
51
     * @var SymfonyStyle
52
     */
53
    protected $output;
54
55
    public function __construct(EventDispatcherInterface $eventDispatcher, ManagerInterface $manager, SourcesRegistryInterface $sourcesRegistry)
56
    {
57
        parent::__construct();
58
        $this->eventDispatcher = $eventDispatcher;
59
        $this->manager = $manager;
60
        $this->sourcesRegistry = $sourcesRegistry;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    protected function configure()
67
    {
68
        $this
69
            ->setName('runopencode:exchange-rate:fetch')
70
            ->setAliases([
71
                'roc:exchange-rate:fetch'
72
            ])
73
            ->setDescription('Fetch exchange rates from sources.')
74
            ->addOption('date', 'd', InputOption::VALUE_OPTIONAL, 'State on which date exchange rates should be fetched.')
75
            ->addOption('source', 'src', InputOption::VALUE_OPTIONAL, 'State which sources should be contacted only, separated with comma.')
76
            ->addOption('silent', null, InputOption::VALUE_OPTIONAL, 'In silent mode, rates are fetched, but no event will be fired.', false)
77
        ;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    protected function execute(InputInterface $input, OutputInterface $output)
84
    {
85
        $this->output = new SymfonyStyle($input, $output);
86
87
        $date = (null !== $input->getOption('date')) ? $this->sanitizeDate($input->getOption('date')) : new \DateTime('now');
88
        $sources = $this->sanitizeSources($input->getOption('source'));
89
90
        $this->output->title(sprintf('Fetching rates for sources "%s" on "%s".', implode('", "', $sources), $date->format('Y-m-d')));
91
92
        $errors = false;
93
94
        foreach ($sources as $source) {
95
96
            try {
97
                $rates = $this->manager->fetch($source, $date);
98
99
                $rows = array_map(function(RateInterface $rate) {
100
                    return [
101
                        $rate->getCurrencyCode(),
102
                        $rate->getRateType(),
103
                        $rate->getValue(),
104
                    ];
105
                }, $rates);
106
107
                $this->output->section(sprintf('Fetched rates for source: "%s"', $source));
108
                $this->output->table(['Currency code', 'Rate type', 'Value'], $rows);
109
110 View Code Duplication
                if (!$input->getOption('silent')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
                    $this->eventDispatcher->dispatch(FetchEvents::SUCCESS, new GenericEvent($sources, ['rates' => $rates]));
112
                }
113
            } catch (\Exception $e) {
114
                $this->output->error(sprintf('Could not fetch rates from source "%s".', $source));
115
                $errors = true;
116
117 View Code Duplication
                if (!$input->getOption('silent')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
                    $this->eventDispatcher->dispatch(FetchEvents::ERROR, new GenericEvent($sources, ['exception' => $e]));
119
                }
120
            }
121
        }
122
        
123
        if ($errors) {
124
            $this->output->error('Could not fetch all rates.');
125
            return -1;
126
        }
127
128
        $this->output->success('Rates successfully fetched.');
129
        return 0;
130
    }
131
132
    /**
133
     * Sanitizes a date from console input.
134
     *
135
     * @param string|\DateTime $dateString A date
136
     *
137
     * @return \DateTime
138
     *
139
     * @throws InvalidArgumentException
140
     */
141
    protected function sanitizeDate($dateString)
142
    {
143
        if ($dateString instanceof \DateTime) {
144
            return $dateString;
145
        }
146
147
        $date = \DateTime::createFromFormat('Y-m-d', $dateString);
148
149
        if ($date instanceof \DateTime) {
150
            return $date;
151
        }
152
153
        $date = new \DateTime($dateString);
154
155
        if ($date instanceof \DateTime) {
156
            return $date;
157
        }
158
159
        throw new InvalidArgumentException(sprintf('Provided date "%s" is provided in unknown format. You should use "Y-m-d" instead.', $dateString));
160
    }
161
162
    /**
163
     * Clean sources from console input.
164
     *
165
     * @param mixed $sourcesString A sources.
166
     *
167
     * @return array|null
168
     *
169
     * @throws InvalidArgumentException
170
     */
171
    protected function sanitizeSources($sourcesString)
172
    {
173
        $sources = $sourcesString;
174
175
        if (is_string($sources)) {
176
            $sources = array_map('trim', explode(',', $sources));
177
        }
178
179
        if (null === $sources || (is_array($sources) && count($sources) === 0)) {
180
181
            return array_map(function(SourceInterface $source) {
182
                return $source->getName();
183
            }, $this->sourcesRegistry->all());
184
        }
185
186
        if (!is_array($sources) && !$sources instanceof \Traversable) {
187
            throw new InvalidArgumentException(sprintf('Expected collection of sources as string, \Traversable or array, got "%s".', is_object($sourcesString) ? get_class($sourcesString) : gettype($sourcesString)));
188
        }
189
190
        foreach ($sources as $source) {
191
            if (!$this->sourcesRegistry->has($source)) {
192
                throw new InvalidArgumentException(sprintf('Unknown source "%s" provided.', $source));
193
            }
194
        }
195
196
        return $sources;
197
    }
198
}
199