Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ LaravelFS functions similarly to the Laravel Installer but with **extra capabili
✅ Support for **Breeze and Jetstream**, even if they are abandoned.
✅ Install **custom starter kits** from Packagist.
✅ Save and reuse project setups with **Templates**.
✅ Easily **remove saved templates** when no longer needed.
✅ Ensure that provided starter kits are **Composer packages of type `project`**.
✅ CLI command to fetch additional details about a starter kit package.

Expand Down Expand Up @@ -93,6 +94,27 @@ This runs the exact same command as if you typed everything manually!

---

## **🗑️ Removing Templates**
Need to clean up your templates? You can easily remove them.

### **Remove a Specific Template**
To delete a single template:

```sh
laravelfs template:remove my-template
```

### **Remove All Templates**
To remove **all saved templates** at once:

```sh
laravelfs template:remove --all
```

> ⚠️ **This action is irreversible!** Make sure you want to delete all templates before running this command.

---

## **Installing Custom Starter Kits**
LaravelFS allows you to install **custom Laravel starter kits** from Packagist by providing the package name:

Expand Down
3 changes: 2 additions & 1 deletion bin/laravelfs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (file_exists(__DIR__.'/../../../autoload.php')) {
}

// Define our own version and the Laravel Installer version we aim to match.
$laravelFSVersion = '1.1.0';
$laravelFSVersion = '1.2.0';
$laravelInstallerVersion = '5.13.0';

// Compose the displayed version string.
Expand All @@ -20,6 +20,7 @@ $app->add(new HichemTabTech\LaravelFS\Console\NewCommand);
$app->add(new HichemTabTech\LaravelFS\Console\NewTemplateCommand);
$app->add(new HichemTabTech\LaravelFS\Console\ShowTemplatesCommand);
$app->add(new HichemTabTech\LaravelFS\Console\UseTemplateCommand);
$app->add(new HichemTabTech\LaravelFS\Console\RemoveTemplateCommand);

/** @noinspection PhpUnhandledExceptionInspection */
$app->run();
21 changes: 21 additions & 0 deletions src/Concerns/CommonTemplateUtils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace HichemTabTech\LaravelFS\Console\Concerns;

use Symfony\Component\Console\Input\InputInterface;
use function Laravel\Prompts\text;

trait CommonTemplateUtils
{
protected function ensureTemplateNameArgument(InputInterface $input): void
{
$templatesData = $this->getSavedTemplates(true);
$templates = $templatesData['templates'];
$input->setArgument('template-name', text(
label: 'What is the name this template',
placeholder: count($templates) == 0 ? 'E.g. template1, or-any-name-u-want' : ('E.g. '.implode(', ', array_slice(array_keys($templates), 0, 3)).(count($templates) > 3 ? ', ...' : '')),
required: 'The template name is required.',
hint: 'This name is the key of the template you are searching for.',
));
}
}
107 changes: 107 additions & 0 deletions src/RemoveTemplateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

namespace HichemTabTech\LaravelFS\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

use function Laravel\Prompts\confirm;
use function Laravel\Prompts\error;
use function Laravel\Prompts\intro;

class RemoveTemplateCommand extends Command
{
use Concerns\CommandsUtils, Concerns\ConfiguresPrompts, Concerns\CommonTemplateUtils;

protected function configure(): void
{
$this->setName('template:remove')
->setDescription('remove a saved template')
->setHelp('This command removes a saved template that you no longer need.')
->addOption('all', 'a', InputOption::VALUE_NONE, 'Remove all saved templates')
->addArgument('template-name', InputArgument::REQUIRED, 'The name of the template to remove');
}

protected function interact(InputInterface $input, OutputInterface $output): void
{
parent::interact($input, $output);

$this->configurePrompts($input, $output);

$output->write(PHP_EOL . ' <fg=blue> _ _
| | | |
| | __ _ _ __ __ ___ _____| |
| | / _` | __/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|</>' . PHP_EOL . PHP_EOL);

if (!$input->getArgument('template-name')) {
if (!$input->getOption('all')) {
$this->ensureTemplateNameArgument($input);
} else {
$input->setArgument('template-name', confirm(
label: 'Are you sure you want to remove all saved templates?',
default: false,
hint: 'This action is irreversible.',
) ? '/all/' : null);
}
}
}


protected function execute(InputInterface $input, OutputInterface $output): int
{

$templatesData = $this->getSavedTemplates();
$templates = $templatesData['templates'];
if (empty($templates)) {
$this->info('No saved templates found.');
return Command::SUCCESS;
}

if ($input->getArgument('template-name') == '/all/') {
$templateToRemove = null;
} elseif (!$input->getArgument('template-name')) {
intro('Operation cancelled.');
return Command::SUCCESS;
} else {
$templateName = $input->getArgument('template-name');

if (!isset($templates[$templateName])) {
error("Template '$templateName' not found.");
return Command::INVALID;
}

$templateToRemove = $templateName;
}
intro("Removing a saved template...");

if ($templateToRemove) {
$done = $this->removeTemplates($templatesData['path'], $templatesData, $templateToRemove);
} else {
$done = $this->removeTemplates($templatesData['path'], $templatesData);
}

if ($done) {
$this->info($templateToRemove ? "Template '$templateToRemove' removed successfully." : 'All saved templates removed successfully.');
return Command::SUCCESS;
}

error($templateToRemove ? "Failed to remove template '$templateToRemove'." : 'Failed to remove all saved templates.');
return Command::FAILURE;
}

private function removeTemplates(string $path, array $templatesData, string|null $templateToRemove = null): bool
{
if (!$templateToRemove) {
$templatesConfig = ['templates' => []];
} else {
unset($templatesData['templates'][$templateToRemove]);
$templatesConfig = ['templates' => $templatesData['templates']];
}
return file_put_contents($path, json_encode($templatesConfig, JSON_PRETTY_PRINT)) !== false;
}
}
11 changes: 2 additions & 9 deletions src/UseTemplateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class UseTemplateCommand extends Command
{
use Concerns\CommandsUtils, Concerns\ConfiguresPrompts;
use Concerns\CommandsUtils, Concerns\ConfiguresPrompts, Concerns\CommonTemplateUtils;
protected function configure(): void
{
$this->setName('use')
Expand All @@ -39,14 +39,7 @@ protected function interact(InputInterface $input, OutputInterface $output): voi
|______\__,_|_| \__,_| \_/ \___|_|</>'.PHP_EOL.PHP_EOL);

if (!$input->getArgument('template-name')) {
$templatesData = $this->getSavedTemplates(true);
$templates = $templatesData['templates'];
$input->setArgument('template-name', text(
label: 'What is the name this template',
placeholder: count($templates) == 0 ? 'E.g. template1, or-any-name-u-want' : ('E.g. '.implode(', ', array_slice(array_keys($templates), 0, 3)).(count($templates) > 3 ? ', ...' : '')),
required: 'The template name is required.',
hint: 'This name is the key of the template you are searching for.',
));
$this->ensureTemplateNameArgument($input);
}

if (!$input->getArgument('project-name')) {
Expand Down