Completed
Push — master ( 5cec17...25ceca )
by Pascal
03:29 queued 12s
created

SetInfos::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 45
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.3645

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 45
ccs 2
cts 7
cp 0.2857
rs 8.8571
cc 1
eloc 15
nc 1
nop 0
crap 1.3645
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 12
        'icon'   => null,
50
    ];
51 12
52 12
    /**
53 12
     * Set Scraper
54 12
     * @param \MtGTutor\Console\Scraper $scraper
55
     */
56 12
    public function setScraper(Scraper $scraper)
57 12
    {
58 12
        $this->scraper = $scraper;
59 12
    }
60 12
61 12
    /**
62
     * Configure command
63
     */
64
    protected function configure()
65
    {
66
        // Sets the scraper
67
        $this->setScraper(new Scraper(new Client()));
68
69
        // Configure command
70
        $this->setName('set:info')
71
            ->addArgument(
72
                'set',
73
                InputArgument::REQUIRED,
74
                'Which set do you want to select. Use the official three-letter code.'
75
            )
76
            ->addOption('full-path', null, InputOption::VALUE_NONE, 'Add the full path to the images')
77
            ->addOption('date-format', null, InputOption::VALUE_OPTIONAL, 'Date Format', 'Y-m-d')
78
            ->addOption('json', null, InputOption::VALUE_NONE, 'Output result as json')
79
            ->setDescription('Get some basic information about a specific set')
80
            ->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 12
 * Logo
89 12
 * 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
            );
108
    }
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
    protected function execute(InputInterface $input, OutputInterface $output)
118
    {
119
        // init vars
120
        $this->data['code'] = $input->getArgument('set');
121
122
        // Fetch WotC website
123
        $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
            $logo = $node->attr('src');
127
128
            if ($this->setExists($logo)) {
129
                $this->exists = true;
130
131
                // Get Logo + Icon + Name
132
                $siblings = $node->parents()->first()->siblings();
133
134
                $this->data['logo'] = str_replace($this->imagePath, '', $logo);
135
                $this->data['icon'] = str_replace($this->imagePath, '', $siblings->eq(0)->children()->attr('src'));
136
                $this->data['name'] = trim($siblings->eq(1)->text());
137
138
                // go to next page
139
                $crawler = $this->crawlNextPage($node);
140
141
                // Fetch block, number of cards and release date
142
                $crawler->filter('.tab-content.current > p')->each(function (Crawler $node, $i) {
143
                    if ($i % 2) {
144
                        $this->fetchBlockCardsAndDate($node, $i);
145
                    }
146
                });
147
            }
148
        });
149
150
        // Could not find set
151
        if (!$this->exists) {
152
            throw new \InvalidArgumentException('Could not find set with the following code: ' . $this->data['code']);
153
        }
154
155
        // Format result
156
        $this->formatResult($input);
157
158
        // Ouput result
159
        $this->output($input, $output);
160
    }
161
162
    /**
163
     * @param string $url
164
     * @return bool|null
165
     */
166
    protected function setExists($url)
167
    {
168
        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
    protected function crawlNextPage(Crawler $crawler)
176
    {
177
        // Go to details page
178
        $link = $crawler->parents()->parents()->link();
179
        $crawler = $this->scraper->click($link);
180
181
        // Go to to info page (if exists)
182
        $anchor = $crawler->selectLink('Info');
183
        if ($anchor->count()) {
184
            $crawler = $this->scraper->click($anchor->link());
185
        }
186
187
        return $crawler;
188
    }
189
190
    /**
191
     * @param \Symfony\Component\DomCrawler\Crawler $node
192
     * @param integer                               $i
193
     */
194
    protected function fetchBlockCardsAndDate(Crawler $node, $i)
195
    {
196
        // Get block and number of cards
197
        if ($i == 1) {
198
            preg_match('~<strong>Block:<\\/strong>.*<em>(.+?)</~m', $node->html(), $block);
199
            preg_match('~<strong>Number of Cards:\s*<\/strong>[^\d]*(\d+)<?~m', $node->html(), $number);
200
201
            $this->data['block'] = $block[1];
202
            $this->data['number'] = (int) $number[1];
203
        }
204
205
        // get release date
206
        if ($i == 5) {
207
            preg_match('~<strong>Release Date:<\/strong>.+?([\w|,|\s]+)<~im', $node->html(), $release);
208
            $this->data['date'] = $release[1];
209
        }
210
    }
211
212
    /**
213
     * Format result
214
     * @param \Symfony\Component\Console\Input\InputInterface $input
215
     * @return void
216
     */
217
    protected function formatResult(InputInterface $input)
218
    {
219
        // change date format
220
        $date = new \DateTime(date('Y-m-d H:i:s', strtotime($this->data['date'])));
221
        $this->data['date'] = $date->format($input->getOption('date-format'));
222
223
        // add full path to url
224
        if ($input->getOption('full-path')) {
225
            $this->data['logo'] = $this->imagePath . $this->data['logo'];
226
            $this->data['icon'] = $this->imagePath . $this->data['icon'];
227
        }
228
    }
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
    protected function output(InputInterface $input, OutputInterface $output)
236
    {
237
        // json output
238
        if ($input->getOption('json')) {
239
            $output->writeln(json_encode($this->data, JSON_PRETTY_PRINT));
240
        }
241
242
        // table output
243
        if (!$input->getOption('json')) {
244
            $table = new Table($output);
245
            $table
246
                ->setHeaders(['Code', 'Name', 'Block', 'Number', 'Release Date', 'Logo', 'Icon'])
247
                ->setRows([$this->data]);
248
            $table->render();
249
        }
250
    }
251
}
252