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

Engine Laravel Helper Laravel Package

betalabs/engine-laravel-helper

A Laravel helper package from Betalabs that bundles reusable utility functions for Engine-based applications. It streamlines common tasks so developers can avoid duplicating boilerplate across projects, keeping code cleaner and more consistent within the Betalabs ecosystem.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the Laravel integration layer for Betalabs Engine (ERP/back-office). It gives you Passport-backed API auth, tenant scoping, registry access, NFe tax-invoice indexing, and workflow condition enums — plus a thin wrapper over betalabs/engine-phpsdk.

Requirements (v6.x): PHP ^8.2 (tested against 8.5), Laravel 10/11/12, Passport 11 or 12, betalabs/engine-phpsdk ^3.0.

Minimal setup:

  1. composer require betalabs/engine-phpsdk:^3.0 alongside the package, and pin v6.0.2 — the v6.0.0 tag points at stale code and the whole 6.x line is superseded by 6.0.2.
  2. Publish config/migrations and run php artisan passport:install. On Passport 12, if the DB has no oauth_* tables yet: php artisan vendor:publish --tag=passport-migrations then php artisan migrate.
  3. Laravel 11/12: register the package routes in bootstrap/app.php (->withRouting(...)) and delete any Passport::routes() calls — that method no longer exists since Passport 11.
  4. Create the tenant's engine registry row with its engine_api_access_token before touching any service class; Services\Tenant\Updater will now throw a RuntimeException if it's absent.

First use case to validate the install end-to-end: an authenticated request that lists orders with a joined relation and sparse fields, e.g. GET /...?_fields=orders->code. That path exercises the API guard, the tenant global scope, and the v6.0.2 ambiguous-column fix in one shot.

Where to look first: Models\BelongsToTenant + Scopes\Tenant (data isolation), Services\Tenant\Updater (token/registry writes), Services\NFe\TaxInvoice\Indexer (fiscal documents). Also read the README's "Upgrading to 6.x" section before migrating anything from 5.x.

Implementation Patterns

Multi-tenancy via trait + global scope. Add BelongsToTenant to every tenant-owned model and stop writing manual where('tenant_id', ...) clauses. The scope resolves the tenant from the request context and — as of 6.0.2 — qualifies the column as tabela.tenant_id. That qualification is what makes JOIN-heavy listings (_fields=orders->code, eager relation fields) safe from "ambiguous column" errors. If you have raw query-builder joins outside Eloquent, still qualify tenant_id by hand; the scope only protects models it's attached to.

Registry selection is service-specific, not global. Two distinct behaviours to internalize:

  • Services\Tenant\Updater always writes engine_api_access_token into the engine registry, even when the tenant owns several registries. Previously it wrote to whichever registry came first — a real bug for multi-registry tenants.
  • Services\NFe\TaxInvoice\Indexer prefers the tenant's nfe registry when present, and otherwise falls back to whatever you set via setRegistryId(). So multi-registry tenants get NFe routing for free; single-registry tenants must set the ID explicitly.

Practical pattern: treat registries as named capability slots (engine, nfe, …) rather than an ordered list, and assert the slot exists at boot/seed time rather than discovering it at request time.

Branch on workflow operators via the enum. Models\Enums\WorkflowConditionOperator is now loadable (a missing quote broke class loading in earlier 6.x builds). Use it for match expressions when evaluating workflow conditions instead of string literals — it's the natural extension point if you need custom evaluation logic.

Wrap service classes, don't call them from controllers. Updater and Indexer do IO against the Engine API and can throw. Put them behind a job or an application service so RuntimeException from a missing engine registry becomes a retryable job failure with context, not a 500 on a user request.

Auth integration. The api guard is Passport-based; the suite fixes in 6.0.2 confirm the guard config is the supported path. Keep passport client secrets out of tenant config and in the service config.

Gotchas and Tips

  • Pin the tag. v6.0.0 resolves to old code. Require 6.0.2 explicitly in composer.json, not ^6.0, until you've verified what the constraint resolves to.
  • PHP 8.1 / engine-phpsdk 2.x users must stay on 5.x. This is a hard floor, not a soft deprecation.
  • Passport::routes() is gone. On Laravel 11/12 you register package routes in bootstrap/app.php. Leftover calls are a fatal error, not a warning.
  • Passport 12 needs published migrations. Symptom of skipping this: auth fails against missing oauth_* tables with no obvious config error.
  • Missing engine registry now throws RuntimeException with a clear message (previously a raw PHP error). Good news for debugging, but any code path that lazily created tenants without a registry will start failing loudly — seed the registry in your tenant-creation transaction.
  • The tenant_id ambiguity bug taught a lesson: if you wrote workarounds (aliased subqueries, manual qualified columns) for the old scope, revisit them after upgrading — they may now be redundant or, worse, conflicting.
  • Testing your own app against this: the package's own suite was broken from v4 through 6.0.1 and only fixed in 6.0.2 (45 tests / 158 assertions across Laravel 10–12, Passport 11 and 12, random order). If you inherited an app-level test harness that stubbed package internals, re-validate it — six package tests that previously asserted nothing now assert real calls, so behaviour that "passed" before may genuinely differ.
  • Dev toolchain: Testbench 8–10 and PHPUnit 10.5/11 are the supported matrix. Removed PHPUnit APIs will bite older test scaffolds.
  • Debugging tenant leaks: when a query returns another tenant's rows, check in this order — trait present on the model, relation loaded through a model that also uses the trait, then any withoutGlobalScopes() calls (they're the usual culprit). The qualified column now makes EXPLAIN/query-log reading easier since tenant_id is always table-prefixed.
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel