E - The editor · · 5 min read

Meeting the benchmark: what e 0.6.5 learned from Laravel Idea

How e 0.6.5 closed the last gaps with Laravel Idea — and why reading your live database lets a from-scratch editor quietly step past it.

Meeting the benchmark: what e 0.6.5 learned from Laravel Idea

On the plugin Laravel developers stay on PhpStorm for — and how understanding the actual database lets a from-scratch editor match it, then quietly pull ahead.

If you ask a room of Laravel developers why they're still on PhpStorm, a surprising number will give you the same one-word answer: Laravel Idea. It's a paid plugin, and for a lot of people it is the IDE — the thing that knows your routes, your views, your Eloquent models, and fills in the hundred little blanks you'd otherwise type by hand.

So when I started measuring e against something, Laravel Idea was the honest yardstick. And the interesting discovery was this: e already had a lot of it — route/view/config/__() completion, <x-…> components, Eloquent attributes. The gaps that were left were exactly the ones that make Laravel Idea feel like magic. 0.6.5 is about closing them — and there's a recurring twist, because e has something PhpStorm doesn't: it reads your live database.

Why the database changes everything

Laravel Idea is brilliant, but on the model side it works from generated helper files and static analysis. It has to infer, or you have to run a generator. e connects to your actual schema. So everywhere Laravel Idea guesses, e can know. Keep that in mind — it's the thread running through every feature below.

The feature people feel a hundred times a day

Query-builder string completion. You're inside a where() and you want a column:

User::where('ema…')
//           └── completes to email, from the real users table
    ->orderBy('created_at')   // ← completes here too
    ->with('posts');          // ← and relationship names here

Columns complete inside where(), orderBy(), select(), pluck(), value(), groupBy() — resolved from whatever the query is on (Model::, $model, or DB::table('…')). Relationship names complete inside with(), load(), whereHas().

And here's the twist Laravel Idea can't pull off, because it doesn't have the database open:

User::where('emial', $value)
//           └── ⚠ Column `emial` not found in table `users`

A typo in a string, underlined before you ever run the query. That's not autocomplete — that's the editor checking your SQL against reality.

The other Laravel Idea flagship: generation

Its "New Eloquent Model" wizard is a headline feature. e beats it in a specific way. Open a table in the database panel, run Generate Model from Table, and:

class Post extends Model
{
    use HasFactory;
protected $fillable = ['user_id', 'title', 'published', 'meta'];

protected $casts = [
    'published' =&gt; 'boolean',   // from tinyint(1)
    'meta'      =&gt; 'array',     // from json
];

public function user()
{
    return $this-&gt;belongsTo(User::class);   // ← from the actual foreign key
}

public function comments()
{
    return $this-&gt;hasMany(Comment::class);   // ← comments.post_id → posts.id
}

}

The casts come from the column types. The relationships come from the real foreign keys — posts.user_id → users.id becomes belongsTo(User), and any table pointing back becomes hasMany. PhpStorm has to guess these; e reads them.

The same idea powers Generate Validation Rules from Table:

'email' => 'required|email|max:255',   // not-null varchar(255), name "email"
'age'   => 'nullable|integer',         // nullable int

Nullability, string lengths, types — straight from the schema.

The mid-weights that punch above their size

Gates & policies

Abilities complete and navigate:

$this->authorize('update', $post);
//                └── completes, and F12 jumps to PostPolicy@update

can(), authorize(), @can, Gate::allows() — all resolve to the policy method or Gate::define() that declares them. And because it shares data with the security lens from a previous release, it's one dataset doing two jobs.

The event dispatch graph (⌘⌥G)

Event-driven apps are archaeology without this — you dispatch an event and hope you remember who's listening:

⚡ OrderShipped
→ SendShipmentNotification
→ UpdateInventory

Built from $listen, Event::listen(), and auto-discovered handle(OrderShipped $event) type hints. F12 on OrderShipped::dispatch() jumps straight to a listener. With this, the architecture map is finally complete: routes, views, and the asynchronous flow.

Related files (⌘⌥E)

The smallest feature, and the one you'll use without thinking. From any file in a resource, one shortcut lists the rest:

Model       app/Models/Post.php
Migration   database/migrations/…_create_posts_table.php
Factory     database/factories/PostFactory.php
Controller  app/Http/Controllers/PostController.php
Test        tests/Feature/PostTest.php

The naming conventions make the mapping deterministic, so it just works — click, and you're there.

How it was built: same data, more contexts

The honest truth about most of 0.6.5 is that it wasn't new machinery — it was pointing existing machinery at new places. The query-builder completion reuses the exact model→table resolution and live-schema cache that Eloquent attribute completion ($user->email) already used; it just recognizes a few more contexts. The validation generator and the model generator both read the same ColumnInfo the database panel loads. The gates feature shares its dataset with the security lens.

That's the pattern I keep coming back to: the best features are usually two things you already have, wired together. Thirteen new unit tests, every feature compiling green, and the whole thing signed and notarized by Apple in CI so the .dmg just opens.

A word on getting it wrong

Shipping fast means sometimes shipping a bug, and 0.6.5 had a nasty one: an overlay wrapper I added to group panels ended up covering the whole window and eating every click — the file explorer went dead. A user caught it within the day, and 0.6.6 fixed it (plus made ⌘P find your .env). I mention it because that loop — ship, someone tells you, fix it fast — is the whole point of doing this in the open. The tool gets better because people use it and say something.

What I hope it feels like

Less "I should really set up Laravel Idea's helper files" and more the editor already knows my project — its columns, its relationships, its policies, its events. And in the places that matter most, it doesn't infer from generated stubs. It asks the database.

Meeting the benchmark was the goal. Reading the live schema is how e quietly steps past it.

☕ Grab 0.6.6 on the releases page. If the column linter flags something it shouldn't — or misses one it should — that's exactly the report I want.