Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Canvas Core Laravel Package

orchestra/canvas-core

Core utilities for Orchestra Canvas code generators. Build and customize generators for Laravel apps and packages, with testing and coverage support. Provides the foundational services used by Canvas to scaffold code and streamline development workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require orchestra/canvas-core
    

    For Laravel 11.x, target orchestra/canvas-core:^10.0 (check compatibility notes).

  2. First Use Case: Create a basic generator command by extending Orchestra\Canvas\Core\GeneratorCommand:

    use Orchestra\Canvas\Core\GeneratorCommand;
    
    class MakeApiResource extends GeneratorCommand
    {
        protected $name = 'make:api-resource';
        protected $description = 'Create a new API resource with controller, model, and migrations';
        protected $type = 'ApiResource';
    
        public function configure()
        {
            $this->option('with-tests', null, 'Generate test stubs');
            $this->option('with-migrations', null, 'Generate migrations');
        }
    
        protected function getStub()
        {
            return __DIR__.'/stubs/api-resource.stub';
        }
    
        protected function getDefaultNamespace($rootNamespace)
        {
            return $rootNamespace.'\Http\Controllers\Api';
        }
    }
    
  3. Register the Command: Add the command to app/Console/Kernel.php:

    protected $commands = [
        \App\Console\Commands\MakeApiResource::class,
    ];
    
  4. Run It:

    php artisan make:api-resource User --with-tests
    

Where to Look First


Implementation Patterns

Core Workflows

1. Basic Generator

Extend GeneratorCommand for simple scaffolding (e.g., controllers, models):

class MakeDomainService extends GeneratorCommand
{
    protected $name = 'make:domain-service';
    protected $description = 'Create a new domain service';
    protected $type = 'DomainService';

    protected function getStub()
    {
        return __DIR__.'/stubs/domain-service.stub';
    }

    protected function getNamespace($targetNamespace)
    {
        return $targetNamespace.'\Services';
    }
}

2. Interactive Prompts

Use Laravel’s PromptsForMissingInput concern for dynamic inputs:

use Illuminate\Console\Concerns\PromptsForMissingInput;

class MakeFeatureFlag extends GeneratorCommand
{
    use PromptsForMissingInput;

    protected function promptForMissingInput()
    {
        $this->ask('Feature flag name', null, function ($name) {
            return Str::of($name)->kebab();
        });
    }
}

3. Presets for Consistency

Define reusable configurations in app/Canvas/Presets/ApiResourcePreset.php:

namespace App\Canvas\Presets;

use Orchestra\Canvas\Core\Presets\Preset;

class ApiResourcePreset extends Preset
{
    public function namespace()
    {
        return 'App\Http\Controllers\Api';
    }

    public function stub()
    {
        return __DIR__.'/../../Console/Commands/stubs/api-resource.stub';
    }

    public function migrationsNamespace()
    {
        return 'App\Migrations';
    }
}

Register the preset in AppServiceProvider:

public function boot()
{
    Canvas::preset('api-resource', ApiResourcePreset::class);
}

4. Post-Generation Actions

Use GeneratesCodeListener for post-processing (e.g., run migrations, publish configs):

use Orchestra\Canvas\Core\GeneratesCodeListener;

class RunMigrationsAfterGeneration implements GeneratesCodeListener
{
    public function afterCodeHasBeenGenerated($command, $name, $path)
    {
        if (Str::contains($command, 'make:api-resource') && $this->option('with-migrations')) {
            Artisan::call('migrate', ['--path' => 'database/migrations']);
        }
    }
}

Bind the listener in AppServiceProvider:

public function boot()
{
    Canvas::listen(RunMigrationsAfterGeneration::class);
}

5. Multi-Step Generators

Chain commands using orchestra/workbench (included via orchestra/sidekick):

use Orchestra\Workbench\Actions\Action;
use Orchestra\Workbench\Actions\Artisan;

class MakeModule extends GeneratorCommand
{
    protected function handle()
    {
        $actions = [
            new Artisan('make:model', ['name' => $this->argument('name')]),
            new Artisan('make:controller', ['name' => 'ModuleController']),
            new Artisan('make:migration', ['name' => 'create_'.$this->argument('name').'_table']),
        ];

        Action::run($actions);
    }
}

Integration Tips

  • Stub Management: Store stubs in resources/stubs/ or a dedicated stubs/ directory in your package.
  • Testing: Use orchestra/testbench-core to test generators in isolation.
  • CI/CD: Trigger generators via GitHub Actions or GitLab CI:
    # .github/workflows/generate.yml
    jobs:
      generate:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: shivammathur/setup-php@v2
          - run: composer install
          - run: php artisan make:api-resource User --with-tests
    
  • Monorepos: Scope generators to specific directories using getPath():
    protected function getPath($name)
    {
        return $this->laravel->basePath("modules/{$name}/src");
    }
    

Gotchas and Tips

Pitfalls

  1. Laravel Version Mismatches:

    • v10.x targets Laravel 12/13 (unverified; avoid for production).
    • v8.x targets Laravel 10.x (stable but drops older support).
    • Fix: Pin to orchestra/canvas-core:^8.11 for Laravel 10.x or wait for Orchestra’s validation of v11.x.
  2. Stub Path Resolution:

    • Hardcoding stub paths (e.g., __DIR__.'/stubs/...') breaks when moving generators to packages.
    • Fix: Use Illuminate\Filesystem\join_paths() or base_path():
      protected function getStub()
      {
          return join_paths(__DIR__, '..', '..', 'stubs', 'api-resource.stub');
      }
      
  3. Null Generators Config:

    • Passing null to generators() in presets causes runtime errors.
    • Fix: Ensure presets return an array:
      public function generators()
      {
          return [
              'controller' => ControllerGenerator::class,
          ];
      }
      
  4. Deprecated Methods:

    • possibleModelsUsingCanvas() is soft-deprecated in v10.1.1.
    • Fix: Use Laravel’s native possibleModels() instead.
  5. PHP Attributes Overhead:

    • v8.10.1+ uses PHP Attributes, which may require PHP 8.0+.
    • Fix: Downgrade to v8.9.x if using PHP 7.4.
  6. Sidekick Dependency:

    • orchestra/sidekick is a hidden dependency (required for orchestra/workbench actions).
    • Fix: Explicitly require it in composer.json:
      "require": {
          "orchestra/sidekick": "^5.0"
      }
      

Debugging Tips

  • Dry Runs: Add --dry-run to test generators without writing files:
    if ($this->option('dry-run')) {
        $this->info("Would generate: {$this->getPath($name)}");
        return;
    }
    
  • Stub Debugging: Use dd($this->getStub()) to verify stub paths.
  • Listener Debugging: Log in GeneratesCodeListener:
    public function afterCodeHasBeenGenerated($command, $name, $path)
    {
        \Log::info("Generated {$path} via {$command}");
    }
    
  • Command Introspection: Dump command options:
    $this->info("Options: " . print_r($this->options(), true));
    

Extension Points

  1. Custom Generators:
    • Extend Orchestra\Canvas\Core\GeneratorCommand for new scaffolding types.
    • Example: make:domain-event for C
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport