SetInfos::output()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 16
ccs 11
cts 11
cp 1
rs 9.4286
cc 3
eloc 9
nc 4
nop 2
crap 3
1
<?php namespace MtGTutor\Console\Commands;
2
3
use MtGTutor\Console\Scraper;
4
use Goutte\Client;
5
use Symfony\Component\Console\Command\Command;
6
use Symfony\Component\Console\Helper\Table;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\DomCrawler\Crawler;
12
13
/**
14
 * Class SetInfos
15
 * @package MtGTutor\Console\Commands
16
 */
17
class SetInfos extends Command
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $url = 'http://magic.wizards.com/en/game-info/products/card-set-archive';
23
24
    /**
25
     * @var string
26
     */
27
    protected $imagePath = 'http://magic.wizards.com/sites/mtg/files/';
28
29
    /**
30
     * @var bool
31
     */
32
    protected $exists = false;
33
34
    /**
35
     * @var \MtGTutor\Console\Scraper
36
     */
37
    protected $scraper;
38
39
    /**
40
     * @var array
41
     */
42
    protected $data = [
43
        'code'   => null,
44
        'name'   => null,
45
        'block'  => null,
46
        'number' => null,
47
        'date'   => null,
48
        'logo'   => null,
49
        'icon'   => null,
50
    ];
51
52
    /**
53
     * Set Scraper
54
     * @param \MtGTutor\Console\Scraper $scraper
55
     */
56 24
    public function setScraper(Scraper $scraper)
57 3
    {
58 24
        $this->scraper = $scraper;
59 24
    }
60
61
    /**
62
     * Configure command
63
     */
64 24
    protected function configure()
65
    {
66
        // Sets the scraper
67 24
        $this->setScraper(new Scraper(new Client()));
68
69
        // Configure command
70 24
        $this->setName('set:info')
71 24
            ->addArgument(
72 24
                'set',
73 24
                InputArgument::REQUIRED,
74
                'Which set do you want to select. Use the official three-letter code.'
75 24
            )
76 24
            ->addOption('full-path', null, InputOption::VALUE_NONE, 'Add the full path to the images')
77 24
            ->addOption('date-format', null, InputOption::VALUE_OPTIONAL, 'Date Format', 'Y-m-d')
78 24
            ->addOption('json', null, InputOption::VALUE_NONE, 'Output result as json')
79 24
            ->setDescription('Get some basic information about a specific set')
80 24
            ->setHelp(
81
                <<<EOT
82
Gets the following information about a set:
83
 * Official Three-Letter Code
84
 * Set Name
85
 * Block
86
 * Number of Cards
87
 * Release Date
88
 * Logo
89
 * Icon
90
91
Usage:
92
Default usage to get a set (here Alara Reborn)
93
<info>mtgtutor-console set:info ARB</info>
94
95
You can specify a date format via the --date-format option
96
<info>mtgtutor-console set:info ARB --date-format=d.m.Y</info>
97
98
You can change the output format to json with the --json option
99
<info>mtgtutor-console set:info ARB --json</info>
100
101
You can add the full path to the files with --full-path
102
<info>mtgtutor-console set:info ARB --full-path</info>
103
104
You can combine all these options
105
<info>mtgtutor-console set:info ARB --date-format=d.m.Y --json --full-path</info>
106
EOT
107 24
            );
108 24
    }
109
110
    /**
111
     * Get set infos
112
     * @throws \InvalidArgumentException if no set is found
113
     * @param \Symfony\Component\Console\Input\InputInterface   $input
114
     * @param \Symfony\Component\Console\Output\OutputInterface $output
115
     * @return void
116
     */
117 12
    protected function execute(InputInterface $input, OutputInterface $output)
118
    {
119
        // init vars
120 12
        $this->data['code'] = $input->getArgument('set');
121
122
        // Fetch WotC website
123 12
        $crawler = $this->scraper->request($this->url);
124
125
        $crawler->filter('.card-set-archive-table > ul > li > a > span.logo > img')->each(function (Crawler $node) {
126 12
            $logo = $node->attr('src');
127
128 12
            if ($this->setExists($logo)) {
129 9
                $this->exists = true;
130
131
                // Get Logo + Icon + Name
132 9
                $siblings = $node->parents()->first()->siblings();
133
134 9
                $this->data['logo'] = str_replace($this->imagePath, '', $logo);
135 9
                $this->data['icon'] = str_replace($this->imagePath, '', $siblings->eq(0)->children()->attr('src'));
136 9
                $this->data['name'] = trim($siblings->eq(1)->text());
137
138
                // go to next page
139 9
                $crawler = $this->crawlNextPage($node);
140
141
                // Fetch block, number of cards and release date
142 9
                $crawler->filter('.tab-content.current > p')->each(function (Crawler $node, $i) {
143 9
                    if ($i % 2) {
144 9
                        $this->fetchBlockCardsAndDate($node, $i);
145 9
                    }
146 9
                });
147 9
            }
148 12
        });
149
150
        // Could not find set
151 12
        if (!$this->exists) {
152 3
            throw new \InvalidArgumentException('Could not find set with the following code: ' . $this->data['code']);
153
        }
154
155
        // Format result
156 9
        $this->formatResult($input);
157
158
        // Ouput result
159 9
        $this->output($input, $output);
160 9
    }
161
162
    /**
163
     * @param string $url
164
     * @return bool|null
165
     */
166 12
    protected function setExists($url)
167
    {
168 12
        return strpos(strtolower($url), strtolower($this->data['code'])) !== false;
169
    }
170
171
    /**
172
     * @param \Symfony\Component\DomCrawler\Crawler $crawler
173
     * @return \Symfony\Component\DomCrawler\Crawler
174
     */
175 9
    protected function crawlNextPage(Crawler $crawler)
176
    {
177
        // Go to details page
178 9
        $link = $crawler->parents()->parents()->link();
179 9
        $crawler = $this->scraper->click($link);
180
181
        // Go to to info page (if exists)
182 9
        $anchor = $crawler->selectLink('Info');
183 9
        if ($anchor->count()) {
184 3
            $crawler = $this->scraper->click($anchor->link());
185 3
        }
186
187 9
        return $crawler;
188
    }
189
190
    /**
191
     * @param \Symfony\Component\DomCrawler\Crawler $node
192
     * @param integer                               $i
193
     */
194 9
    protected function fetchBlockCardsAndDate(Crawler $node, $i)
195
    {
196
        // Get block and number of cards
197 9
        if ($i == 1) {
198 9
            preg_match('~<strong>Block:<\\/strong>.*<em>(.+?)</~m', $node->html(), $block);
199 9
            preg_match('~<strong>Number of Cards:\s*<\/strong>[^\d]*(\d+)<?~m', $node->html(), $number);
200
201 9
            $this->data['block'] = $block[1];
202 9
            $this->data['number'] = (int) $number[1];
203 9
        }
204
205
        // get release date
206 9
        if ($i == 5) {
207 3
            preg_match('~<strong>Release Date:<\/strong>.+?([\w|,|\s]+)<~im', $node->html(), $release);
208 3
            $this->data['date'] = $release[1];
209 3
        }
210 9
    }
211
212
    /**
213
     * Format result
214
     * @param \Symfony\Component\Console\Input\InputInterface $input
215
     * @return void
216
     */
217 9
    protected function formatResult(InputInterface $input)
218
    {
219
        // change date format
220 9
        $date = new \DateTime(date('Y-m-d H:i:s', strtotime($this->data['date'])));
221 9
        $this->data['date'] = $date->format($input->getOption('date-format'));
222
223
        // add full path to url
224 9
        if ($input->getOption('full-path')) {
225 3
            $this->data['logo'] = $this->imagePath . $this->data['logo'];
226 3
            $this->data['icon'] = $this->imagePath . $this->data['icon'];
227 3
        }
228 9
    }
229
230
    /**
231
     * Write result to console
232
     * @param \Symfony\Component\Console\Input\InputInterface   $input
233
     * @param \Symfony\Component\Console\Output\OutputInterface $output
234
     */
235 9
    protected function output(InputInterface $input, OutputInterface $output)
236
    {
237
        // json output
238 9
        if ($input->getOption('json')) {
239 3
            $output->writeln(json_encode($this->data, JSON_PRETTY_PRINT));
240 3
        }
241
242
        // table output
243 9
        if (!$input->getOption('json')) {
244 6
            $table = new Table($output);
245
            $table
246 6
                ->setHeaders(['Code', 'Name', 'Block', 'Number', 'Release Date', 'Logo', 'Icon'])
247 6
                ->setRows([$this->data]);
248 6
            $table->render();
249 6
        }
250 9
    }
251
}
252