DEV Community

Benjamin Delespierre
Benjamin Delespierre

Posted on

3 3

Identify models using their name with Laravel

Some database objects are atomic - i.e. they're just a name. Think of a Tag, think of a Role, think of a Country... There's really nothing more than the name - or at least the other properties are entirely optional. In such cases you might want an unique index on the name property, wouldn't you?

Now the name uniquely identifies your object, why not use the name to fetch it?

// instead of...
$role = Role::where('name', '=', 'admin')->firstOrCreate([]);

// ...you want to do 
$role = Role::wrap('admin');
Enter fullscreen mode Exit fullscreen mode

Well, that's precisely what today's snippet does for you!

Note: the following trait has been designed to create objects that are not found. If you want to protect yourself from typos being written in database I suggest you define the setNameAttribute method to implement the security you need.

Implementation

app/HasName.php

namespace App;

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection;

trait HasName
{
    public static function findFromName(string $name): self
    {
        return self::whereName($name)->firstOrFail();
    }

    public static function findOrCreate(string $name): self
    {
        try {
            return self::findFromName($name);
        } catch (ModelNotFoundException $e) {
            return self::create(compact('name'));
        }
    }

    public static function wrap($name): self
    {
        if (is_string($name)) {
            $name = self::findOrCreate($name);
        }

        if (is_array($name)) {
            $name = self::firstOrCreate($name);
        }

        if (! $name instanceof self) {
            throw new \InvalidArgumentException("\$name should be string, array, or " . self::class);
        }

        return $name;
    }

    public static function fromArray(array $array): Collection
    {
        return (new Collection($array))->map(fn($item) => self::wrap($item));
    }
}
Enter fullscreen mode Exit fullscreen mode

app/Country.php

<?php

namespace App;

use App\HasName;
use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    use HasName;

    protected $fillable = ['name'];
}
Enter fullscreen mode Exit fullscreen mode

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay