Completed
Pull Request — develop (#407)
by
unknown
13:06
created

GenerateCommand   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 4
Bugs 0 Features 1
Metric Value
wmc 14
c 4
b 0
f 1
lcom 1
cbo 7
dl 0
loc 133
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A configure() 0 7 1
B execute() 0 33 6
B executeGenerateBootstrap() 0 40 3
A getCopyrightHeader() 0 18 3
1
<?php
2
3
/**
4
 * This file is part of BraincraftedBootstrapBundle.
5
 *
6
 * (c) 2012-2013 by Florian Eckerstorfer
7
 */
8
9
namespace Braincrafted\Bundle\BootstrapBundle\Command;
10
11
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Output\OutputInterface;
14
15
use Braincrafted\Bundle\BootstrapBundle\Util\PathUtil;
16
use Symfony\Component\Filesystem\Filesystem;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpKernel\Kernel;
19
20
/**
21
 * GenerateCommand
22
 *
23
 * @package    BraincraftedBootstrapBundle
24
 * @subpackage Command
25
 * @author     Florian Eckerstorfer <[email protected]>
26
 * @copyright  2012-2013 Florian Eckerstorfer
27
 * @license    http://opensource.org/licenses/MIT The MIT License
28
 * @link       http://bootstrap.braincrafted.com BraincraftedBootstrapBundle
29
 */
30
class GenerateCommand extends ContainerAwareCommand
31
{
32
    /** @var PathUtil */
33
    private $pathUtil;
34
35
    /**
36
     * {@inheritDoc}
37
     */
38
    public function __construct($name = null)
39
    {
40
        $this->pathUtil = new PathUtil;
41
42
        parent::__construct($name);
43
    }
44
45
    /**
46
     * {@inheritDoc}
47
     *
48
     * @codeCoverageIgnore
49
     */
50
    protected function configure()
51
    {
52
        $this
53
            ->setName('braincrafted:bootstrap:generate')
54
            ->setDescription('Generates a custom bootstrap.less')
55
        ;
56
    }
57
58
    /**
59
     * {@inheritDoc}
60
     */
61
    protected function execute(InputInterface $input, OutputInterface $output)
62
    {
63
        $config = $this->getContainer()->getParameter('braincrafted_bootstrap.customize');
64
65
        if (false === isset($config['variables_file']) || null === $config['variables_file']) {
66
            $output->writeln('<error>Found no custom variables.less file.</error>');
67
68
            return;
69
        }
70
71
        $filter = $this->getContainer()->getParameter('braincrafted_bootstrap.less_filter');
72
        if ('less' !== $filter && 'lessphp' !== $filter) {
73
            $output->writeln(
74
                '<error>Bundle must be configured with "less" or "lessphp" to generated bootstrap.less</error>'
75
            );
76
77
            return;
78
        }
79
80
        $fs = new Filesystem();
81
        $bootstrapLessFile = $this->getContainer()->getParameter('kernel.root_dir') . '/../vendor/twbs/bootstrap/less/bootstrap.less';
82
        if (false === $fs->exists($bootstrapLessFile)) {
83
            $output->writeln(
84
                '<error>Required bundle "twbs/bootstrap" not found in composer.json, please run "composer require twbs/bootstrap && composer update"</error>'
85
            );
86
87
            return;
88
        }
89
90
        $output->writeln('<comment>Found custom variables file. Generating...</comment>');
91
        $this->executeGenerateBootstrap($config, $output);
92
        $output->writeln(sprintf('Saved to <info>%s</info>', $config['bootstrap_output']));
93
    }
94
95
    protected function executeGenerateBootstrap(array $config, OutputInterface $output)
96
    {
97
        // In the template for bootstrap.less we need the path where Bootstraps .less files are stored and the path
98
        // to the variables.less file.
99
        // Absolute path do not work in LESSs import statement, we have to calculate the relative ones
100
101
        $lessDir = $this->pathUtil->getRelativePath(
102
            dirname($config['bootstrap_output']),
103
            $this->getContainer()->getParameter('braincrafted_bootstrap.assets_dir')
104
        ) . 'less/';
105
106
        $variablesDir = $this->pathUtil->getRelativePath(
107
            dirname($config['bootstrap_output']),
108
            dirname($config['variables_file'])
109
        );
110
        $variablesFile = sprintf(
111
            '%s%s%s',
112
            $variablesDir,
113
            strlen($variablesDir) > 0 ? '/' : '',
114
            basename($config['variables_file'])
115
        );
116
117
        $container = $this->getContainer();
118
119
        if (Kernel::VERSION_ID >= 20500) {
120
            $container->enterScope('request');
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...Interface::enterScope() has been deprecated with message: since version 2.8, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
121
            $container->set('request', new Request(), 'request');
122
        }
123
124
        // Load the content from the original twbs bootstrap.less file
125
        // and make some modifications and save it to our custom
126
        // bootstrap less file.
127
128
        $bootstrapLessFile = $this->getContainer()->getParameter('kernel.root_dir') . '/../vendor/twbs/bootstrap/less/bootstrap.less';
129
        $content = $this->getCopyrightHeader($output) . "\xA" . file_get_contents($bootstrapLessFile);
130
        $content = str_replace('@import "', '@import "' . $lessDir, $content);
131
        $content = str_replace('variables.less";', 'variables.less";' . "\xA" . '@import "' . $variablesFile . '";', $content);
132
133
        file_put_contents($config['bootstrap_output'], $content);
134
    }
135
136
    /**
137
     * Fetches the twbs copyright header from the bootstrap.css file.
138
     *
139
     *
140
     * @param OutputInterface $output An OutputInterface instance
141
     *
142
     * @return empty string if unable to fetch header, or the copyright header as string.
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
143
     */
144
    private function getCopyrightHeader(OutputInterface $output) {
145
        $fs = new Filesystem();
146
        $copyrightHeaderFile = $this->getContainer()->getParameter('kernel.root_dir') . '/../vendor/twbs/bootstrap/dist/css/bootstrap.css';
147
148
        if (false !== $fs->exists($copyrightHeaderFile)) {
149
            $content = file_get_contents(  $copyrightHeaderFile);
150
            preg_match_all('/^\/\*!.+copyright.+\*\/$/imsU', $content, $matches);
151
152
            if (isset($matches[0][0]))
0 ignored issues
show
Coding Style introduced by
Please always use braces to surround the code block of IF statements.
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
153
                return $matches[0][0];
154
        }
155
156
        $output->writeln(
157
            '<comment>Unable to fetch copyright header from ' .   $copyrightHeaderFile . ', please add it manually.</comment>'
158
        );
159
160
        return '';
161
    }
162
}
163