Modelos de Laravel: ¿Dónde están las propiedades del modelo?

11 minutos de lectura

avatar de usuario de dotNET
punto net

(Vengo del fondo de Visual Studio + Entity Framework y trato de ubicar una funcionalidad equivalente en Laravel + Eloquent)

En EF y Visual Studio, agregamos un nuevo modelo a nuestra aplicación y solo le informamos sobre nuestra base de datos existente. EF luego puede generar modelos para mis tablas con propiedades públicas para columnas. Esto nos brinda todos esos beneficios de IDE y compilador, como Intellisense, detección de errores ortográficos, etc.

Recientemente comenté a explorar VS Code, Laravel y Eloquent. Al revisar todos esos tutoriales y artículos, no estoy seguro de cuándo y cómo se generan estas propiedades en las clases del modelo. acabo de intentar artisan make:model comando y generó la clase modelo, pero no tiene propiedades. Entonces,

  1. ¿Se supone que debo escribirlos a mano? (¿en realidad?)
  2. ¿Serán solo variables públicas o propiedades estándar con getter/setter (perdón por mi mentalidad de .NET :))?
  3. ¿Existe alguna herramienta/extensión que pueda examinar mi base de datos y crear modelos con propiedades para sus columnas?

Actualizar

A las personas que respondieron mi pregunta, muchas gracias. Además, algunos de los comentarios que publiqué se debieron a mi ignorancia sobre el enfoque de PHP (OMI extraño) sobre el acceso de miembros; Acabo de enterarme de que PHP no se queja de los miembros de la clase que no existen y, en cambio, los genera sobre la marcha (por ejemplo, $post->NonExistingMember = SomeValue funciona bien; esto ni siquiera se compilaría en la mayoría de los otros idiomas que conozco). Gran sorpresa para mí. He usado C++, VB, C#, Java entre varios otros lenguajes y no he visto ese comportamiento en ningún otro lado. Todos esos lenguajes generarían un error de tiempo de compilación de inmediato diciendo algo así como que el tipo X no contiene un miembro llamado Y. No puedo ver cómo el enfoque diferente de PHP encaja con OOP.

El problema real para el que publiqué esta pregunta sigue sin resolverse. Aunque puedo usar confiar/laravel para generar clases de modelo para mi base de datos, la herramienta aún no genera miembros de clase contra las columnas de la tabla, por lo que no obtengo los beneficios de autocompletar. Me encantaría saber de los expertos si eso se puede hacer (automáticamente, por supuesto).

Actualización 2

Ahora que entiendo un poco mejor el entorno de Laravel, pensé en compartir mi experiencia. Vea mi respuesta a continuación.

  • Tal vez esto podría ayudarte: stackoverflow.com/questions/30560485/…

    – Rafael

    8 de agosto de 2018 a las 11:33

  • Tal vez esto pueda ayudar: Laravel: Introducción Elocuente. Pero básicamente, sí, los escribes a mano. Hay paquetes disponibles que pueden generar modelos a partir de una base de datos existente

    – bromista

    8 de agosto de 2018 a las 11:38

  • @RafaelBoszko: Eso da en el clavo (la cabeza del clavo es :)). Gracias.

    – punto net

    8 de agosto de 2018 a las 11:43

  • ¿Alguna vez resolvió esto para obtener beneficios de autocompletar? Yo también vengo de C# y estoy acostumbrado a que las cosas sean un poco más explícitas y no “automágicas”.

    – Louise Eggleton

    15 de noviembre de 2019 a las 12:49

  • @LouiseEggleton: He pasado más tiempo trabajando con Laravel. El problema básico (o llámelo característica) es que una clase no necesita contener un miembro en tiempo de compilación, porque no hay tiempo de compilación por así decirlo. PHP interpreta el código en tiempo de ejecución y genera miembros sobre la marcha. Por lo tanto, una clase modelo no requiere que tenga ningún miembro. Esto es muy diferente del mundo de C# donde tenemos modelos fuertemente tipados (Entidad o incluso Conjuntos de datos) con una correspondencia 1-1 entre las propiedades de clase y las columnas de la tabla subyacente. Todo esto significa que no habrá ningún tipo de autocompletado en VS Code para Laravel.

    – punto net

    15 de noviembre de 2019 a las 17:24

avatar de usuario de dotNET
punto net

Ahora que he pasado un tiempo con Laravel, Eloquent y PHP en general, compartiré algunas cosas con la esperanza de que ayuden a otros principiantes.

PHP es un lenguaje dinámico y su código se compila sobre la marcha (esto es diferente a C# y VB.NET). Sus clases modelo no necesitan definir miembros explícitamente para que sean accesibles/asignables, por lo que siempre que se extiendan Model (una clase integrada en Laravel Eloquent), puede asignar valores a miembros no existentes que tengan el mismo nombre que la columna de la tabla de la base de datos subyacente y Eloquent lo almacenará en la base de datos por usted. Entonces, por ejemplo, si tienes un posts tabla en su base de datos que tiene una columna llamada bodypuede escribir el siguiente código para crear un nuevo registro en su base de datos:

$p = new Post;
$p->body = 'Some stuff';
$p->save();

Por supuesto que necesitas tener una clase. Post en su proyecto que se extiende desde Model pero no es necesario definir un miembro body dentro de esa clase. Esto sonaría extraño para la gente que viene del mundo .NET, pero así es como funcionan los lenguajes dinámicos.

En cuanto a la generación automática de modelos, Laravel incluye comandos integrados (php artisan make:model) que pueden generarlos para usted.

Por último, para intellisense y autocompletar, use la misma herramienta que usa Laravel, es decir, DocBlocks. Estos son tipos especiales de comentarios en PHP con los que puede documentar sus elementos de código. Por lo tanto, puede agregar DocBlocks a todas sus clases de modelos que contengan nombres y tipos de propiedades. Afortunadamente para todos, hay una extensión muy ordenada en VS Code que puede hacer esto automáticamente por usted. Instálalo usando el siguiente comando:

composer require --dev barryvdh/laravel-ide-helper

Ahora ejecute el siguiente comando para generar DocBlocks para todas sus clases de modelo (obviamente, ya debería haber generado su base de datos y modelos antes de esto):

php artisan ide-helper:models --dir="app"

La extensión obtendrá la estructura de su base de datos e inyectará DocBlocks en todos sus modelos, que se verán así:

/**
 * App\User
 *
 * @property int $id
 * @property string $name
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @method static \Illuminate\Database\Eloquent\Builder|\App\User whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\User whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\User whereName($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Exam whereUpdatedAt($value)
 * @mixin \Eloquent
 */
class User extends Model
{
}

VS Code ahora le mostrará los nombres de los campos de la tabla en las propiedades del modelo, como este (vea cómo intellisense muestra name miembro de nuestros DocBlocks mientras escribimos na...):

ingrese la descripción de la imagen aquí Tenga en cuenta que también tengo Intelephense instalado en mi VS Code, aunque no estoy seguro de si es necesario para que funcione la función de autocompletar.

Editar

Las propiedades dinámicas han quedado obsoletas en PHP 8.2 y escuché que dejarán de ser válidas en PHP 9.0, lo que significa que los modelos de Laravel no deberían poder hacer estas cosas mágicas en las versiones futuras.

No soy un gurú de PHP, pero escuché que no debemos entrar en pánico. Dos cosas: en primer lugar, los objetos que implementan __get y __set seguirá funcionando bien. En segundo lugar, Plus usted (ellos) también pueden usar #[AllowDynamicProperties] en clases de modelo para permitir accesorios dinámicos. Y, por último, pueden reescribir el generador de modelos para escupir los nombres de las columnas como accesorios en la clase del modelo. Este último será el mejor y llevará a PHP un paso más cerca de cómo funciona el mundo de C# (precisamente donde comenzó esta publicación, lol).

  • No necesita definir las propiedades, pero sí no debe definir las propiedades. Definirlos rompe los supuestos de Eloquent. Esta es una elección de diseño que no entiendo, pero lo que es más molesto no se menciona en las páginas de documentación de Laravel.

    – aros

    6 oct 2020 a las 15:19

  • Tenía esto desconcertado cuando me mudé a laravel desde symfony. Al igual que usted, programo muchos idiomas y prefiero mucho el tipo estricto, puede codificar php estricto o suelto en 7+. en symfony uso la doctrina orm para la base de datos, se llaman entidades en lugar de modelos, pero son solo una versión codificada de tu tabla y usan repositorios para hacer consultas. De hecho, declaras las propiedades con getters y setters. Laravel usa métodos mágicos para crear las propiedades, no me gusta, pero me gusta laravel en general, así que vivo con eso. Sin embargo, usar el enfoque docblock funciona bien para equilibrarlo un poco

    – MMMRaro

    20 de enero de 2022 a las 20:07


  • Bueno, ¿qué tal ahora que las propiedades dinámicas se consideran obsoletas en PHP 8.2 (php.net/releases/8.2/en.php#deprecate_dynamic_properties)? No pude encontrar nada al respecto en la documentación de Laravel.

    – Boris N.

    10 de febrero a las 0:37


  • Los atributos del modelo no son propiedades dinámicas. Laravel usa los métodos mágicos __get y __set para mapear las columnas de la base de datos en una propiedad, que es una matriz de atributos.

    – Dividir

    23 de febrero a las 19:33

Avatar de usuario de Holonaut
holonauta

Uso anotaciones para declarar todas las propiedades para autocompletar (funciona en PHPStorm, no estoy seguro acerca de otros IDE).

/**
 * @property $id
 * @property $microsoft_id
 * @property $name
 * @property $qualification
 * @property $company
 */
class ShopTenant extends Model
{
    public $connection = 'shop';
    public $table="tenants";
    protected $guarded = ['id'];
}

Puede usar algo como esto para obtener una lista de todas las columnas de una tabla, luego pegue/formatee esa lista en sus anotaciones:

SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'tenants';

Avatar de usuario de NicuVlad
nicuvlad

  1. Desafortunadamente, sí, debe escribirlas a mano, pero solo si necesita actualizar el valor de estas propiedades, verifique el punto 2 ($ matriz rellenable)
  2. Debe declarar las propiedades que se pueden completar:

Por ejemplo, un modelo llamado Publicar para una tabla de base de datos “publicaciones” que tiene 2 columnas “título” y “cuerpo”:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{

 //not mandatory to declare the table name, Laravel will find it using reflection if you follow the naming standard
 protected $table="posts"; //not mandatory

 protected $fillable = ['title','body'];
}

En el controlador:

$newPost = new Post;
$newPost->title="A new title";
$newPost->body = 'A new body';
$newPost->save(); //only at this point the db is modified

O puede ocultarlos si devuelve las propiedades en una matriz o una respuesta JSON (en la Colección también se mostrarán los ocultos):

protected $hidden = [
 'title',
];

También puede inyectar nuevas propiedades en el modelo usando Accesorios

  1. No lo creo, puede instalar algunos complementos de Laravel VS Code para facilitarle la vida (por ejemplo: fragmentos de Blade) Puede verificar Este artículo.

  • Gracias. ¿Puede incluir su definición de clase modelo en la respuesta?

    – punto net

    8 de agosto de 2018 a las 12:07

  • Revisa mi respuesta actualizada, espero que esto sea lo que pediste. Si necesitas algo más, puedo actualizar mi respuesta.

    – Nicu Vlad

    8 de agosto de 2018 a las 12:16

  • Ahora estás cerca de lo que estoy preguntando. Qué es $newPost->title en el código anterior? No existe tal propiedad o variable pública en su clase. Incluso si lo hubiera, ¿cómo se correlacionaría esa variable con la columna de la tabla subyacente?

    – punto net

    8 de agosto de 2018 a las 12:29


  • El título es la columna “título” de su base de datos, si necesita crear una publicación y agregar un valor de “título”, entonces debe agregar el título en la matriz “$ rellenable”.

    – Nicu Vlad

    8 de agosto de 2018 a las 12:33

  • De manera predeterminada, probablemente también tenga un “id”, “created_at” y “updated_at” creado por Laravel, pero en esta matriz debe declarar solo las propiedades que necesita cambiar.

    – Nicu Vlad

    8 de agosto de 2018 a las 12:36

En realidad, no es necesario especificar las propiedades. Todo lo hace laravel automáticamente. Cuando creas un modelo, laravel usa el plural (y tiene un sistema realmente bueno para eso: la publicación se convierte en publicaciones, la actividad se convierte en actividades, etc.) del nombre de la clase para acceder a la tabla. Por lo tanto, puede trabajar con un modelo vacío sin configurar la $tabla o la propiedad $rellenable/$guardada.

// use only, if your table name differs from the models classname
$table="users_options"; // when you want to name your model 'Vote' but the table is called 'users_options' for instance.

// use fillable and guarded only to specify mass-assignment columns
$fillable = [whatever, ...];
$guarded = [whatever, ...];

Puedes acceder a las propiedades cuando quieras:

class Post extends Model
{

}

// would do sth like this: select name from posts where id = 1;
// without specifying anything in the model
$name = Post::find(1)->name;

Necesitas agregar por ti mismo. Por ejemplo

$fillable = ['firstname', 'email','username'];
$guarded = ['price'];

  • Estoy buscando agregar propiedades públicas en mis columnas, para obtener beneficios de tiempo de código como autocompletado y detección de errores ortográficos, etc.

    – punto net

    8 de agosto de 2018 a las 17:48

  • Estoy buscando agregar propiedades públicas en mis columnas, para obtener beneficios de tiempo de código como autocompletado y detección de errores ortográficos, etc.

    – punto net

    8 de agosto de 2018 a las 17:48

¿Ha sido útil esta solución?