NewPage   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 90
dl 0
loc 159
rs 10
c 1
b 0
f 0
wmc 24

3 Methods

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