Skip to content

Commit 842c154

Browse files
committed
Update laravel todo
1 parent 0e8a919 commit 842c154

1 file changed

Lines changed: 80 additions & 2 deletions

File tree

docs/todo-laravel.md

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PHPantom — Laravel Support: Remaining Work
22

3-
> Last updated: 2026-02-26
3+
> Last updated: 2026-02-27
44
55
This document tracks bugs, known gaps, and missing features in
66
PHPantom's Laravel Eloquent support. For the general architecture and
@@ -32,4 +32,82 @@ virtual member provider design, see `ARCHITECTURE.md`.
3232
are best-effort.
3333
- **Facades fall back to `@method`.** Facades whose `getFacadeAccessor()`
3434
returns a string alias cannot be resolved. `@method` tags on facade
35-
classes provide completion without template intelligence.
35+
classes provide completion without template intelligence.
36+
37+
---
38+
39+
## Model property source gaps
40+
41+
The `LaravelModelProvider` synthesizes virtual properties from several
42+
sources on Eloquent models. The table below summarises what we handle
43+
today and what is still missing.
44+
45+
### What we cover
46+
47+
| Source | Type info | Notes |
48+
|--------|-----------|-------|
49+
| `$casts` / `casts()` | Rich (built-in map, custom cast `get()` return type, enum, `Castable`, `CastsAttributes<TGet>` generics fallback) | |
50+
| `$attributes` defaults | Literal type inference (string, bool, int, float, null, array) | Fallback when no `$casts` entry |
51+
| `$fillable`, `$guarded`, `$hidden` | `mixed` | Last-resort column name fallback |
52+
| Legacy accessors (`getXAttribute()`) | Method's return type | |
53+
| Modern accessors (returns `Attribute`) | Always `mixed` | **See gap 1 below** |
54+
| Relationship methods | Generic params or body inference | |
55+
56+
### Gaps (ranked by impact)
57+
58+
#### 1. Modern accessor `Attribute<TGet>` generic extraction
59+
60+
Modern accessors (Laravel 9+) return `Illuminate\Database\Eloquent\Casts\Attribute`.
61+
We detect these correctly and synthesize a virtual property, but the
62+
property is always typed `mixed`. When the return type carries a generic
63+
argument (e.g. `Attribute<string>` or `Attribute<string, never>` via
64+
`@return` or a native return type), we should extract the first generic
65+
parameter and use it as the property type.
66+
67+
```php
68+
// @return Attribute<string>
69+
protected function firstName(): Attribute { ... }
70+
// Expected: $first_name typed as `string`
71+
// Actual: $first_name typed as `mixed`
72+
```
73+
74+
This is the most impactful gap because modern accessors are the
75+
recommended approach since Laravel 9.
76+
77+
**Where to change:** `is_modern_accessor` already strips generics to
78+
match the base type. A companion function (or inline logic in `provide`)
79+
should extract the first generic arg from the return type string via
80+
`parse_generic_args` and pass it through instead of hard-coding `mixed`.
81+
82+
#### 2. `$visible` array not included in column name extraction
83+
84+
The `$visible` property lists attribute names that should appear in
85+
serialized output. It functions identically to `$fillable`/`$guarded`/
86+
`$hidden` as a source of column names.
87+
88+
**Where to change:** Add `"visible"` to the `targets` array in
89+
`extract_column_names` in `parser/classes.rs`.
90+
91+
#### 3. `$dates` array (deprecated)
92+
93+
Before `$casts`, Laravel used `protected $dates = [...]` to mark
94+
columns as Carbon instances. This was deprecated in favour of
95+
`casts()` with a `datetime` type, but older codebases still use it.
96+
Columns listed in `$dates` should be typed as `\Carbon\Carbon`.
97+
98+
**Where to change:** Add a new `extract_dates_definitions` function in
99+
`parser/classes.rs` (similar to `extract_column_names` but returning
100+
`Vec<(String, String)>` with each column mapped to `\Carbon\Carbon`).
101+
Merge these into `casts_definitions` at a lower priority than explicit
102+
`$casts` entries, or add a separate field on `ClassInfo` and handle
103+
priority in the provider.
104+
105+
#### 4. `$appends` array
106+
107+
The `$appends` property lists accessor names that should always be
108+
included in `toArray()` / `toJson()`. These reference existing
109+
accessors, so in most cases the accessor method itself already produces
110+
the virtual property. Parsing `$appends` would only help when the
111+
accessor is defined in an unloaded parent class.
112+
113+
**Priority:** Low. The accessor method is the real source of truth.

0 commit comments

Comments
 (0)