Laravel Example

Package Development

Learn how to create and distribute Laravel packages

Package Structure

Basic package setup and organization

Directory Structure

my-package/
├── src/
│   ├── MyPackageServiceProvider.php
│   ├── Facades/
│   │   └── MyPackage.php
│   └── MyPackage.php
├── config/
│   └── my-package.php
├── database/
│   ├── migrations/
│   └── factories/
├── resources/
│   ├── views/
│   └── lang/
├── routes/
│   └── web.php
├── tests/
│   ├── TestCase.php
│   └── Feature/
├── composer.json
├── phpunit.xml
└── README.md

Composer Configuration

{
    "name": "vendor/my-package",
    "description": "My awesome Laravel package",
    "type": "library",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Vendor\\MyPackage\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Vendor\\MyPackage\\Tests\\": "tests/"
        }
    },
    "extra": {
        "laravel": {
            "providers": [
                "Vendor\\MyPackage\\MyPackageServiceProvider"
            ],
            "aliases": {
                "MyPackage": "Vendor\\MyPackage\\Facades\\MyPackage"
            }
        }
    },
    "require": {
        "php": "^8.1",
        "illuminate/support": "^10.0"
    },
    "require-dev": {
        "orchestra/testbench": "^8.0",
        "phpunit/phpunit": "^10.0"
    }
}

Key Points

  • Organize code with standard structure
  • Setup autoloading with PSR-4
  • Define Laravel service provider
  • Specify dependencies and versions

Service Provider

Package registration and bootstrapping

Service Provider Class

namespace Vendor\MyPackage;

use Illuminate\Support\ServiceProvider;

class MyPackageServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Register the main class to use with the facade
        $this->app->singleton('my-package', function () {
            return new MyPackage();
        });

        // Register config
        $this->mergeConfigFrom(
            __DIR__.'/../config/my-package.php', 'my-package'
        );
    }

    public function boot()
    {
        // Publish configuration
        $this->publishes([
            __DIR__.'/../config/my-package.php' => config_path('my-package.php'),
        ], 'config');

        // Load routes
        $this->loadRoutesFrom(__DIR__.'/../routes/web.php');

        // Load views
        $this->loadViewsFrom(__DIR__.'/../resources/views', 'my-package');
        $this->publishes([
            __DIR__.'/../resources/views' => resource_path('views/vendor/my-package'),
        ], 'views');

        // Load migrations
        $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
        $this->publishes([
            __DIR__.'/../database/migrations/' => database_path('migrations')
        ], 'migrations');

        // Load translations
        $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'my-package');
        $this->publishes([
            __DIR__.'/../resources/lang' => resource_path('lang/vendor/my-package'),
        ], 'lang');
    }
}

Publishing Assets

# Publish all assets
php artisan vendor:publish --provider="Vendor\MyPackage\MyPackageServiceProvider"

# Publish specific tags
php artisan vendor:publish --provider="Vendor\MyPackage\MyPackageServiceProvider" --tag="config"
php artisan vendor:publish --provider="Vendor\MyPackage\MyPackageServiceProvider" --tag="views"

Key Points

  • Register services in register() method
  • Bootstrap package in boot() method
  • Publish assets with tags
  • Load routes, views, migrations, etc.

Facades & Configuration

Package API and settings

Facade Class

namespace Vendor\MyPackage\Facades;

use Illuminate\Support\Facades\Facade;

class MyPackage extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'my-package';
    }
}

Configuration File

// config/my-package.php
return [
    'api_key' => env('MY_PACKAGE_API_KEY'),
    
    'default_options' => [
        'timeout' => 30,
        'retries' => 3,
    ],
    
    'cache' => [
        'enabled' => true,
        'ttl' => 3600,
    ],
];

Key Points

  • Create facade for clean API
  • Centralize configuration
  • Use environment variables
  • Provide sensible defaults

Package Testing

Testing package functionality

Test Case Setup

namespace Vendor\MyPackage\Tests;

use Orchestra\Testbench\TestCase as Orchestra;
use Vendor\MyPackage\MyPackageServiceProvider;

class TestCase extends Orchestra
{
    protected function getPackageProviders($app)
    {
        return [
            MyPackageServiceProvider::class,
        ];
    }

    protected function getPackageAliases($app)
    {
        return [
            'MyPackage' => MyPackage::class,
        ];
    }

    protected function defineEnvironment($app)
    {
        // Setup default configuration
        $app['config']->set('my-package.api_key', 'test-key');
    }
}

Key Points

  • Use Orchestra Testbench
  • Setup package environment
  • Test all features and edge cases
  • Verify configuration handling