NewPage::execute()   F
last analyzed

Complexity

Conditions 20
Paths 1084

Size

Total Lines 79
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 20
eloc 56
c 1
b 0
f 0
nc 1084
nop 2
dl 0
loc 79
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <[email protected]>
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
declare(strict_types=1);
13
14
namespace Cecil\Command;
15
16
use Cecil\Exception\RuntimeException;
17
use Cecil\Util;
18
use Symfony\Component\Console\Input\InputArgument;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
/**
24
 * NewPage command.
25
 *
26
 * This command creates a new page file in the specified directory.
27
 * It allows users to define the page name, whether to slugify the file name, add a date prefix,
28
 * and whether to open the file in an editor after creation.
29
 */
30
class NewPage extends AbstractCommand
31
{
32
    /**
33
     * {@inheritdoc}
34
     */
35
    protected function configure()
36
    {
37
        $this
38
            ->setName('new:page')
39
            ->setDescription('Creates a new page')
40
            ->setDefinition([
41
                new InputArgument('path', InputArgument::OPTIONAL, 'Use the given path as working directory'),
42
                new InputOption('name', null, InputOption::VALUE_REQUIRED, 'Page path name'),
43
                new InputOption('slugify', null, InputOption::VALUE_NEGATABLE, 'Slugify file name (or disable --no-slugify)'),
44
                new InputOption('prefix', 'p', InputOption::VALUE_NONE, 'Prefix the file name with the current date (`YYYY-MM-DD`)'),
45
                new InputOption('force', 'f', InputOption::VALUE_NONE, 'Override the file if already exist'),
46
                new InputOption('open', 'o', InputOption::VALUE_NONE, 'Open editor automatically'),
47
                new InputOption('editor', null, InputOption::VALUE_REQUIRED, 'Editor to use with open option'),
48
            ])
49
            ->setHelp(
50
                <<<'EOF'
51
The <info>%command.name%</> command creates a new page file.
52
If your run this command without any options, it will ask you for the page name and others options.
53
54
  <info>%command.full_name%</>
55
  <info>%command.full_name% --name=path/to/a-page.md</>
56
  <info>%command.full_name% --name=path/to/A Page.md --slugify</>
57
58
To create a new page with a <comment>date prefix</comment> (i.e: `YYYY-MM-DD`), run:
59
60
  <info>%command.full_name% --prefix</>
61
62
To create a new page and open it with an <comment>editor</comment>, run:
63
64
  <info>%command.full_name% --open --editor=editor</>
65
66
To <comment>override</comment> an existing page, run:
67
68
  <info>%command.full_name% --force</>
69
EOF
70
            );
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     *
76
     * @throws RuntimeException
77
     */
78
    protected function execute(InputInterface $input, OutputInterface $output)
79
    {
80
        $name = (string) $input->getOption('name');
81
        $slugify = $input->getOption('slugify');
82
        $prefix = (bool) $input->getOption('prefix');
83
        $force = (bool) $input->getOption('force');
84
        $open = (bool) $input->getOption('open');
85
        $editor = $input->getOption('editor');
86
87
        try {
88
            // ask
89
            if (empty($name)) {
90
                $name = $this->io->ask('What is the name of the page file?', 'new-page.md');
91
                $slugify = ($slugify !== null) ? $slugify : $this->io->confirm('Slugify the file name?', true);
92
                $prefix = ($prefix !== false) ?: $this->io->confirm('Add date prefix to the filename?', false);
93
                $open = ($open !== false) ?: $this->io->confirm('Do you want open the created file with your editor?', false);
94
                if ($open && !$this->getBuilder()->getConfig()->has('editor')) {
95
                    $editor = ($editor !== null) ? $editor : $this->io->ask('Which editor?');
96
                }
97
            }
98
            // parse given path name
99
            $nameParts = pathinfo($name);
100
            $dirname = trim($nameParts['dirname'], '.');
101
            $basename = $nameParts['basename'];
102
            $extension = $nameParts['extension'];
103
            $title = substr($basename, 0, -\strlen(".$extension"));
104
            $filename = $basename;
105
            if (!\in_array($extension, (array) $this->getBuilder()->getConfig()->get('pages.ext'))) {
106
                $title = $filename;
107
                $filename = trim("$basename.md"); // force a valid extension
108
            }
109
            $title = trim(ucfirst(str_replace('-', ' ', $title)));
110
            $date = date('Y-m-d');
111
            // date prefix?
112
            $datePrefix = $prefix ? \sprintf('%s-', $date) : '';
113
            // define target path
114
            $fileRelativePath = \sprintf(
115
                '%s%s%s%s%s',
116
                (string) $this->getBuilder()->getConfig()->get('pages.dir'),
117
                DIRECTORY_SEPARATOR,
118
                empty($dirname) ? '' : $dirname . DIRECTORY_SEPARATOR,
119
                $datePrefix,
120
                $slugify ? \Cecil\Collection\Page\Page::slugify($filename) : $filename
121
            );
122
            $filePath = Util::joinFile($this->getPath(), $fileRelativePath);
123
            // ask to override existing file?
124
            if (Util\File::getFS()->exists($filePath) && !$force) {
125
                $output->writeln(\sprintf('<comment>The file "%s" already exists.</comment>', $fileRelativePath));
126
                if (!$this->io->confirm('Do you want to override it?', false)) {
127
                    return 0;
128
                }
129
            }
130
            // creates a new file
131
            $model = $this->findModel(\sprintf('%s%s', empty($dirname) ? '' : $dirname . DIRECTORY_SEPARATOR, $filename));
132
            $fileContent = str_replace(
133
                ['%title%', '%date%'],
134
                [$title, $date],
135
                $model['content']
136
            );
137
            Util\File::getFS()->dumpFile($filePath, $fileContent);
138
            $output->writeln(\sprintf('<info>File %s created (with "%s" model).</info>', $filePath, $model['name']));
139
            // open editor?
140
            if ($open) {
141
                if ($editor === null) {
142
                    if (!$this->getBuilder()->getConfig()->has('editor')) {
143
                        $output->writeln('<comment>No editor configured.</comment>');
144
145
                        return 0;
146
                    }
147
                    $editor = (string) $this->getBuilder()->getConfig()->get('editor');
148
                }
149
                $output->writeln(\sprintf('<info>Opening file with %s...</info>', ucfirst($editor)));
150
                $this->openEditor($filePath, $editor);
151
            }
152
        } catch (\Exception $e) {
153
            throw new RuntimeException(\sprintf($e->getMessage()));
154
        }
155
156
        return 0;
157
    }
158
159
    /**
160
     * Finds the page model and returns its [name, content].
161
     */
162
    private function findModel(string $name): array
163
    {
164
        $name = strstr($name, DIRECTORY_SEPARATOR, true) ?: 'default';
165
        if (file_exists($model = Util::joinFile($this->getPath(), 'models', "$name.md"))) {
166
            return [
167
                'name'    => $name,
168
                'content' => Util\File::fileGetContents($model),
169
            ];
170
        }
171
172
        $content = <<<'EOT'
173
---
174
title: "%title%"
175
date: %date%
176
published: true
177
---
178
_Your content here_
179
180
EOT;
181
182
        return [
183
            'name'    => $name,
184
            'content' => $content,
185
        ];
186
    }
187
}
188