Completed
Pull Request — master (#2012)
by
unknown
02:08
created

ThemeController::renderCmsLayout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace luya\console\commands;
4
5
use luya\helpers\FileHelper;
6
use luya\helpers\Json;
7
use luya\theme\ThemeConfig;
8
use Yii;
9
use yii\helpers\Console;
10
use yii\helpers\Inflector;
11
12
/**
13
 * Command to create a new LUYA theme.
14
 *
15
 * @author Bennet Klarhoelter <[email protected]>
16
 * @since 1.0.21
17
 */
18
class ThemeController extends \luya\console\Command
19
{
20
    /**
21
     * @inheritdoc
22
     */
23
    public $defaultAction = 'create';
24
    
25
    /**
26
     * Create a new theme.
27
     *
28
     * @param string|null $themeName
29
     *
30
     * @return int
31
     * @throws \yii\base\Exception
32
     */
33
    public function actionCreate(string $themeName = null)
34
    {
35
        Console::clearScreenBeforeCursor();
36
        
37
        $themeName = $this->prompt("Enter the name (lower case) of the theme you like to generate:", ['default' => $themeName]);
38
        
39
        $newName = preg_replace("/[^a-z]/", "", strtolower($themeName));
40
        if ($newName !== $themeName) {
41
            if (!$this->confirm("We have changed the name to '{$newName}'. Do you want to proceed with this name?")) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->confirm("We have ...oceed with this name?") of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
42
                return $this->outputError('Abort by user.');
43
            } else {
44
                $themeName = $newName;
45
            }
46
        }
47
        
48
        $availableModules = implode(', ', array_column(Yii::$app->getFrontendModules(), 'id'));
49
        $themeLocation = $this->prompt("Enter the theme location where to generate (as path alias e.g. app, $availableModules):", ['default' => 'app']);
50
        $themeLocation = '@' . ltrim($themeLocation, '@');
51
        
52
        preg_match("#^@[A-z]+#", $themeLocation, $newThemeLocation);
53
        
54
        if ($newThemeLocation[0] !== $themeLocation) {
55
            if (!$this->confirm("We have changed the name to '{$newThemeLocation[0]}'. Do you want to proceed with this name?")) {
56
                return $this->outputError('Abort by user.');
57
            } else {
58
                $themeLocation = $newThemeLocation[0];
59
            }
60
        }
61
        
62
        $basePath = $themeLocation . '/themes/' . $themeName;
63
        $themeFolder = Yii::getAlias($basePath);
64
        
65
        if (file_exists($themeFolder)) {
66
            return $this->outputError("The folder " . $themeFolder . " exists already.");
67
        }
68
        
69
        $this->outputInfo("Theme path alias: " . $basePath);
70
        $this->outputInfo("Theme real path: " . $themeFolder);
71
        if (!$this->confirm("Do you want continue?")) {
72
            return $this->outputError('Abort by user.');
73
        }
74
        
75
        $folders = [
76
            '',
77
            'resources',
78
            'views',
79
            'views/layouts',
80
            'views/cmslayouts',
81
        ];
82
        
83
        foreach ($folders as $folder) {
84
            FileHelper::createDirectory($themeFolder . DIRECTORY_SEPARATOR . $folder);
85
        }
86
        
87
        $contents = [
88
            $themeFolder. DIRECTORY_SEPARATOR . 'theme.json' => $this->renderJson($basePath, $themeName),
89
            $themeFolder. DIRECTORY_SEPARATOR . ucfirst($themeName) . 'Asset.php' => $this->renderAssetClass($themeName),
90
            $themeFolder. DIRECTORY_SEPARATOR . 'resources/'. $themeName .'-asset/style.css' => '',
91
            $themeFolder. DIRECTORY_SEPARATOR . 'views/layouts/theme.php' => $this->renderLayout($themeName),
92
            $themeFolder. DIRECTORY_SEPARATOR . 'views/cmslayouts/theme.php' => $this->renderCmsLayout($themeName),
0 ignored issues
show
Unused Code introduced by
The call to ThemeController::renderCmsLayout() has too many arguments starting with $themeName.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
93
        ];
94
        
95
        foreach ($contents as $fileName => $content) {
96
            FileHelper::writeFile($fileName, $content);
97
        }
98
        
99
        return $this->outputSuccess("Theme files has been created successfully. Please run `".$_SERVER['PHP_SELF']." import` to import the theme into the database.");
100
    }
101
    
102
    /**
103
     * Render the json template.
104
     *
105
     * @param string $basePath
106
     * @param string $themeName
107
     * @return string
108
     */
109
    private function renderJson(string $basePath, string $themeName)
110
    {
111
        $themeConfig = new ThemeConfig($basePath, []);
112
        $themeConfig->name = $themeName;
113
        
114
        if ($this->confirm('Inherit from other theme?')) {
115
            $themeConfig->parentTheme = $this->prompt(
116
                "Enter the base path (e.g. `@app/themes/blank`) of the parent theme:",
117
                [
118
                    'default' => null,
119
                    'validator' => [$this, 'validateParentTheme'],
120
                ]
121
            );
122
        }
123
        
124
        return Json::encode($themeConfig->toArray(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
125
    }
126
    
127
    private function renderAssetClass($themeName)
128
    {
129
        $className = ucfirst($themeName) . 'Asset';
130
        return "<?php
131
namespace app\\themes\\{$themeName};
132
133
use luya\web\Asset;
134
135
class {$className} extends Asset
136
{
137
    public \$css = [
138
        \'{$themeName}.css\',
139
    ];
140
}";
141
    }
142
    
143
    private function validateParentTheme($input, &$error)
144
    {
145
        if (!preg_match('/^@[a-z]+$/', $input)) {
146
            $error = 'The theme name must be only letter chars!';
147
            return false;
148
        } elseif (Yii::getAlias($input, false) === false) {
149
            $error = 'The theme base path not exists!';
150
            return false;
151
        }
152
        
153
        return true;
154
    }
155
    
156
    private function renderLayout($themeName)
157
    {
158
        $className = ucfirst($themeName) . 'Asset';
159
    
160
        return '<?php
161
/**
162
 * @var $this \luya\web\View
163
 */
164
use luya\themes\frontend\\'.$className.';
165
166
'.$className.'::register($this);
167
168
$this->beginPage();
169
?>
170
<!DOCTYPE html>
171
<html lang="<?= Yii::$app->composition->language; ?>">
172
    <head>
173
        <title><?= $this->title; ?></title>
174
        <meta charset="utf-8">
175
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
176
        <meta http-equiv="x-ua-compatible" content="ie=edge">
177
        <meta name="author" content="boehsermoe">
178
        <?php $this->head() ?>
179
    </head>
180
    <body class="homepage">
181
    <?php $this->beginBody() ?>
182
183
        <div id="wrapper">
184
            <?php echo $content ?>
185
        </div>
186
187
    <?php $this->endBody() ?>
188
    </body>
189
</html>
190
<?php $this->endPage() ?>
191
';
192
    }
193
    
194
    private function renderCmsLayout()
195
    {
196
        return '<?= $placeholders[\'content\'] ?>';
197
    }
198
}
199