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

Fun Laravel Package

php-standard-library/fun

Functional programming utilities for PHP: compose and pipe callables, decorate functions, and control execution (memoize, throttle, debounce, retry, etc.). Part of PHP Standard Library with focused, reusable helpers for cleaner functional-style code.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Add the package to your Laravel project:

    composer require php-standard-library/fun
    

    No service provider or configuration is needed—it’s a standalone utility library.

  2. First Use Case: Middleware Decoration Replace traditional middleware grouping with functional composition in app/Http/Kernel.php:

    use Fun\Decorators\decorate;
    use Fun\Compose\pipe;
    
    protected $middlewareGroups = [
        'web' => [
            decorate(
                \App\Http\Middleware\EncryptCookies::class,
                fn($next) => fn($request) => logger()->info('Encrypting cookies')
            ),
            // More middleware...
        ],
    ];
    
  3. First Use Case: Request Transformation Compose request transformations in a controller:

    use Fun\Compose\pipe;
    use Illuminate\Http\Request;
    
    public function store(Request $request)
    {
        $data = pipe(
            $request->all(),
            fn($data) => array_filter($data), // Filter empty values
            fn($data) => collect($data)->toArray(), // Ensure array
            fn($data) => $this->validateData($data) // Custom validation
        );
        // Process $data...
    }
    
  4. Where to Look First

    • Documentation: PHP Standard Library - Fun
    • Source Code: Focus on Fun/Compose (for pipelines) and Fun/Decorators (for wrapping).
    • Laravel Synergy: Explore how to integrate with Laravel’s pipe() helper or middleware stack.

Implementation Patterns

1. Middleware Composition

Pattern: Replace grouped middleware with functional decorators. Example:

// app/Http/Kernel.php
protected $middleware = [
    decorate(
        \App\Http\Middleware\TrimStrings::class,
        fn($next) => fn($request) => logger()->debug('Trimming strings', ['request' => $request->all()])
    ),
    decorate(
        \App\Http\Middleware\ValidateCsrfToken::class,
        fn($next) => fn($request) => $this->checkForJsonRequest($request)
    ),
];

Workflow:

  1. Identify cross-cutting concerns (logging, validation, auth).
  2. Wrap existing middleware with decorate().
  3. Chain decorators for pre/post-processing.

2. Service Layer Decoration

Pattern: Decorate repositories/services with cross-cutting concerns. Example:

// app/Services/UserService.php
class UserService {
    public function __construct(private UserRepository $repository) {}

    public function getWithDecorators(User $user) {
        return pipe(
            $this->repository->find($user->id),
            tap(fn($user) => logger()->info("Fetched user {$user->email}")),
            memoize(ttl(60)), // Cache for 60 seconds
        );
    }
}

Workflow:

  1. Extract business logic into a service.
  2. Use pipe() to chain transformations, logging, or caching.
  3. Leverage memoize() or retry() for performance/resilience.

3. Job/Command Pipelines

Pattern: Compose pre/post-processing in Laravel jobs or commands. Example:

// app/Jobs/ProcessOrder.php
public function handle() {
    $order = pipe(
        $this->fetchOrder(),
        tap(fn($order) => $this->logOrderCreation($order)),
        fn($order) => $this->validateOrder($order),
        fn($order) => $this->notifyCustomer($order),
    );
}

Workflow:

  1. Break down job logic into small functions.
  2. Use pipe() to chain them sequentially.
  3. Add tap() for side effects (logging, notifications).

4. Event Listener Composition

Pattern: Chain event listeners functionally. Example:

// app/Listeners/ProcessUserRegistered.php
public function handle(UserRegistered $event) {
    pipe(
        $event->user,
        tap(fn($user) => $this->sendWelcomeEmail($user)),
        tap(fn($user) => $this->logUserRegistration($user)),
        fn($user) => $this->createUserProfile($user),
    );
}

Workflow:

  1. Register the listener in EventServiceProvider.
  2. Use pipe() and tap() to compose side effects.

5. API Request/Response Transformation

Pattern: Transform requests/responses in route middleware. Example:

// app/Http/Middleware/TransformResponse.php
public function handle($request, Closure $next) {
    return pipe(
        $next($request),
        fn($response) => $response->setContent(json_encode($response->getContent(), JSON_PRETTY_PRINT)),
        fn($response) => $response->header('X-Transformed', 'true'),
    );
}

Workflow:

  1. Use pipe() to modify the response object.
  2. Register the middleware globally or per route.

6. Testing Helpers

Pattern: Create reusable test pipelines. Example:

// tests/TestHelpers.php
function assertPipeline($input, array $transformations, $expected) {
    $result = pipe($input, ...$transformations);
    $this->assertEquals($expected, $result);
}

// Usage in test
assertPipeline(
    ['name' => 'John', 'age' => 30],
    [
        fn($data) => array_filter($data),
        fn($data) => collect($data)->toArray(),
    ],
    ['name' => 'John']
);

Integration Tips

  1. Leverage Laravel’s Container Bind composed functions to the container for reuse:

    $this->app->bind('transform.request', fn() => pipe(
        fn($request) => $request->all(),
        fn($data) => array_filter($data),
    ));
    
  2. Combine with Laravel’s pipe() Use Fun\Compose\pipe alongside Laravel’s pipe() for consistency:

    use Fun\Compose\pipe as funPipe;
    use Illuminate\Support\Facades\Pipe;
    
    $result = funPipe($input, fn($x) => $x + 1);
    $laravelResult = Pipe::through($input, [fn($x) => $x * 2]);
    
  3. Type Safety with PHP 8.1+ Use typed closures for better IDE support:

    $add = fn(int $a, int $b): int => $a + $b;
    $result = $add(1, 2); // Type-checked
    
  4. Error Handling Wrap composed functions in try-catch or use Fun\Control\try:

    use Fun\Control\try;
    
    $result = try(
        fn() => pipe($data, fn($x) => $x / 0), // Will throw
        fn($e) => logger()->error($e->getMessage()),
        fn() => null
    );
    

Gotchas and Tips

Pitfalls

  1. Debugging Complexity

    • Issue: Stack traces for composed functions can be hard to follow.
    • Fix: Use Fun\Compose\tap to log intermediate values:
      $result = pipe(
          $data,
          tap(fn($x) => logger()->debug('Step 1', ['data' => $x])),
          fn($x) => $x * 2,
      );
      
  2. Performance Overhead

    • Issue: Deep composition (e.g., 10+ decorators) may impact performance.
    • Fix: Benchmark critical paths and avoid over-composing:
      // Bad: Too many decorators
      $slow = pipe($data, ...array_fill(0, 10, fn($x) => $x));
      
      // Good: Minimal composition
      $fast = pipe($data, fn($x) => $x + 1, fn($x) => $x * 2);
      
  3. Closure Scope Issues

    • Issue: Closures may not capture expected variables due to late binding.
    • Fix: Use use to bind variables explicitly:
      $userId = 1;
      $getUser = fn() => User::find($userId); // Late binding: $userId may change!
      
      // Fixed
      $getUser = fn() => User::find($userId); // Works if $userId is captured
      // OR
      $getUser = fn() use ($userId) => User::find($userId); // Explicit capture
      
  4. Laravel-Specific Quirks

    • Issue:
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope