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

Circle Contacts Module Laravel Package

tomatophp/circle-contacts-module

Circle Contacts is a TomatoPHP module that adds contact management to your Laravel app, letting you store, organize, and browse people and their details through a ready-made admin interface, with a simple structure you can extend for your own CRM or directory needs.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the first tagged release (v1.0.0) of tomatophp/circle-contacts-module, a contacts sub-module for the TomatoPHP Circle CRM stack. Release notes contain only a changelog link, so treat the source as the documentation.

Minimal steps:

composer require tomatophp/circle-contacts-module
php artisan vendor:publish --provider="TomatoPHP\CircleContacts\CircleContactsServiceProvider"
php artisan migrate

Before writing any code, read these in order:

  1. composer.json — confirms the required Laravel, PHP, tomatophp/circle and Filament/Tomato panel versions. This dictates everything else; a Filament major-version mismatch is the most common install failure.
  2. src/Providers/*ServiceProvider.php — shows what is auto-discovered, what is publishable (config, migrations, lang, views) and whether the Filament plugin/resource registers itself or must be added to a panel provider.
  3. config/circle-contacts.php (after publishing) — usually exposes table names, model class bindings and feature flags. This is your primary extension surface.
  4. database/migrations/ — check table names and foreign keys against your existing schema before running.
  5. src/Models/ and src/Filament/ — the actual contact entity and its admin UI.

First use case: if the panel plugin auto-registers, you get a Contacts resource in the Circle admin immediately — create a contact, attach it to a customer/lead, confirm the relation shows on the parent record. If it does not auto-register, add the plugin to your panel provider (->plugin(CircleContactsPlugin::make())) and verify the navigation group appears. If you are headless (API only), skip the UI and exercise the model + service layer directly in tinker.

Implementation Patterns

Treat the package models as base classes, not as your domain. The standard TomatoPHP pattern is a config-driven model swap: publish the config, point the model key at App\Models\Contact extends TomatoPHP\CircleContacts\Models\Contact, and add your own casts, scopes, accessors and relationships there. This survives package upgrades far better than editing vendor files. Verify the config key exists in v1.0.0 before relying on it; if it does not, bind your subclass in a service provider with $this->app->bind().

Relation managers on the parent resource. Contacts almost always hang off a customer/lead/company. Register the package's relation manager (or your own wrapping its table) on the parent Filament resource rather than building a second CRUD screen. This keeps one source of truth for contact editing and reuses the package's form schema.

Events over direct coupling. If you need to sync contacts to an external CRM, mail provider or audit log, listen on Eloquent model events (created, updated, deleted) or a package event class if one is dispatched. Observers registered in your own provider keep the integration out of the vendor namespace and are trivially testable.

API surface. For a JSON API, do not serialize the package model directly — wrap it in your own ContactResource. The package's attribute set will change between minor releases in a 1.x line, and leaking it into your public contract creates avoidable breaking changes.

Multi-tenancy / ownership. If contacts are team- or tenant-scoped, add a global scope in your subclass and confirm the package's Filament resource respects it. Filament resources that query the model directly will honour global scopes; ones using raw queries may not — check getQuery() / getTableQuery() in the resource.

Testing. Publish and use the package factories if present; otherwise define your own. Refresh the database per test and assert on your subclass, not the vendor class, so a future model swap is caught by the suite.

Feature flags in config. Anything you are unsure about — soft deletes, activity logging, duplicate detection — gate behind your own config entry so you can toggle behaviour per environment without a deploy.

Gotchas and Tips

  • 1.0.0 is stability in name only. This is the first tag; the public surface (config keys, Filament plugin API, event names) may still shift. Pin ^1.0 and read the diff of each release rather than assuming semver discipline.
  • Migrations should not be published blindly. Publishing copies them into database/migrations permanently; running package migrations keeps them updateable. Pick one strategy and be consistent — mixing both causes duplicate-table errors. Also check the contacts table name against any existing contacts table in your app.
  • Clear caches after publishing. php artisan config:clear and php artisan filament:optimize-clear (or optimize:clear) after publishing config or registering a plugin. Stale cached config is the usual cause of "my model swap is ignored".
  • Filament version lockstep. A Filament v3/v4 mismatch produces confusing class-not-found errors deep in the resource layer rather than a clean composer conflict. Confirm the constraint in the package's composer.json matches your panel before installing.
  • Auto-discovery vs. manual registration. If the panel has no Contacts entry, first check the provider actually implements the Filament plugin contract and that your panel provider is the one being booted (multiple panels is a common trap). php artisan about and php artisan filament:about narrow this quickly.
  • Unique email constraints fail late. Contact imports and seeders commonly trip the unique index. Catch QueryException on contacts.email and decide explicitly between upsert, skip, or error — do not let the framework surface a 500.
  • Seeder guard. Anything that seeds demo contacts must be disabled outside local. Wrap in app()->environment('local') checks.
  • N+1 in listings. The Contacts table typically renders company/owner columns. Eager-load those relations on the resource query; the package cannot know your relations.
  • Extension points, in order of safety: config-driven model binding → your own Filament resource replacing the package's → subclassing the resource → publishing views → editing vendor files (never). If you must override a resource, unregister the package's via the panel provider first, otherwise you get duplicate navigation entries.
  • Debugging checklist: composer constraints → provider booted → config published and cached cleared → migrations run → panel plugin registered → policy/gate permitting access. Authorization failures in Filament render as an empty or 403 page, which is easily mistaken for a broken install.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core