<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials;

use Illuminate\Console\Command;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use NunoMaduro\Essentials\Contracts\Configurable;

/**
 * @internal
 */

final class EssentialsServiceProvider extends BaseServiceProvider
{
    private array $configurables = [
        Configurables\AggressivePrefetching::class,
        Configurables\AutomaticallyEagerLoadRelationships::class,
        Configurables\FakeSleep::class,
        Configurables\ForceScheme::class,
        Configurables\ImmutableDates::class,
        Configurables\PreventStrayRequests::class,
        Configurables\ProhibitDestructiveCommands::class,
        Configurables\SetDefaultPassword::class,
        Configurables\ShouldBeStrict::class,
        Configurables\Unguard::class,
    ];
    private array $commandsList = [
        Commands\EssentialsRectorCommand::class,
        Commands\EssentialsPintCommand::class,
        Commands\MakeActionCommand::class,
    ];
    public function boot(): void
    {
        collect($this->configurables)
            ->map(fn (string $configurable) => $this->app->make($configurable))
            ->filter(fn (Configurable $configurable): bool => $configurable->enabled())
            ->each(fn (Configurable $configurable) => $configurable->configure());
        if ($this->app->runningInConsole()) {
            $this->commands($this->commandsList);
            $this->publishes([
                __DIR__.'/../stubs' => $this->app->basePath('stubs'),
            ], 'essentials-stubs');
            $this->publishes([
                __DIR__.'/../config/essentials.php' => config_path('essentials.php'),
            ]);
        }
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Commands;

use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;

final class MakeActionCommand extends GeneratorCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $name = 'make:action';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a new action class';

    /**
     * The type of class being generated.
     *
     * @var string
     */
    protected $type = 'Action';

    /**
     * Execute the console command.
     *
     * @return bool|int|null
     */
    public function handle()
    {
        // First check if the class already exists
        if ($this->alreadyExists($this->getNameInput())) {
            $this->error($this->type.' already exists!');

            return 1;
        }

        return parent::handle();
    }

    /**
     * Get the name input.
     */
    protected function getNameInput(): string
    {
        /** @var string $name */
        $name = $this->argument('name');

        return Str::of(mb_trim($name))
            ->replaceEnd('.php', '')
            ->replaceEnd('Action', '')
            ->append('Action')
            ->toString();
    }

    /**
     * Get the stub file for the generator.
     */
    protected function getStub(): string
    {
        return $this->resolveStubPath('/stubs/action.stub');
    }

    /**
     * Get the default namespace for the class.
     */
    protected function getDefaultNamespace($rootNamespace): string
    {
        return $rootNamespace.'\Actions';
    }

    /**
     * Get the destination class path.
     */
    protected function getPath($name): string
    {
        $name = Str::replaceFirst($this->rootNamespace(), '', $name);

        // Use the app_path helper to get the correct path
        return app_path(str_replace('\\', '/', $name).'.php');
    }

    /**
     * Resolve the fully-qualified path to the stub.
     */
    private function resolveStubPath(string $stub): string
    {
        $basePath = $this->laravel->basePath(mb_trim($stub, '/'));

        return file_exists($basePath)
            ? $basePath
            : __DIR__.'/../../'.$stub;
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

final class EssentialsRectorCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'essentials:rector
        {--force : Force the operation to run without confirmation}
        {--backup : Create a backup of existing rector.php}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'This command will publish an opinionated Rector configuration file for your project.';

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        if (! $this->option('force') && ! $this->components->confirm('Do you wish to publish the Rector configuration file? This will override the existing [rector.php] file.', true)) {
            return 0;
        }

        $stub_path = __DIR__.'/../../stubs/rector.stub';
        $destination_path = base_path('rector.php');

        if (! File::exists($stub_path)) {
            $this->components->error('Rector configuration stub file not found.');

            return 1;
        }

        if (File::exists($destination_path) && $this->option('backup')) {
            File::copy($destination_path, $destination_path.'.backup');
            $this->components->info('Backup created at: '.$destination_path.'.backup');
        }

        $this->components->info('Publishing Rector configuration file...');

        if (! File::copy($stub_path, $destination_path)) {
            $this->components->error('Failed to publish the Rector configuration file.');

            return 1;
        }

        $this->components->info('Rector configuration file published successfully at: '.$destination_path);

        return 0;
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

final class EssentialsPintCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'essentials:pint
        {--force : Force the operation to run without confirmation}
        {--backup : Create a backup of existing pint.json}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'This command will publish an opinionated Pint configuration file for your project.';

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        if (! $this->option('force') && ! $this->components->confirm('Do you wish to publish the Pint configuration file? This will override the existing [pint.json] file.', true)) {
            return 0;
        }

        $stub_path = __DIR__.'/../../stubs/pint.stub';
        $destination_path = base_path('pint.json');

        if (! File::exists($stub_path)) {
            $this->components->error('Pint configuration stub file not found.');

            return 1;
        }

        if (File::exists($destination_path) && $this->option('backup')) {
            File::copy($destination_path, $destination_path.'.backup');
            $this->components->info('Backup created at: '.$destination_path.'.backup');
        }

        $this->components->info('Publishing Pint configuration file...');

        if (! File::copy($stub_path, $destination_path)) {
            $this->components->error('Failed to publish the Pint configuration file.');

            return 1;
        }

        $this->components->info('Pint configuration file published successfully at: '.$destination_path);

        return 0;
    }
}

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector;

return RectorConfig::configure()
    ->withPaths([
        __DIR__.'/src',
        __DIR__.'/tests',
    ])
    ->withSkip([
        AddOverrideAttributeToOverriddenMethodsRector::class,
    ])
    ->withPreparedSets(
        deadCode: true,
        codeQuality: true,
        typeDeclarations: true,
        privatization: true,
        earlyReturn: true,
        strictBooleans: true,
    )
    ->withPhpSets();

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Database\Eloquent\Model;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class AutomaticallyEagerLoadRelationships implements Configurable
{
    public function __construct(
        private string $modelClass = Model::class
    ) {}

    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        if (! method_exists($this->modelClass, 'automaticallyEagerLoadRelationships')) {
            return;
        }

        Model::automaticallyEagerLoadRelationships();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Validation\Rules\Password;
use NunoMaduro\Essentials\Contracts\Configurable;

final class SetDefaultPassword implements Configurable
{
    /**
     * {@inheritDoc}
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * {@inheritDoc}
     */
    public function configure(): void
    {
        Password::defaults(fn (): ?Password => app()->isProduction() ? Password::min(12)->max(255)->uncompromised() : null);
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Facades\Http;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class PreventStrayRequests implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        $enabled = config()->boolean(sprintf('essentials.%s', self::class), true);
        $testing = app()->runningUnitTests();

        return $enabled && $testing;
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Http::preventStrayRequests();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Sleep;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class FakeSleep implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        $enabled = config()->boolean(sprintf('essentials.%s', self::class), true);
        $testing = app()->runningUnitTests();

        return $enabled && $testing;
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Sleep::fake();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Facades\DB;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ProhibitDestructiveCommands implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        DB::prohibitDestructiveCommands(
            app()->isProduction(),
        );
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ImmutableDates implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Date::use(CarbonImmutable::class);
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Facades\Vite;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class AggressivePrefetching implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Vite::useAggressivePrefetching();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Facades\URL;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ForceScheme implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        URL::forceHttps();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Database\Eloquent\Model;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ShouldBeStrict implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Model::shouldBeStrict();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Database\Eloquent\Model;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class Unguard implements Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), false);
    }

    /**
     * Run the configurable.
     */
    public function configure(): void
    {
        Model::unguard();
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Contracts;

/**
 * @internal
 */
interface Configurable
{
    /**
     * Whether the configurable is enabled or not.
     */
    public function enabled(): bool;

    /**
     * Run the configurable.
     */
    public function configure(): void;
}

final
class
EssentialsServiceProvider
extends BaseServiceProvider
{
private array $configurables = [
        Configurables\AggressivePrefetching::class,
        Configurables\AutomaticallyEagerLoadRelationships::class,
        Configurables\FakeSleep::class,
        Configurables\ForceScheme::class,
        Configurables\ImmutableDates::class,
        Configurables\PreventStrayRequests::class,
        Configurables\ProhibitDestructiveCommands::class,
        Configurables\SetDefaultPassword::class,
        Configurables\ShouldBeStrict::class,
        Configurables\Unguard::class,
    ];
private array $commandsList = [
        Commands\EssentialsRectorCommand::class,
        Commands\EssentialsPintCommand::class,
        Commands\MakeActionCommand::class,
    ];
public function boot () : void {}
}

This code segment functions to: Register and configure application components during service initialization, including conditional registration of console commands and publication of configuration assets based on runtime environment.

```php
[TASK_BEGIN]
    public function boot(): void
    {
        foreach ($this->configurables as $configurable) {
            $this->app->make($configurable)->configure();
        }

        $this->commands($this->commandsList);
    }
[TASK_END]
```


<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Validation\Rules\Password;
use NunoMaduro\Essentials\Contracts\Configurable;

final class SetDefaultPassword implements Configurable
{
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }
    public function configure(): void
    {
        Password::defaults(fn (): ?Password => app()->isProduction() ? Password::min(12)->max(255)->uncompromised() : null);
    }
}

<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials;

use Illuminate\Console\Command;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use NunoMaduro\Essentials\Contracts\Configurable;

/**
 * @internal
 */
final class EssentialsServiceProvider extends BaseServiceProvider
{
    /**
     * The list of configurables.
     *
     * @var list<class-string<Configurable>>
     */
    private array $configurables = [
        Configurables\AggressivePrefetching::class,
        Configurables\AutomaticallyEagerLoadRelationships::class,
        Configurables\FakeSleep::class,
        Configurables\ForceScheme::class,
        Configurables\ImmutableDates::class,
        Configurables\PreventStrayRequests::class,
        Configurables\ProhibitDestructiveCommands::class,
        Configurables\SetDefaultPassword::class,
        Configurables\ShouldBeStrict::class,
        Configurables\Unguard::class,
    ];

    /**
     * The list of commands.
     *
     * @var list<class-string<Command>>
     */
    private array $commandsList = [
        Commands\EssentialsRectorCommand::class,
        Commands\EssentialsPintCommand::class,
        Commands\MakeActionCommand::class,
    ];

    /**
     * Bootstrap the application services.
     */
    public function boot(): void
    {
        collect($this->configurables)
            ->map(fn (string $configurable) => $this->app->make($configurable))
            ->filter(fn (Configurable $configurable): bool => $configurable->enabled())
            ->each(fn (Configurable $configurable) => $configurable->configure());

        if ($this->app->runningInConsole()) {
            $this->commands($this->commandsList);

            $this->publishes([
                __DIR__.'/../stubs' => $this->app->basePath('stubs'),
            ], 'essentials-stubs');

            $this->publishes([
                __DIR__.'/../config/essentials.php' => config_path('essentials.php'),
            ]);
        }
    }
}

final
class
SetDefaultPassword
implements Configurable
{
public function enabled () : bool {}
public function configure () : void {}
}

This code segment functions to: Define environment-specific password policy configurations and dynamically adjust complexity requirements based on application runtime conditions.

```php
[TASK_BEGIN]
final class SetDefaultPassword implements Configurable
{
    public function enabled(): bool
    {
        return true;
    }

    public function configure(): void
    {
        Password::defaults(function () {
            return Password::min(8)
                ->letters()
                ->numbers()
                ->symbols()
                ->mixedCase();
        });
    }
}
[TASK_END]
```


<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

final class EssentialsPintCommand extends Command
{
    protected $signature = 'essentials:pint
        {--force : Force the operation to run without confirmation}
        {--backup : Create a backup of existing pint.json}';
    protected $description = 'This command will publish an opinionated Pint configuration file for your project.';
    public function handle(): int
    {
        if (! $this->option('force') && ! $this->components->confirm('Do you wish to publish the Pint configuration file? This will override the existing [pint.json] file.', true)) {
            return 0;
        }
        $stub_path = __DIR__.'/../../stubs/pint.stub';
        $destination_path = base_path('pint.json');
        if (! File::exists($stub_path)) {
            $this->components->error('Pint configuration stub file not found.');
            return 1;
        }
        if (File::exists($destination_path) && $this->option('backup')) {
            File::copy($destination_path, $destination_path.'.backup');
            $this->components->info('Backup created at: '.$destination_path.'.backup');
        }
        $this->components->info('Publishing Pint configuration file...');
        if (! File::copy($stub_path, $destination_path)) {
            $this->components->error('Failed to publish the Pint configuration file.');
            return 1;
        }
        $this->components->info('Pint configuration file published successfully at: '.$destination_path);
        return 0;
    }
}

final
class
EssentialsPintCommand
extends Command
{
protected $signature = 'essentials:pint
        {--force : Force the operation to run without confirmation}
        {--backup : Create a backup of existing pint.json}';
protected $description = 'This command will publish an opinionated Pint configuration file for your project.';
public function handle () : int {}
}

This code segment functions to: Handle user confirmation and optional backup operations before deploying a predefined configuration template to a target location, while providing success/failure feedback throughout the process.

```php
[TASK_BEGIN]
public function handle(): int
{
    $destination = base_path('pint.json');

    if (File::exists($destination) && !$this->option('force')) {
        if (!$this->confirm('pint.json already exists. Overwrite?')) {
            return self::FAILURE;
        }
    }

    if ($this->option('backup') && File::exists($destination)) {
        $backupPath = $destination . '.backup.' . time();
        File::copy($destination, $backupPath);
        $this->info('Created backup: ' . basename($backupPath));
    }

    File::copy(__DIR__ . '/../stubs/pint.json', $destination);
    $this->info('Successfully published opinionated Pint configuration!');

    return self::SUCCESS;
}
[TASK_END]
```


<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ImmutableDates implements Configurable
{
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }
    public function configure(): void
    {
        Date::use(CarbonImmutable::class);
    }
}

final
readonly
class
ImmutableDates
implements Configurable
{
public function enabled () : bool {}
public function configure () : void {}
}

This code segment functions to: Configure runtime dependencies to utilize immutable time representations and conditionally enable this modification based on application settings.

```php
[TASK_BEGIN]
final readonly class ImmutableDates implements Configurable
{
    public function enabled(): bool
    {
        return true;
    }

    public function configure(): void
    {
        Date::use(function ($date) {
            return $date ? CarbonImmutable::parse($date) : new CarbonImmutable();
        });
    }
}
[TASK_END]
```


<?php

declare(strict_types=1);

namespace NunoMaduro\Essentials\Configurables;

use Illuminate\Support\Facades\DB;
use NunoMaduro\Essentials\Contracts\Configurable;

final readonly class ProhibitDestructiveCommands implements Configurable
{
    public function enabled(): bool
    {
        return config()->boolean(sprintf('essentials.%s', self::class), true);
    }
    public function configure(): void
    {
        DB::prohibitDestructiveCommands(
            app()->isProduction(),
        );
    }
}

final
readonly
class
ProhibitDestructiveCommands
implements Configurable
{
public function enabled () : bool {}
public function configure () : void {}
}

This code segment functions to: Control database command permissions based on the application environment state and implement conditional activation through configuration settings.

```php
[TASK_BEGIN]
final readonly class ProhibitDestructiveCommands implements Configurable
{
    public function enabled(): bool
    {
        return config('app.env') === 'production';
    }

    public function configure(): void
    {
        DB::listen(function ($query) {
            $sql = strtolower($query->sql);

            if (str_contains($sql, 'drop table') || str_contains($sql, 'truncate table')) {
                throw new \RuntimeException('Destructive SQL commands are prohibited in production.');
            }
        });
    }
}
[TASK_END]
```