Laravel Package Core Showcase
Discover real-world examples and use cases of Laravel Package Core in action. See how this project uses the package as a foundation for provider bootstrapping, reusable CRUD services, runtime model extension, and response standardization.
Package Provider Foundation
Flow Service Provider Bootstrapping
Real implementation from packages/laravel-flow/src/FlowServiceProvider.php
Overview
FlowServiceProvider extends PackageCoreServiceProvider and uses the fluent PackageCore API to register package capabilities in one place. This includes config, migrations, routes, translations, dependency publishables, artisan commands, and service container aliases.
Key Features
- Fluent package setup with
configuration(PackageCore $package) - Container binding strategy via
registerClass - Dependency publishable registration
- Automatic command registration
- Post-boot event registry integration
Use Cases
- Building consistent package providers across a monorepo
- Sharing registration conventions between teams
- Reducing provider boilerplate in each package
- Ensuring deterministic bootstrap behavior
- Centralizing package lifecycle customization
Implementation Example
use JobMetric\PackageCore\PackageCore;
use JobMetric\PackageCore\PackageCoreServiceProvider;
use JobMetric\PackageCore\Enums\RegisterClassTypeEnum;
use JobMetric\Translation\TranslationServiceProvider;
class FlowServiceProvider extends PackageCoreServiceProvider
{
public function configuration(PackageCore $package): void
{
$package->name('laravel-workflow')
->hasConfig()
->hasMigration()
->hasRoute()
->hasTranslation()
->registerDependencyPublishable(TranslationServiceProvider::class)
->registerCommand(\JobMetric\Flow\Commands\MakeTask::class)
->registerClass('flow', \JobMetric\Flow\Services\Flow::class, RegisterClassTypeEnum::SINGLETON());
}
}
CRUD Service with Domain Logic
Flow Service Based on AbstractCrudService
Real implementation from packages/laravel-flow/src/Services/Flow.php
Overview
The Flow service inherits common CRUD behavior from AbstractCrudService and extends it with workflow-specific logic: START state initialization, default-flow switching with locking, rollout/window controls, consistency validation, and graph import/export.
Key Features
- Model/resource binding with static class properties
- Hook-based data shaping (
changeFieldStore,afterStore) - Lifecycle event mapping for CRUD actions
- Shared response contract via
Response::make - Transactional safety for stateful operations
Use Cases
- Package-level APIs that require consistent CRUD contracts
- Complex services that need hooks + transactions
- Entity-level event dispatching in reusable modules
- Advanced workflows with duplication/import/export
- Operations requiring deterministic cache invalidation
Implementation Example
use JobMetric\PackageCore\Services\AbstractCrudService;
use JobMetric\Flow\Models\Flow as FlowModel;
use JobMetric\Flow\Http\Resources\FlowResource;
use JobMetric\Flow\Events\Flow\FlowStoreEvent;
class Flow extends AbstractCrudService
{
protected bool $softDelete = true;
protected string $entityName = 'workflow::base.entity_names.flow';
protected static string $modelClass = FlowModel::class;
protected static string $resourceClass = FlowResource::class;
protected static ?string $storeEventClass = FlowStoreEvent::class;
protected function changeFieldStore(array &$data): void
{
$data = dto($data, \JobMetric\Flow\Http\Requests\Flow\StoreFlowRequest::class);
}
}
Dynamic Relation Extension in App Layer
Runtime Dynamic Relations
Real implementation from app/Models/Order.php
Overview
The Order model registers an orders relation on Member at boot time using addDynamicRelation. This makes cross-package model integration possible without hard-coding relation methods in upstream package models.
Key Features
- Boot-time relation injection
- Package-safe model extension pattern
- Polymorphic many-to-many compatibility
- No edits needed in dependency source code
- Works in modular domain boundaries
Use Cases
- Package integration in host application models
- Custom relation mapping per project
- Extensible membership/content/product modules
- Plugin-like architecture for relations
- Avoiding rigid compile-time coupling
Implementation Example
use JobMetric\Membership\Models\Member;
class Order extends Model
{
protected static function boot(): void
{
parent::boot();
Member::addDynamicRelation('orders', function ($model) {
return $model
? $model->morphedByMany(Order::class, 'memberable')
: (new Order)->morphedByMany(Member::class, 'memberable');
});
}
}
API Response Consistency with HasResponse
Controller Response Standardization
Real implementation from app/Http/Controllers/CategoryTestController.php
Overview
The controller uses HasResponse to keep single-item and collection responses consistent. This helps API endpoints return predictable structures while preserving custom message/status handling.
Key Features
response()helper for single payloadsresponseCollection()helper for resources- Automatic message/status defaults
- Additional metadata injection support
- Reduced duplicate JSON boilerplate
Use Cases
- Consistent API response contracts
- Controller-level response abstraction
- Mixed list/single endpoint patterns
- Package facade result wrapping
- Team-wide response style alignment
Implementation Example
use JobMetric\PackageCore\Controllers\HasResponse;
class CategoryTestController extends Controller
{
use HasResponse;
public function index(Request $request): JsonResponse
{
$category = Category::paginate(
$request->input('type'),
$request->input('filter', []),
$request->input('page_limit', 50),
$request->input('with', [])
);
return $this->responseCollection($category);
}
}
Get Started
Ready to implement these patterns in your package ecosystem?