Completed
Push — master ( 355dae...6d9195 )
by WEBEWEB
19:50
created

UnzipAssetsCommand::displayResult()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.5066
c 0
b 0
f 0
cc 7
nc 6
nop 2
1
<?php
2
3
/**
4
 * This file is part of the core-bundle package.
5
 *
6
 * (c) 2018 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WBW\Bundle\CoreBundle\Command;
13
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Console\Style\SymfonyStyle;
18
use WBW\Bundle\CoreBundle\Helper\AssetsHelper;
19
use WBW\Bundle\CoreBundle\Provider\AssetsProviderInterface;
20
21
/**
22
 * Unzip assets command.
23
 *
24
 * @author webeweb <https://github.com/webeweb/>
25
 * @package WBW\Bundle\CoreBundle\Command
26
 */
27
class UnzipAssetsCommand extends Command {
28
29
    /**
30
     * Command help.
31
     *
32
     * @var string
33
     */
34
    const COMMAND_HELP = <<< 'EOT'
35
The <info>%command.name%</info> command unzips bundle assets into a given
36
directory (e.g. the <comment>public</comment> directory).
37
38
    <info>php %command.full_name% public</info>
39
40
EOT;
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    protected function configure() {
46
        $this
47
            ->setName("wbw:core:unzip-assets")
48
            ->setDescription("Unzip assets under a public directory")
49
            ->setHelp(self::COMMAND_HELP);
50
    }
51
52
    /**
53
     * Display the footer.
54
     *
55
     * @param SymfonyStyle $io The I/O.
56
     * @param int $exitCode The exit code.
57
     * @param int $count The count.
58
     * @return void
59
     */
60
    protected function displayFooter(SymfonyStyle $io, $exitCode, $count) {
61
        if (0 < $exitCode) {
62
            $io->error("Some errors occurred while unzipping assets");
63
            return;
64
        }
65
        if (0 === $count) {
66
            $io->success("No assets were provided by any bundle");
67
        }
68
        $io->success("All assets were succefully unzipped");
69
    }
70
71
    /**
72
     * Displays the header.
73
     *
74
     * @param SymfonyStyle $io The I/O.
75
     * @return void
76
     */
77
    protected function displayHeader(SymfonyStyle $io) {
78
        $io->newLine();
79
        $io->text("Trying to unzip assets");
80
        $io->newLine();
81
    }
82
83
    /**
84
     * Displays the result.
85
     *
86
     * @param SymfonyStyle $io The I/O.
87
     * @param array $results The results.
88
     * @return int Returns the exit code.
89
     */
90
    protected function displayResult(SymfonyStyle $io, array $results) {
91
92
        // Initialize.
93
        $success = sprintf("<fg=green;options=bold>%s</>", "\\" === DIRECTORY_SEPARATOR ? "OK" : "\xE2\x9C\x94");
94
        $warning = sprintf("<fg=yellow;options=bold>%s</>", "\\" === DIRECTORY_SEPARATOR ? "KO" : "!");
95
96
        $rows = [];
97
98
        $exitCode = 0;
99
100
        // Handle each result.
101
        foreach ($results as $bundle => $assets) {
102
            foreach ($assets as $asset => $result) {
103
104
                $rows[] = [
105
                    true === $result ? $success : $warning,
106
                    $bundle,
107
                    basename($asset),
108
                ];
109
110
                $exitCode += true === $result ? 0 : 1;
111
            }
112
        }
113
114
        // Display a table.
115
        $io->table(["", "Bundle", "Asset"], $rows);
116
117
        // Return the exit code.
118
        return $exitCode;
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    protected function execute(InputInterface $input, OutputInterface $output) {
125
126
        // Create an I/O.
127
        $io = $this->newSymfonyStyle($input, $output);
128
        $this->displayHeader($io);
129
130
        // Initialize the results.
131
        $results = [];
132
133
        // Get the bundles.
134
        $bundles = $this->getApplication()->getKernel()->getBundles();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Console\Application as the method getKernel() does only exist in the following sub-classes of Symfony\Component\Console\Application: Symfony\Bundle\FrameworkBundle\Console\Application. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
135
136
        // Handle each bundle.
137
        foreach ($bundles as $current) {
138
139
            // Check the bundle.
140
            if (false === ($current instanceOf AssetsProviderInterface)) {
141
                continue;
142
            }
143
144
            // Get the bundle path.
145
            $bundlePath = $current->getPath();
146
147
            // Initialize the directories.
148
            $assetsDirectory = $bundlePath . $current->getAssetsDirectory();
149
            $publicDirectory = $bundlePath . "/Resources/public";
150
151
            // Unzip the assets.
152
            $results[$current->getName()] = AssetsHelper::unzipAssets($assetsDirectory, $publicDirectory);
153
        }
154
155
        // Display the result.
156
        $exitCode = $this->displayResult($io, $results);
157
158
        // Display the footer.
159
        $this->displayFooter($io, $exitCode, count($results));
160
161
        // Return the exit code.
162
        return $exitCode;
163
    }
164
165
    /**
166
     * Create a Symfony style.
167
     *
168
     * @param InputInterface $input The input.
169
     * @param OutputInterface $output The ouptut.
170
     * @return SymfonyStyle Returns the Symfony style.
171
     */
172
    protected function newSymfonyStyle(InputInterface $input, OutputInterface $output) {
173
        return new SymfonyStyle($input, $output);
174
    }
175
176
}
177