Weave 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

Smokescreen Laravel Package

rexlabs/smokescreen

Smokescreen provides configurable redaction for Laravel apps, helping keep passwords, tokens, and other sensitive values out of logs and exception reports. Define what to mask and reduce accidental data exposure during debugging.

View on GitHub
Deep Wiki
Context7

Getting Started

Smokescreen is a Fractal-style transformation layer: you write a transformer class per resource, and the library turns models/arrays into clean, serializable output. It sits between your models and your JSON responses, so controllers stay thin and API shape stays consistent.

Minimal setup:

composer require rexlabs/smokescreen

Look at these four things first, in this order:

  1. Transformer/AbstractTransformer — the base class you extend.
  2. Resource/Item and Resource/Collection — what a transformer returns when nested.
  3. The serializer (Serializer/DefaultSerializer or equivalent) — controls the final envelope.
  4. The manager/factory that ties transformer + data + serializer together.

First use case — a single transformer for one endpoint:

use Rexlabs\Smokescreen\Transformer\AbstractTransformer;

class UserTransformer extends AbstractTransformer
{
    public function transform(User $user): array
    {
        return [
            'id'    => $user->id,
            'name'  => $user->name,
            'email' => $user->email,
        ];
    }
}

Then transform one item and a collection through the manager, and toArray()/toJson() the result. Once that works, add one includeX() method for a relation — that is the 80% use case for this package.

Implementation Patterns

One transformer per resource, transform() returns a plain array. No queries, no formatting side effects, no conditionals on the request inside transform(). Anything request-dependent belongs in includes or in the controller.

Relationships via includes. Define $availableIncludes (whitelist) and $defaultIncludes (always rendered), and implement includeAuthor() style methods that return nested resources:

protected $availableIncludes = ['posts', 'company'];

public function includePosts(User $user)
{
    return $this->collection($user->posts, new PostTransformer());
}

public function includeCompany(User $user)
{
    return $this->item($user->company, new CompanyTransformer());
}

Drive includes from the query string, but whitelist them. Parse an ?include=posts,company parameter through the manager, and rely on $availableIncludes to reject anything unknown. Never let a client request an include that isn't declared, or you have an unbounded query surface.

Compose, don't duplicate. Nested $this->item(...) / $this->collection(...) calls are how you get consistent shapes across endpoints — the same PostTransformer used standalone and inside UserTransformer. Keep transformers reusable and dependency-free (constructor injection only for services like URL generators or formatters).

Wrap the manager as a singleton in Laravel. Bind the manager + chosen serializer once in a service provider, resolve it in a base controller or an ApiResponse helper, and keep transformers as ordinary classes. Typical controller:

return response()->json(
    $smokescreen->item($user, new UserTransformer())->toArray()
);

Paginate before transforming. Run the query with paginate(), hand the paginator to the manager/adapter, and transform the page's items. Transforming then slicing means you build every row's array for nothing.

Test transformers directly. They're pure functions of a model — instantiate the transformer, pass a factory-built model, assert the array with assertSame. This catches accidental schema drift faster than HTTP tests and needs no database round trip for simple cases.

Use a consistent envelope decision early. Default serializer vs. a data-wrapped serializer is a one-way door for your frontend. Pick once, document it, and route every endpoint through the same serializer instance.

Gotchas and Tips

  • Includes do not eager-load. Smokescreen renders whatever is on the model. Always with(['posts', 'company']) on the query before transforming, or you get N+1s that only appear when a client asks for includes. Add a Model::preventLazyLoading() in local/CI to catch it.
  • $defaultIncludes are viral. They apply to every use of that transformer, including nested ones, so a "small" default include can balloon a collection response. Prefer $availableIncludes and opt in per endpoint.
  • Transformers are reused across items in a collection. Don't stash per-item state on $this inside transform(); it will leak between rows. Pass values through return arrays or method arguments.
  • Entry-point class names have moved between versions. The transformer API is stable, but the manager/factory and serializer class names are worth confirming against the README of the exact version you install — this package has a small dependent base, so community examples are scarce and often stale. Read the source for the class you're actually using.
  • Null relations. includeCompany() on a user with no company still runs; return $this->item(null, ...) (or a null-safe check) rather than letting the transformer call methods on null. Decide now whether absent relations serialize as null or are omitted, and stay consistent.
  • Collection keys. Eloquent collections can carry non-sequential keys (e.g. after keyBy), which can serialize as a JSON object instead of an array. Reindex with values() before handing a collection to the transformer.
  • Pagination metadata lives outside the transformer. The transformer only sees items; meta/links come from the paginator adapter or you add them at the controller level. Don't try to inject pagination info from inside transform().
  • Debug by dumping the resource, not the response. Call ->toArray() on the item/collection before any HTTP layer mangles it — most "missing field" bugs are a serializer envelope or an include that silently didn't resolve.
  • Watch include recursion. Deeply nested includes or self-referencing transformers can loop. If you build dynamic include paths, cap the depth or explicitly exclude the parent relation.
  • Keep transform() side-effect free. Anything that writes, dispatches events, or hits the network makes collections non-deterministic and slows down list endpoints by an order of magnitude. Do that work in the controller/service, and let the transformer only shape data.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core