PHPackages                             andrebhas/laravel-brick - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. andrebhas/laravel-brick

ActiveLibrary[Testing &amp; Quality](/categories/testing)

andrebhas/laravel-brick
=======================

Build modular monolith Laravel applications with a solid foundation. Each module is a 'brick' that can be stacked wisely. Includes an optional internal bridge with async support, circuit breaker, and Pest testing.

v1.0.0(3mo ago)00MITPHPPHP ^8.1

Since Mar 4Pushed 3mo agoCompare

[ Source](https://github.com/andrebhas/laravel-brick)[ Packagist](https://packagist.org/packages/andrebhas/laravel-brick)[ RSS](/packages/andrebhas-laravel-brick/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (12)Versions (2)Used By (0)

🧱 Laravel Brick
===============

[](#-laravel-brick)

Build modular Laravel applications with a solid foundation. Each module is an independent, self-contained unit (a "brick") that can be composed into robust, scalable applications using Domain-Driven Design principles.

> **"Each module is a brick. Stack them wisely."**

[![PHP](https://camo.githubusercontent.com/8e58b490725ac49cc8e463c473173681b324c9d92d7854275a785db013ca3de7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d3737374242343f6c6f676f3d706870)](https://php.net)[![Laravel](https://camo.githubusercontent.com/5a0f1cd13d9c994a470f0e1412cc07eacb2cb4b0facf1ddf542b89adb5b9770e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d392e7825323025374325323031302e7825323025374325323031312e782d4646324432303f6c6f676f3d6c61726176656c)](https://laravel.com)[![License](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![Tests](https://camo.githubusercontent.com/dec73264999400b668ee27aea374504f315088c1f751eb418ddbebf0c5161236/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f54657374732d506573742d677265656e)](https://pestphp.com)

---

✨ Features
----------

[](#-features)

FeatureDescription🏗 **Modular Core**Create isolated modules with a standard DDD structure🌉 **Internal Bridge**Optional typed, validated cross-module communication⚡ **Async Calls**Dispatch bridge calls to queues, poll results by job ID🛡 **Circuit Breaker**Protect against cascading failures (closed/open/half-open)🔗 **Middleware Pipeline**Logging, circuit breaker, caching per bridge call🧪 **Pest Testing**Auto-generate test scaffolding with every module📦 **Module Dependencies**Modules declare dependencies; enable/disable with checks⚙️ **Per-Module Config**Each module has its own `Config/config.php`🎨 **Asset Publishing**Copy or symlink module assets to `public/bricks/`🚀 **Octane Compatible**No static state; fully safe for Laravel Octane---

📋 Requirements
--------------

[](#-requirements)

- PHP **8.1** or higher
- Laravel **9.x**, **10.x**, or **11.x**

---

📦 Installation
--------------

[](#-installation)

```
composer require andrebhas/laravel-brick
```

The package uses Laravel's auto-discovery. The service provider is registered automatically.

### Publish Configuration

[](#publish-configuration)

```
php artisan vendor:publish --tag=brick-config
```

### Publish Stubs (optional, to customise scaffolding)

[](#publish-stubs-optional-to-customise-scaffolding)

```
php artisan vendor:publish --tag=brick-stubs
```

---

🗂 Module Structure
------------------

[](#-module-structure)

### Layer-Driven Architecture (Default)

[](#layer-driven-architecture-default)

After running `php artisan brick:make`, each module follows this structure:

```
bricks/
└── Hotel/
    ├── module.json                  # Module manifest
    ├── Actions/
    │   └── CreateHotelAction.php
    ├── Models/
    │   └── Hotel.php
    ├── Repositories/
    │   ├── HotelRepositoryInterface.php
    │   └── EloquentHotelRepository.php
    ├── Services/
    │   └── HotelService.php
    ├── Bridge/                      # Optional: inter-module communication
    │   └── HotelBridge.php
    ├── Http/
    │   ├── Controllers/
    │   └── Requests/
    ├── Database/
    │   ├── Migrations/
    │   └── Seeders/
    ├── Routes/
    │   ├── api.php
    │   └── web.php
    ├── Resources/
    │   ├── views/
    │   ├── lang/
    │   └── assets/
    ├── Config/
    │   └── config.php
    ├── Providers/
    │   └── HotelServiceProvider.php
    ├── tests/
    │   ├── Pest.php
    │   ├── Feature/
    │   └── Unit/
    └── README.md

```

### Feature-Driven Architecture

[](#feature-driven-architecture)

If you prefer to organizer your module by business features rather than technical layers, you can use the `--features` flag (or answer `yes` during the interactive prompt). This replaces the `Actions` directory with a `Features` directory:

```
bricks/
└── Hotel/
    ├── Features/
    │   └── CreateHotel/                     # A cohesive, isolated feature
    │       ├── CreateHotelAction.php        # Core logic
    │       ├── CreateHotelRequest.php       # Specific validation
    │       ├── CreateHotelResponse.php      # Formatting Output
    │       └── CreateHotelFeatureTest.php   # Feature tests lives here
    ├── Models/
    ├── Http/
    └── ... (other standard directories)

```

---

🚀 Quick Start
-------------

[](#-quick-start)

### 1. Create a Module

[](#1-create-a-module)

```
php artisan brick:make
```

Interactive flow:

```
Nama modul:
 > Hotel

Deskripsi modul (opsional):
 > Modul manajemen hotel

Versi modul [1.0.0]:
 >

Buat jembatan (bridge)? (yes/no) [no]:
 > yes

Buat rute API? (yes/no) [no]:
 > yes

Buat rute web? (yes/no) [no]:
 > no

Buat tes (Pest)? (yes/no) [yes]:
 > yes

Gunakan struktur Feature-Driven? (yes/no) [no]:
 > yes

Membuat modul...
✓ Module [Hotel] created successfully

```

Or non-interactively:

```
php artisan brick:make Hotel --with-bridge --with-api --with-tests --features
```

### 2. Register the Module's Namespace

[](#2-register-the-modules-namespace)

Add to `composer.json`:

```
{
    "autoload": {
        "psr-4": {
            "Bricks\\Hotel\\": "bricks/Hotel/"
        }
    }
}
```

Then regenerate autoload:

```
composer dump-autoload
```

### 3. Enable the Module

[](#3-enable-the-module)

```
php artisan brick:enable Hotel
```

### 4. Run Migrations

[](#4-run-migrations)

```
php artisan brick:migrate Hotel
```

---

📄 Module Manifest (`module.json`)
---------------------------------

[](#-module-manifest-modulejson)

```
{
    "name": "Hotel",
    "description": "Modul manajemen hotel",
    "version": "1.0.0",
    "namespace": "Bricks\\Hotel",
    "active": true,
    "order": 0,
    "dependencies": ["Auth"],
    "bridge": {
        "class": "Bricks\\Hotel\\Bridge\\HotelBridge"
    },
    "author": {
        "name": "Andre Bhaskoro"
    }
}
```

---

🌉 Bridge: Cross-Module Communication
------------------------------------

[](#-bridge-cross-module-communication)

### 1. Implement the Bridge

[](#1-implement-the-bridge)

```
namespace Bricks\Hotel\Bridge;

use AndreBhas\Brick\Brick\Bridge\Contracts\Bridgeable;

class HotelBridge implements Bridgeable
{
    public static function getBridgeName(): string
    {
        return 'Hotel';
    }

    public static function getExposedMethods(): array
    {
        return ['getById', 'checkAvailability'];
    }

    public function getById(int $id): array
    {
        // Fetch hotel data...
        return ['id' => $id, 'name' => 'Grand Hotel'];
    }

    public function checkAvailability(int $hotelId, string $date): bool
    {
        return true;
    }
}
```

### 2. Synchronous Call (from another module)

[](#2-synchronous-call-from-another-module)

```
use AndreBhas\Brick\Brick\Bridge\InternalGateway;

$gateway = app(InternalGateway::class);

// Goes through middleware pipeline (logging, circuit breaker, etc.)
$hotel = $gateway->call('Hotel', 'getById', 42);
```

### 3. Asynchronous Call

[](#3-asynchronous-call)

```
// Dispatch to queue, get a job ID
$jobId = $gateway->callAsync('Hotel', 'getById', 42);

// Later, poll for the result
$result = $gateway->getAsyncResult($jobId);
// ['status' => 'success', 'result' => [...], 'completed_at' => '...']
// or
// ['status' => 'pending', 'queued_at' => '...']
// or
// ['status' => 'failed', 'error' => '...']
```

### 4. Generate Bridge for Existing Module

[](#4-generate-bridge-for-existing-module)

```
php artisan brick:make-bridge Hotel
```

---

🛡 Circuit Breaker
-----------------

[](#-circuit-breaker)

The circuit breaker prevents cascading failures when a module's bridge is unreliable.

### States

[](#states)

- **Closed** 🟢 — Normal operation; calls pass through
- **Open** 🔴 — Failures exceeded threshold; calls rejected immediately
- **Half-Open** 🟡 — Testing recovery with limited trial calls

### Configuration (`config/brick.php`)

[](#configuration-configbrickphp)

```
'circuit_breaker' => [
    'default' => [
        'threshold'              => 5,  // failures before opening
        'timeout'                => 30, // seconds before half-open
        'half_open_max_attempts' => 3,
    ],
],
```

### Status Command

[](#status-command)

```
php artisan brick:bridge:status
```

```
+--------+------------+---------------+
| Bridge | State      | Failure Count |
+--------+------------+---------------+
| Hotel  | ● CLOSED   | 0             |
| Auth   | ● OPEN     | 7             |
+--------+------------+---------------+

```

### Manual Reset

[](#manual-reset)

```
php artisan brick:bridge:status --reset=Hotel
```

---

🧪 Testing
---------

[](#-testing)

### Package Tests

[](#package-tests)

```
composer test
```

### Module Tests (Pest)

[](#module-tests-pest)

Each generated module includes its own tests directory with Pest setup:

```
# Run a specific module's tests
./vendor/bin/pest bricks/Hotel/tests/
```

### Testing Helpers

[](#testing-helpers)

#### `BridgeFake` – Mock bridge calls in tests

[](#bridgefake--mock-bridge-calls-in-tests)

```
use AndreBhas\Brick\Brick\Testing\BridgeFake;
use AndreBhas\Brick\Brick\Bridge\InternalGateway;

$fake = new BridgeFake(
    container: app(),
    cache: app('cache')->store(),
    queue: app('queue'),
);

// Register a fake response
$fake->shouldReceive('Hotel', 'getById', fn ($id) => ['id' => $id, 'name' => 'Test Hotel']);

// Swap in the container
app()->instance(InternalGateway::class, $fake);

// ... run your code ...

// Assert calls
$fake->assertCalled('Hotel', 'getById', 1);
$fake->assertNotCalled('Hotel', 'delete');
$fake->assertNothingCalled(); // if no calls expected
```

#### `CircuitBreakerFake` – Simulate circuit states

[](#circuitbreakerfake--simulate-circuit-states)

```
use AndreBhas\Brick\Brick\Testing\CircuitBreakerFake;
use AndreBhas\Brick\Brick\Bridge\CircuitBreaker;

$fake = new CircuitBreakerFake();
$fake->forceOpen('Hotel');    // simulate open circuit
$fake->forceHalfOpen('Payment');
$fake->forceClose('Auth');

app()->instance(CircuitBreaker::class, $fake);
```

### Generate Test File

[](#generate-test-file)

```
# Feature test
php artisan brick:make-test Hotel HotelAvailability --type=feature

# Unit test
php artisan brick:make-test Hotel HotelPricing --type=unit
```

---

🎮 Artisan Commands Reference
----------------------------

[](#-artisan-commands-reference)

CommandDescription`brick:make`Create a new module interactively`brick:make-feature {module} {feature}`Scaffold a full feature (Action, Request, etc)`brick:make-action {module} {name}`Generate an Action class`brick:make-request {module} {name}`Generate a FormRequest class`brick:make-response {module} {name}`Generate a Response/Resource class`brick:make-job {module} {name}`Generate a specific Job`brick:make-event {module} {name}`Generate an Event`brick:make-listener {module} {name}`Generate a Listener`brick:make-bridge {module}`Generate bridge for a module`brick:make-test {module} {name}`Generate a Pest test file`brick:bridge:status`Show circuit breaker status for all bridges`brick:enable {module}`Enable a module (checks dependencies)`brick:disable {module}`Disable a module (checks dependents)`brick:publish-assets {module?}`Publish module assets to public/`brick:migrate {module}`Run module migrations`brick:rollback {module}`Rollback module migrations`brick:refresh {module}`Refresh (rollback + re-run) module migrations`brick:seed {module}`Run module seeders### Command Options

[](#command-options)

```
# Enable with --force to skip dependency check
php artisan brick:enable Hotel --force

# Disable with --force to skip dependents check
php artisan brick:disable Hotel --force

# Publish assets as symlinks
php artisan brick:publish-assets Hotel --symlink

# Run specific number of rollback steps
php artisan brick:rollback Hotel --step=2

# Refresh and seed
php artisan brick:refresh Hotel --seed

# Run specific seeder class
php artisan brick:seed Hotel --class="Bricks\\Hotel\\Database\\Seeders\\HotelDemoSeeder"
```

---

⚙️ Configuration Reference
--------------------------

[](#️-configuration-reference)

```
// config/brick.php

return [
    // Root directory for all modules
    'modules_path' => base_path('bricks'),

    'bridge' => [
        'enabled' => env('BRICK_BRIDGE_ENABLED', true),

        // Middleware applied to every synchronous bridge call
        'middlewares' => [
            \AndreBhas\Brick\Brick\Bridge\Middleware\LoggingMiddleware::class,
            \AndreBhas\Brick\Brick\Bridge\Middleware\CircuitBreakerMiddleware::class,
            // \AndreBhas\Brick\Brick\Bridge\Middleware\CacheMiddleware::class,
        ],

        'circuit_breaker' => [
            'default' => [
                'threshold' => 5,
                'timeout'   => 30,
                'half_open_max_attempts' => 3,
            ],
        ],

        'queue'       => env('BRICK_BRIDGE_QUEUE', 'default'),
        'cache_store' => env('BRICK_BRIDGE_CACHE', null),
        'cache_ttl'   => 3600,
    ],

    'assets' => [
        'publish_method' => env('BRICK_ASSETS_METHOD', 'copy'), // 'copy' or 'symlink'
        'public_path'    => public_path('bricks'),
    ],

    'dependencies' => [
        'auto_enable' => env('BRICK_AUTO_ENABLE_DEPENDENCIES', false),
    ],
];
```

### Environment Variables

[](#environment-variables)

VariableDefaultDescription`BRICK_BRIDGE_ENABLED``true`Enable/disable the bridge globally`BRICK_BRIDGE_QUEUE``default`Queue for async bridge calls`BRICK_BRIDGE_CACHE``null`Cache store for circuit breaker &amp; async results`BRICK_ASSETS_METHOD``copy`Asset publishing method (`copy` or `symlink`)`BRICK_AUTO_ENABLE_DEPENDENCIES``false`Auto-enable missing dependencies---

🔧 Adding Custom Middleware
--------------------------

[](#-adding-custom-middleware)

Create a middleware class:

```
namespace App\Brick\Middleware;

use Closure;

class RateLimitMiddleware
{
    public function handle(Closure $next, string $bridge, string $method, array $args): mixed
    {
        // Rate limiting logic...
        return $next($bridge, $method, $args);
    }
}
```

Register in `config/brick.php`:

```
'middlewares' => [
    \AndreBhas\Brick\Brick\Bridge\Middleware\LoggingMiddleware::class,
    \AndreBhas\Brick\Brick\Bridge\Middleware\CircuitBreakerMiddleware::class,
    \App\Brick\Middleware\RateLimitMiddleware::class, //  **"Each module is a brick. Stack them wisely."** — andrebhas/laravel-brick

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance80

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

110d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/64f5c20aa211d6af883d2d36fd1009b293e2ff3ff3b6c653f926bf98b7a8ae07?d=identicon)[andrebhas](/maintainers/andrebhas)

---

Top Contributors

[![andrebhas](https://avatars.githubusercontent.com/u/7027044?v=4)](https://github.com/andrebhas "andrebhas (1 commits)")[![andrebhas-lgq](https://avatars.githubusercontent.com/u/134689139?v=4)](https://github.com/andrebhas-lgq "andrebhas-lgq (1 commits)")

---

Tags

asyncpestlaravelbrickmoduleBridgeDomain Driven Designdddmodularcircuit breaker

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/andrebhas-laravel-brick/health.svg)

```
[![Health](https://phpackages.com/badges/andrebhas-laravel-brick/health.svg)](https://phpackages.com/packages/andrebhas-laravel-brick)
```

###  Alternatives

[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9742.3M121](/packages/roots-acorn)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k14.1M122](/packages/laravel-pulse)[laravel/ai

The official AI SDK for Laravel.

9782.1M162](/packages/laravel-ai)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[flarum/core

Delightfully simple forum software.

201.4M2.2k](/packages/flarum-core)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
