Larastan 3 en los modelos: genéricos en las relaciones y parseModelCastsMethod
Hola, bienvenido. En esta lección vamos a poner los modelos al día para Larastan 3, que cambia 2 cosas respecto a Larastan 2. La primera son las relaciones: Larastan 3 ya no deduce qué modelo devuelve cada una leyendo el cuerpo del método, así que hay que escribirlo en su PHPDoc, con genéricos. La segunda es al revés, una PHPDoc que sobra: la del método casts(), que necesitaba Larastan 2 y que Larastan 3 puede sustituir leyendo directamente el array que devuelve el método.
Partimos de la lección anterior: Larastan 3 instalado y 7 errores en el análisis, con los tests en verde. Al terminar, el análisis estará en verde y los modelos tendrán la forma que espera Larastan 3.
Las relaciones y los casts, de Larastan 2 a Larastan 3
Esta tabla resume qué hacía Larastan 2 con los modelos y qué hace Larastan 3, y más abajo tienes cada fila resuelta en el proyecto:
| Qué | Larastan 2 | Larastan 3 |
|---|---|---|
Relación declarada como public function replies(): HasMany |
Lee el cuerpo, encuentra hasMany(TicketReply::class) y deduce que devuelve TicketReply |
No lee el cuerpo: sin genéricos, la relación devuelve un Model cualquiera |
| Cómo se anota la relación | No hace falta | @return HasMany<TicketReply, $this> |
| Segundo genérico de la relación | Se llamaba TChildModel |
Se llama TDeclaringModel: el modelo que declara la relación |
Casts en el método casts() |
Solo los entiende con una PHPDoc @return array{...} que copia el array |
Con parseModelCastsMethod: true, lee el array del cuerpo del método |
En una relación anotada con genéricos, el primero es el modelo relacionado, el que devuelve la relación, y el segundo es el modelo que la declara. Para el segundo se escribe $this y no Ticket, porque así, si otra clase hereda de Ticket, la relación sabe que la declara la clase hija. Las clases de relaciones de Laravel admiten este segundo genérico desde la versión 11.15, y es lo que nos hacía falta en los 5 errores de las acciones de la lección anterior: con HasMany<Ticket, $this> en User::tickets(), Larastan sabe que $customer->tickets()->create() devuelve un Ticket.
¿Por qué Larastan 3 dejó de leer el cuerpo de los métodos? Según su guía de actualización, porque era lento, ya que obligaba a analizar el archivo del modelo, y difícil de mantener. Ahora la información está en la firma del método, que es donde la buscan PHPStan y los editores. Además, PHPStan exige esos genéricos a partir del nivel 6, el que informa de los tipos que faltan, así que anotarlos ahora deja el proyecto preparado para subir de nivel cuando haga falta.
- 02AddGenericReturnTypeToRelationsRector
- 03parseModelCastsMethod: los casts sin PHPDoc
- 04Cuándo una baseline es aceptable y cuándo no
- 05composer qa en verde y el commit