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

Profile Laravel Package

cleaniquecoders/profile

Laravel package for adding and managing user profiles. It provides profile models, migrations, routes, and views so applications can store and maintain user profile data with less boilerplate, integrating cleanly with existing Laravel user models.

View on GitHub
Deep Wiki
Context7

Getting Started

The package provides a polymorphic profile record (Profile) that can be attached to any model via a morphMany relationship. It stores basic profile fields (name, email, phone, address, etc.) against a nullable profileable morph.

  1. Install via Composer:
composer install cleaniquecoders/profile
  1. Publish and run the migration (the package ships a migration for a profiles table):
php artisan vendor:publish --tag="profile-migrations"
php artisan migrate
  1. Add the trait/relationship to any model that should own a profile. The package typically exposes a HasProfile trait or expects you to add the morph relation:
use Cleaniquecoders\Profile\Traits\HasProfile;

class User extends Authenticatable
{
    use HasProfile;
}
  1. Read the package source first — it's small. Look at src/Models/Profile.php, the trait, and the migration to confirm fillable columns and method names. The README and src/ are your ground truth since the API is minimal.

First use case: creating a profile on user registration.

$user = User::create([...]);
$user->profile()->create([
    'full_name' => 'Jane Doe',
    'email' => '[email protected]',
    'phone' => '555-1234',
]);

Then resolve it anywhere:

$user->profile->full_name;

Implementation Patterns

Profile creation on registration (observer or event listener). Keep profile creation decoupled from the controller:

// app/Observers/UserObserver.php
public function created(User $user): void
{
    $user->profile()->create([
        'full_name' => $user->name,
        'email' => $user->email,
    ]);
}

This avoids the "user exists but no profile" trap and keeps registration logic clean.

Update-or-create pattern. Since a model technically can have many profiles (morphMany), guard against duplicates by using updateOrCreate. If you only ever want one profile per model, enforce a unique constraint on (profileable_type, profileable_id) in a follow-up migration:

$user->profile()->updateOrCreate(
    ['profileable_id' => $user->id],
    $request->validated()
);

Fluent accessor / helper method on the host model. Wrap the relation so controllers stay readable:

// in HasProfile trait, or your own trait
public function profileData(): Profile
{
    return $this->profile()->firstOrCreate([]);
}

Then ProfileData can lazily build an empty shell, which is useful for admin edit screens where a profile may not exist yet.

Form requests + validation. Put validation rules in a FormRequest keyed to the profile columns. Validate only columns you actually expose; don't mass-assign everything. Then pass $request->validated() straight to updateOrCreate.

Admin resource / Filament integration. Because Profile is a normal Eloquent model with a morph, you can register it directly in Filament/Nova as a related record (e.g., Fieldset or nested RelationManager). Use morphMany handling (ProfileResource related to User) — configure the relationship manager on the parent resource, not the child.

Multiple profileable types. The polymorph benefit is attaching profiles to non-User entities (organizations, teams, contacts). Model these explicitly:

class Organization extends Model { use HasProfile; }

This is the main reason to pick this package over just adding columns to users: you can reuse the exact profile schema across User, Organization, Vendor, etc., with a single migration.

API resources. Use an ApiResource to shape output. Because profile is nullable, guard it:

'profile' => $this->whenLoaded('profile', fn () => new ProfileResource($this->profile)),

Eager-load in list endpoints to avoid N+1: User::with('profile')->paginate().

Gotchas and Tips

  • morphMany means multiple profiles are structurally allowed. The package doesn't enforce one-profile-per-model. If that's a business rule, add a unique index on (profileable_type, profileable_id) and always use updateOrCreate, never create().
  • Null profile, always. $user->profile is null until created. Every blade template and accessor must handle null (optional($user->profile)->email). Prefer a firstOrCreate accessor to sidestep this.
  • Mass assignment. Confirm $fillable / $guarded on the Profile model before passing $request->all(). Publish the model (vendor:publish --tag="profile-models" if supported) so you can extend it with app-specific columns without editing vendor files.
  • Migration publishing. If the package has no config or publishable migration, copy the migration out of vendor/ into database/migrations manually and delete the duplicate from the package. Check src/ — the migration location is usually database/migrations.
  • Extending the schema. Need extra fields (avatar, bio, social links)? Create your own migration that adds columns to profiles rather than forking. Keeps package updates clean.
  • Polymorphic query filtering. When querying across profile types, use whereHasMorph or the profileable_type column. Remember morph types are the full class string — if you refactor a model's namespace, existing rows become stale. Use morph maps (Relation::morphMap([...])) to keep values stable.
  • Debugging relations. $user->profile caching bites when you update via $user->profile()->update() (query builder) — the loaded relation is stale. Use $user->profile()->update([...]); $user->refresh(); or set $user->profile->fill(...)->save().
  • Eager loading. Always with('profile') in index/API endpoints; otherwise each row triggers a separate query.
  • Deletion cascade. Profiles won't auto-delete unless you add morphMany(...)->cascadeOnDelete() or handle it in a deleting event. Add cascade to avoid orphan rows.
  • No built-in validation or UI. This is a data-layer package; the README may be sparse. Treat src/ as documentation. Read Profile.php and the trait before writing any code — the public API is a handful of methods and fillable fields.
  • Version drift. Pin the package version in composer.json since it's low-activity (14 stars, single maintainer). Review the changelog between updates; a morph schema change can silently break queries.
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.
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
noith/settings
kda/laravel-package