master

laravel/framework

Last updated at: 29/12/2023 09:22

ComponentMakeCommand.php

TLDR

The ComponentMakeCommand.php file in Illuminate\Foundation\Console namespace is a class that creates a new view component class. It extends the GeneratorCommand class and uses the CreatesMatchingTest trait. The class handles the console command execution, writes the view for the component, builds the component class, resolves the stub path, sets the default namespace, and provides console command options.

Methods

handle

This method executes the console command. If the view option is provided, it calls the writeView method. If the parent::handle method returns false and the force option is not provided, it returns false. Otherwise, it calls the writeView method.

writeView($onSuccess = null)

This method writes the view for the component. It generates the file path based on the view option, creates the necessary directory if it does not exist, checks if the view file already exists, and writes the view content. If an onSuccess callback is provided, it is called after writing the view.

buildClass($name)

This method builds the class with the given name. If the inline option is provided, it replaces the DummyView and {{ view }} placeholders with the inline view content. Otherwise, it replaces the placeholders with the view reference. It then calls the parent buildClass method and returns the result.

getView()

This method returns the view name relative to the components directory. It replaces the backslashes in the argument name with forward slashes, converts each part to kebab case, and joins them with dots.

getStub()

This method returns the stub file path for the generator. It resolves the path using the resolveStubPath method.

resolveStubPath($stub)

This method resolves the fully-qualified path to the stub. If the stub file exists at a custom path in the application, it returns the custom path. Otherwise, it returns the default stub path relative to the current file.

getDefaultNamespace($rootNamespace)

This method returns the default namespace for the generated class. It appends the View\Components namespace to the root namespace.

getOptions()

This method returns an array of console command options. It includes options for creating the class even if it already exists (force), creating an inline view component (inline), and creating an anonymous component with only a view (view).

<?php

namespace Illuminate\Foundation\Console;

use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Str;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputOption;

#[AsCommand(name: 'make:component')]
class ComponentMakeCommand extends GeneratorCommand
{
    use CreatesMatchingTest;

    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'make:component';

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

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

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        if ($this->option('view')) {
            $this->writeView(function () {
                $this->components->info($this->type.' created successfully.');
            });

            return;
        }

        if (parent::handle() === false && ! $this->option('force')) {
            return false;
        }

        if (! $this->option('inline')) {
            $this->writeView();
        }
    }

    /**
     * Write the view for the component.
     *
     * @param  callable|null  $onSuccess
     * @return void
     */
    protected function writeView($onSuccess = null)
    {
        $path = $this->viewPath(
            str_replace('.', '/', 'components.'.$this->getView()).'.blade.php'
        );

        if (! $this->files->isDirectory(dirname($path))) {
            $this->files->makeDirectory(dirname($path), 0777, true, true);
        }

        if ($this->files->exists($path) && ! $this->option('force')) {
            $this->components->error('View already exists.');

            return;
        }

        file_put_contents(
            $path,
            '<div>
    <!-- '.Inspiring::quotes()->random().' -->
</div>'
        );

        if ($onSuccess) {
            $onSuccess();
        }
    }

    /**
     * Build the class with the given name.
     *
     * @param  string  $name
     * @return string
     */
    protected function buildClass($name)
    {
        if ($this->option('inline')) {
            return str_replace(
                ['DummyView', '{{ view }}'],
                "<<<'blade'\n<div>\n    <!-- ".Inspiring::quotes()->random()." -->\n</div>\nblade",
                parent::buildClass($name)
            );
        }

        return str_replace(
            ['DummyView', '{{ view }}'],
            'view(\'components.'.$this->getView().'\')',
            parent::buildClass($name)
        );
    }

    /**
     * Get the view name relative to the components directory.
     *
     * @return string view
     */
    protected function getView()
    {
        $name = str_replace('\\', '/', $this->argument('name'));

        return collect(explode('/', $name))
            ->map(function ($part) {
                return Str::kebab($part);
            })
            ->implode('.');
    }

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

    /**
     * Resolve the fully-qualified path to the stub.
     *
     * @param  string  $stub
     * @return string
     */
    protected function resolveStubPath($stub)
    {
        return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
                        ? $customPath
                        : __DIR__.$stub;
    }

    /**
     * Get the default namespace for the class.
     *
     * @param  string  $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace.'\View\Components';
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return [
            ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the component already exists'],
            ['inline', null, InputOption::VALUE_NONE, 'Create a component that renders an inline view'],
            ['view', null, InputOption::VALUE_NONE, 'Create an anonymous component with only a view'],
        ];
    }
}