Passed
Pull Request — master (#9)
by mon
02:04
created

UpdateCommand::compareMaps()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
cc 3
nc 3
nop 3
1
<?php
2
3
namespace FileEye\MimeMap\Command;
4
5
use SebastianBergmann\Comparator\ComparisonFailure;
6
use SebastianBergmann\Comparator\Factory;
7
use SebastianBergmann\Diff\Differ;
8
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Yaml\Yaml;
14
use FileEye\MimeMap\Map\AbstractMap;
15
use FileEye\MimeMap\MapHandler;
16
use FileEye\MimeMap\MapUpdater;
17
18
/**
19
 * A Symfony application command to update the MIME type to extension map.
20
 */
21
class UpdateCommand extends Command
22
{
23
    /**
24
     * {@inheritdoc}
25
     */
26
    protected function configure()
27
    {
28
        $this
29
            ->setName('update')
30
            ->setDescription('Updates the MIME-type-to-extension map. Reads the source file specified by --source, applies any overrides specified in the file at --override, then writes the map to the PHP file where the PHP --class is defined.')
31
            ->addOption(
32
                'source',
33
                null,
34
                InputOption::VALUE_REQUIRED,
35
                'URL or filename of the source map',
36
                MapUpdater::DEFAULT_SOURCE_FILE
37
            )
38
            ->addOption(
39
                'override',
40
                null,
41
                InputOption::VALUE_REQUIRED,
42
                'URL or filename of the override commands to execute',
43
                MapUpdater::getDefaultOverrideFile()
44
            )
45
            ->addOption(
46
                'class',
47
                null,
48
                InputOption::VALUE_REQUIRED,
49
                'The Fully Qualified Class Name of the PHP class storing the map',
50
                MapHandler::DEFAULT_MAP_CLASS
51
            )
52
        ;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    protected function execute(InputInterface $input, OutputInterface $output)
59
    {
60
        MapHandler::setDefaultMapClass($input->getOption('class'));
61
        $current_map = MapHandler::map();
62
        $updater = new MapUpdater();
63
64
        // Loads the map from the source file.
65
        try {
66
            $new_map = $updater->createMapFromSourceFile($input->getOption('source'));
67
        } catch (\RuntimeException $e) {
68
            $output->writeln('<error>' . $e->getMessage() . '</error>');
69
            exit(2);
70
        }
71
72
        // Applies the overrides.
73
        try {
74
            $content = file_get_contents($input->getOption('override'));
75
            $updater->applyOverrides($new_map, Yaml::parse($content));
76
        } catch (\Exception $e) {
77
            $output->writeln('<error>' . $e->getMessage() . '</error>');
78
            exit(2);
79
        }
80
81
        // Check if anything got changed.
82
        $write = false;
83
        try {
84
            $this->compareMaps($current_map, $new_map, 'types');
85
        } catch (\RuntimeException $e) {
86
            $output->writeln('<comment>Changes to MIME types mapping</comment>');
87
            $output->writeln($e->getMessage());
88
            $write = true;
89
        }
90
        try {
91
            $this->compareMaps($current_map, $new_map, 'extensions');
92
        } catch (\RuntimeException $e) {
93
            $output->writeln('<comment>Changes to extensions mapping</comment>');
94
            $output->writeln($e->getMessage());
95
            $write = true;
96
        }
97
98
        // If changed, save the new map to the PHP file.
99
        if ($write) {
100
            $updater->writeMapToPhpClassFile($new_map, $current_map->getFileName());
101
            $output->writeln('<comment>Code updated.</comment>');
102
        } else {
103
            $output->writeln('<info>No changes to mapping.</info>');
104
        }
105
106
        // Reset the new map's map array.
107
        $new_map->reset();
108
    }
109
110
    /**
111
     * Compares two type-to-extension maps by section.
112
     *
113
     * @param AbstractMap $old_map
114
     *   The first map to compare.
115
     * @param AbstractMap $new_map
116
     *   The second map to compare.
117
     * @param string $section
118
     *   The first-level array key to compare: 'types' or 'extensions'.
119
     *
120
     * @throws \RuntimeException with diff details if the maps differ.
121
     *
122
     * @return bool
123
     *   True if the maps are equal.
124
     */
125
    protected function compareMaps(AbstractMap $old_map, AbstractMap $new_map, $section)
126
    {
127
        $old_map->sort();
128
        $new_map->sort();
129
        $old = $old_map->getMapArray();
130
        $new = $new_map->getMapArray();
131
132
        $factory = new Factory;
133
        $comparator = $factory->getComparatorFor($old[$section], $new[$section]);
134
        try {
135
            $comparator->assertEquals($old[$section], $new[$section]);
136
            return true;
137
        } catch (ComparisonFailure $failure) {
138
            $old_string = var_export($old[$section], true);
139
            $new_string = var_export($new[$section], true);
140
            if (class_exists('\SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder')) {
141
                $differ = new Differ(new UnifiedDiffOutputBuilder("--- Removed\n+++ Added\n"));
142
                throw new \RuntimeException($differ->diff($old_string, $new_string));
143
            } else {
144
                throw new \RuntimeException(' ');
145
            }
146
        }
147
    }
148
}
149