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

Approvals For Laravel Laravel Package

roundly-consulting/approvals-for-laravel

Approvals for Laravel adds flexible approval workflows to Eloquent models. Route records through approval chains, assign approvers, and track decisions with a simple API, making it easy to build review and sign-off processes into your Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is installed with Composer and, like most Laravel packages, registers its service provider through package discovery — there is usually no manual config/app.php edit required. Publish the package config before doing anything else:

composer require <vendor>/<package>
php artisan vendor:publish --tag=<package>-config

Where to look first, in order:

  1. The published config file — this is where the model map lives (the list of package contracts mapped to concrete Eloquent models). Almost every behaviour in the package is driven from this file, so read it end-to-end before writing code.
  2. The package service provider — check which bindings are registered as singletons versus bindings, since that determines whether a swap is picked up immediately or only on the next request.
  3. The shipped factories — these tell you which attributes the package expects and which model class it resolves by default.

First use case. The canonical first task is swapping a model in a host application: the package ships a default model (say Vendor\Package\Models\Post), you point the config at App\Models\Post, extend the package model, and confirm the package now reads and writes through your class. A minimal smoke test after the swap:

it('resolves the swapped model', function () {
    expect(config('package.models.post'))->toBe(\App\Models\Post::class)
        ->and(get_class(app(\Vendor\Package\Contracts\PostContract::class)))
        ->toBe(\App\Models\Post::class);
});

As of 1.2.5, the same test on the factory side is equally important — see below.

Implementation Patterns

Config-driven resolution, not hard-coded classes. The healthy pattern is to always ask the container or the config for the model class rather than referencing a concrete class in your own code:

$postClass = config('package.models.post');
$post = $postClass::create($data);

This keeps your host code compatible if you later swap again (multi-tenant setups, test doubles, or a future package default).

Subclass-and-extend for swaps. When swapping, extend the package model rather than rewriting it, and only override what actually differs:

namespace App\Models;

class Post extends \Vendor\Package\Models\Post
{
    protected $table = 'posts';

    protected $fillable = [/* widen as needed */];
}

Keep $table, $fillable, $casts, and any $appends in sync — the package's own queries and factories assume the parent's schema.

Factories follow the swap (1.2.5). This release fixes a real correctness bug: previously, calling a factory in a host app that had swapped the model could build the package's model instead of yours. The pattern to rely on now:

// In tests, after swapping config to App\Models\Post
$post = Post::factory()->create();

expect($post)->toBeInstanceOf(\App\Models\Post::class);
expect($post->getTable())->toBe('posts');

Prefer calling factory() on the swapped class (App\Models\Post::factory()) when your model defines newFactory(), and call the package factory directly only when you deliberately want the package's default shape. Add one assertion like the above for each swapped model — this is exactly the regression 1.2.5 addressed, so pin the behaviour in your suite rather than trusting it implicitly.

Isolate swaps in tests. Swap in setUp() and restore in tearDown() (or use a dedicated trait) so config leakage between tests does not silently change which model a later test exercises:

protected function setUp(): void
{
    parent::setUp();
    config(['package.models.post' => \App\Models\Post::class]);
}

Integration tip — seed and migrate together. Because factories now build the configured model, host migrations must exist before any package factory runs. In a fresh test database, ensure your host migration that creates/alters the table is ordered ahead of package seeders.

Cross-model relationships. When swapping a model that other package models relate to, verify the relation methods resolve through the container too. If a relation is hard-coded to the package class, override the relation method on your subclass and delegate:

public function author()
{
    return $this->belongsTo(config('package.models.user'));
}

Gotchas and Tips

  • Config caching hides swaps. php artisan config:cache in a deploy can leave stale model mappings. Always run php artisan config:clear after changing the model map, and make sure any runtime swap happens before the config is read — not after the provider has booted.
  • Singletons retain the old class. If the package registers a repository or manager as a singleton, swapping config mid-request will not change an already-resolved instance. Swap at the top of the request (or in a service provider's register()), not inside a controller or job.
  • Upgrading to 1.2.5 can change test outcomes. If you had worked around the old factory behaviour — for example by asserting against the package's default model class, or by manually new-ing your model in tests — those assertions may now fail. That is the fix working. Grep your tests for Vendor\Package\Models\ and update expectations to your swapped class.
  • Morph maps and polymorphic columns. Swapped models change the stored *_type values for polymorphic relations. If you swap after data exists, either add a morph map (Relation::enforceMorphMap([...])) or plan a data migration — the factory fix does not migrate existing rows.
  • Debugging which class is in play. get_class($model), $model->getTable(), and dd(config('package.models')) in php artisan tinker will answer "did the swap take?" faster than reading the provider. For factories specifically, dd(Post::factory()->make()::class) confirms 1.2.5 is doing its job.
  • Extension points to prefer. Config model map → model subclass → published factories → published migrations, in that order. Overriding package classes in app/ via PSR-4 shadowing works but breaks on package updates; avoid it unless the package documents support for it.
  • Keep the patch current. 1.2.5 is a low-risk patch with no API changes, so there is no reason to remain on 1.2.4 — but pin the version in composer.json and re-run your model-swap tests in CI, since factory/model resolution is now a behavioural contract you depend on.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console