Laravel models: Where are model properties?

10,688

Solution 1

Now that I have spent some time with Laravel, Eloquent and PHP in general, I'll share a few things in the hope that these helps other starters.

PHP is a dynamic language and its code is compiled on the fly (this is unlike C# and VB.NET). Your model classes do not need to explicitly define members for them to be accessible/assignable, so as long they extend Model (a built-in class in Laravel Eloquent), you can assign values to non-existing members that have the same name as the underlying database table column and Eloquent will store it in the DB for you. So for example, if you have a posts table in your database that has a column named body, you can write the following code to create a new record in your database:

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

Of course you need to have a class Post in your project that extends from Model but you don't need to define a member body inside that class. This would sound strange to the people coming from .NET world, but that's how dynamic languages work.

As for automatically generating models, Laravel includes built-in commands (php artisan make:model) that can generate those for you.

Lastly, for intellisense and auto-complete, use the same tool that is used by Laravel itself, i.e. DocBlocks. These are special type of comments in PHP using which you can document your code elements. So you can add DocBlocks to all your model classes containing property names and types. Fortunately for everyone, there is a very neat extension in VS Code that can do this automatically for you. Install it using the following command:

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

Now run the following command to generate DocBlocks for all of your model classes (obviously you should already have generated your database and models before this):

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

The extension will fetch the structure of your database and inject DocBlocks to all your models, which will look something like this:

/**
 * 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 will now show you table field names in model properties, like this (see how intellisense brings up name member from our DocBlocks as we type na...):

enter image description here Note that I also have Intelephense installed in my VS Code, though I'm not sure if that is required for auto-complete feature to work.

Solution 2

I use annotations to declare all the properties for autocomplete (works in PHPStorm, not sure about other IDEs).

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

You can use something like this to get a list of all columns of a table, then paste/format that list into your annotations:

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

Solution 3

  1. Unfortunatilly yes, you need to write them by hand, but only if you need to update the value of these properties, check point 2($fillable array)
  2. You need to declare the properties that can be filled:

For example a model called Post for a database table "posts" that has 2 columns "title" and "body" :  

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'];
}

In the controller:

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

Or you can hide them if you return the properties in an array or a JSON response(in the Collection also the hidden ones will be displayed):

protected $hidden = [
 'title',
];

Also you can inject new properties in the model using Accessors

  1. I don't think so, you can install some Laravel VS Code plugins to make your life easier(e.g: Blade snippets) You can check this article.
Share:
10,688
dotNET
Author by

dotNET

Programming since the days of FoxPro 2.0 and Windows 98, all the way through VB4, 5, 6. Started working with .NET in 2004 and never looked back. WinForms, OOP, SQL Server and MS-Office programming (both VBA and VSTO) have been my primary areas of interest. Trying to switch to WPF and MVVM now-a-days. Love studying Islam, literature (especially Urdu) and spending some time on SO each day.

Updated on June 07, 2022

Comments

  • dotNET
    dotNET almost 2 years

    (I come from Visual Studio + Entity Framework background and trying to locate equivalent functionality in Laravel + Eloquent)

    In EF and Visual Studio, we add a new Model to our application and just tell it about our existing database. EF can then generate Models for my tables with public properties for columns. This gives us all those IDE and compiler benefits such as Intellisense, spelling-error detection etc.

    I've recently stated exploring VS Code, Laravel and Eloquent. Going through all those tutorials and articles, I'm not sure when and how these properties are generated in the model classes. I just tried artisan make:model command and it did generate the model class, but there are no properties in it. So,

    1. Am I supposed to write them by hand? (really?)
    2. Will these just be public variables or standard properties with getter/setter (excuse me for my .NET mentality :))?
    3. Is there a tool/extension that could examine my database and create models with properties for their columns?

    Update

    To the people who answered my question, thanks a lot. Plus some of the comments I posted were due to my ignorance about PHP's (strange IMO) approach about member access; I just found out that PHP does not complain about non-existing class members and instead generates them on the fly (e.g. $post->NonExistingMember = SomeValue runs okay; this would not even compile in most other languages that I know). Big surprise for me. I have used C++, VB, C#, Java among several other languages and haven't seen that behavior anywhere else. All those languages would throw a compile-time error straight away saying something like Type X does not contain a member named Y. Cannot see how PHP's different approach fits together with OOP.

    The actual problem that I posted this question for still remains unresolved. Although I can use reliese/laravel to generate Model classes for my database, the tool still does not generate class members against table columns, so I do not get auto-complete benefits. I'd love to hear from the experts if that can be done (automatically of course).

    Update 2

    Now that I understand Laravel environment slightly better, I thought I'd share my experience. See my answer below.