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

Laravel Bento Laravel Package

exolnet/laravel-bento

Exolnet's Laravel Bento is a lightweight package for building modular dashboards from reusable widgets and cards. Compose responsive admin layouts, configure panels, and add metrics or custom views with a simple API, ideal for internal tools and admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements (as of v2.9.0): PHP 8.4+ and Laravel 12 only — Laravel 11 support was removed. Pin "exolnet/laravel-bento": "^2.9" and confirm your composer.json platform block before upgrading.

  1. Install and publish config:
    composer require exolnet/laravel-bento
    php artisan vendor:publish --tag=bento-config   # check `vendor:publish` output for the exact tag
    
  2. Populate .env with the credentials from Bento → Settings → API Keys:
    BENTO_SITE_UUID=
    BENTO_PUBLISHABLE_KEY=
    BENTO_SECRET_KEY=
    
    The publishable key is for client-side/inert use; the secret key is what server-side writes require. Never expose the secret key through a VITE_/MIX_ variable.
  3. The service provider and Bento facade are auto-discovered — no manual registration in config/app.php.
  4. Look here first, in order: config/bento.php (this is where timeouts/keys live), the Bento facade class in vendor/exolnet/laravel-bento/src, then the underlying bentonow/bento-php-sdk it proxies to. The facade method names track the SDK's resource groups (subscribers(), events()/track(), tags(), fields(), broadcasts()), so the SDK's README is your real API reference.

First use case: capture a signup. In a listener for Registered, call the subscriber-create endpoint with the user's email plus any custom fields you've already defined in Bento. Verify it landed in the Bento UI before building anything else on top — most integration pain here is field/tag mismatch, not PHP.

Implementation Patterns

Never call Bento from a controller. Wrap every outbound call in a queued job or a queued event listener so the HTTP round-trip never sits in the request cycle:

class SyncSubscriberToBento implements ShouldQueue
{
    public function handle(User $user): void
    {
        Bento::subscribers()->create([
            'email' => $user->email,
            'first_name' => $user->first_name,
        ]);
    }
}

Prefer constructor injection over the facade in domain services. Type-hint the client (or the package's manager) so tests can swap it; keep the Bento facade for tinker, artisan commands, and one-off scripts.

Define fields and tags before you send them. Bento silently ignores unknown custom fields, so a typo in plan_tier produces a clean 200 and zero data. Bootstrap them once in a migration-like artisan command (bento:sync-schema) that calls the fields/tags endpoints, and run it against each environment.

Model lifecycle events, not controllers. OrderPaid, SubscriptionCancelled, TrialStarted → one queued listener each. This keeps tracking declarative and means backfills can re-fire the same listeners via Event::dispatch or a replay command.

Bulk operations use the import endpoints. Looping create() over 10k users will hit rate limits and take hours. Batch through the import path (typically a CSV/file payload or a chunked array), 500–1000 rows per call, with Bus::batch() so you get progress and failure tracking.

Testing: the SDK talks HTTP underneath, so Http::fake() with URL pattern matching is the lowest-friction approach — assert on the request payload rather than mocking the wrapper. For unit tests, bind a mock of the client into the container in your TestCase::setUp().

Multi-tenant / multi-brand: the credentials come from config at resolution time, so config(['bento.secret_key' => $tenant->bento_key]) inside a scoped job works. Do it in a middleware or job constructor, never mid-request after other Bento calls have already fired.

Gotchas and Tips

  • v2.9.0 is a breaking release. Laravel 11 is dropped and the floor is PHP 8.4. If you're on Laravel 11 or PHP 8.3, stay on ^2.8 and pin it in composer.json; a loose ^2.0 constraint will pull 2.9 and fail resolution (or worse, resolve against a platform mismatch in CI). Audit composer.lock and any Docker images still on 8.3 before bumping.
  • Silent failures are the default failure mode. The API returns 2xx for payloads it partially discards. Always inspect the response body for per-record errors on bulk calls, and log the full response on non-2xx. A try/catch that swallows and returns null will cost you a day of debugging missing events.
  • Config caching bites on deploy. php artisan config:cache snapshots bento.*; if you write credentials at runtime from a database or vault, the cached config wins. Either exclude Bento from the cached file or read credentials inside the job rather than at boot.
  • Set an explicit HTTP timeout. Default Guzzle timeouts are generous enough to hold a queue worker hostage when Bento has a slow spell. Publish the config and set connect/read timeouts to something in the 2–5s range; pair with $tries = 3 and backoff() on the job.
  • Respect rate limits with release(). On 429, $this->release(60) from the job rather than retrying immediately — the SDK generally will not back off for you.
  • PII and logging. Emails and names flow through these payloads; Laravel's HTTP client logging or a debug dump of the request will put them in your logs. Scrub before logging, and confirm your DPA covers Bento as a subprocessor.
  • Deleting a user requires the email, and is irreversible. Bento's delete path is keyed on email; there's no ID to fall back on if a user changes address. If you support email changes, update Bento on change before the old address is gone from your DB.
  • Extension point: the service provider binds the client as a singleton — rebind it in a service provider of your own to wrap calls with logging, metrics, or a circuit breaker, rather than editing vendor code. This survives minor upgrades.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource