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

Nameable Laravel Package

watson/nameable

A Laravel package for giving Eloquent models human-readable names through a polymorphic relationship. Add the trait to any model to store and retrieve names without repeating name columns across tables.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package:
    composer require watson/nameable
    
  2. Add the trait to any Eloquent model that stores a person's name (usually User, but it works on Customer, Contact, Member, etc.):
    use Watson\Nameable\Nameable;
    
    class User extends Model
    {
        use Nameable;
    }
    
  3. Make sure the underlying table has the columns the package expects — by convention first_name and last_name. These are read from the model's attributes, so they can come from a base table, a joined table, or an accessor.
  4. Reach for the formatted accessors instead of concatenating strings yourself:
    $user->name_full;         // "John Smith"
    $user->name_familiar;     // "John"
    $user->name_abbreviated;  // "J. Smith"
    

Where to look first: the package is tiny — read the trait source (src/Nameable.php) before anything else. The whole surface area is a handful of accessors, so the README plus the trait file is the entire mental model. There is no config file, service provider magic, or migration to run.

First use case: replace hand-rolled $user->first_name . ' ' . $user->last_name in Blade templates with $user->name_full. The immediate win is consistency — every view, mail, and notification renders names the same way, and you have one place to change formatting later.

Implementation Patterns

Blade templates. Use the accessor at the point of display rather than pre-formatting in controllers:

{{-- Profile header --}}
<h2>{{ $user->name_full }}</h2>

{{-- Greeting in an email --}}
<p>Hi {{ $user->name_familiar }},</p>

{{-- Comment thread / avatar alt text --}}
<img src="{{ $user->avatar_url }}" alt="{{ $user->name_abbreviated }}">

API resources. Wrap the accessors in a resource so the contract is explicit and you can rename the JSON keys independently of the database:

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id'   => $this->id,
            'name' => [
                'full'        => $this->name_full,
                'familiar'    => $this->name_familiar,
                'abbreviated' => $this->name_abbreviated,
            ],
        ];
    }
}

Greetings and notifications. Pick the accessor based on tone. Transactional mail ("Hi Jane") is a good fit for name_familiar; formal documents and invoices read better with name_full; anything space-constrained (nav bars, mention chips, avatars) wants name_abbreviated.

Fallbacks for sparse profiles. Not every user will have a last name (mononyms, incomplete onboarding). Wrap reads in a small helper on the model or a presenter so views stay clean:

public function displayName(): string
{
    return $this->name_full ?: $this->email;
}

Keep queries on the real columns. Sorting and filtering still happen against first_name and last_name — the accessors are pure presentation and never touch the query builder:

User::orderBy('last_name')->orderBy('first_name')->paginate();

Compose with other name logic. If you have a "display name" preference (e.g. a prefers_full_name setting), branch on it in a view component rather than overriding the trait:

$display = $user->prefers_full_name
    ? $user->name_full
    : $user->name_familiar;

Gotchas and Tips

  • Hard-coded column names. The trait expects first_name and last_name. If your schema uses given_name / family_name, either add accessors mapping to the expected names or don't use the trait — there's little here to justify fighting the convention.
  • Accessors aren't queryable. User::where('name_full', 'John Smith') will fail. Any filter or sort must be expressed against the underlying columns, or you need a generated column / full-text index.
  • Not automatically serialized. Like any accessor, name_full won't appear in toArray() / toJson() unless you add it to $appends. If your app relies on implicit serialization, either append the properties or (better) expose them through an API resource.
  • Empty name parts produce double spaces or stray punctuation. A user with first_name = 'Cher' and last_name = null can yield "Cher " or "C." depending on the method. Normalize with trim() in a wrapper, and decide deliberately what name_abbreviated should mean for a single-token name.
  • Middle names, prefixes, and suffixes are out of scope. "Dr. John Q. Smith Jr." requires extending the model with your own accessors — treat the package as a starting point for the simple first + last case.
  • Name collisions. If you already define name_full, name_familiar, or name_abbreviated on the model, the trait's method is shadowed by the model's own. That's useful for customization but easy to forget when debugging "why isn't the package's format used here?"
  • Internationalization quirks. Names that don't follow given/family ordering (e.g. family-name-first conventions) will be formatted incorrectly by any Western-first logic. If you're shipping globally, plan to swap in locale-aware formatting rather than relying on the trait.
  • Low-maintenance dependency. This is a 30-star package with no dependents — treat it as a thin convenience, not load-bearing infrastructure. Pin it, but consider copying the handful of accessors into your own HasName trait if you want to guarantee future maintenance or extend the formatting rules; the surface area is small enough that the migration cost is negligible.
  • Testing. Set first_name / last_name explicitly in factories rather than relying on fake()->name(), which may produce a single string that won't split cleanly into the two columns.
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