Asked  7 Months ago    Answers:  5   Viewed   39 times

So I'm just starting off with Laravel (using v5) and Eloquent. I'm working on getting some basic APIs up and running and noticing that a lot of working methods don't show up in PhpStorm's code hinting

So I have this model:

namespace ProjectModels;

use IlluminateDatabaseEloquentModel;
use IlluminateContractsAuthAuthenticatable as AuthenticatableContract;
use IlluminateContractsAuthCanResetPassword as CanResetPasswordContract;

class User extends Model 
    implements AuthenticatableContract, CanResetPasswordContract {
}

And in one of my controllers I try to do

User::query()->orderBy('id', 'desc');

User::query() creates a Eloquent Builder object and orderBy() behave properly and without error. However, PhpStorm does not show orderBy() (or take(), skip(), and I'm sure others) when I type User::query()-> and gives warnings when I actually do use it.

I am using Laravel IDE Helper which has helped immensely with bringing code hints to the Facades, but not to the models/builders it would seem.

Does anyone have a solution to this?

 Answers

47

For future Googlers, and perhaps OP as well if you are still sticking to Laravel.

The laravel-ide-helper package solves this issue for you quite elegantly, with what I believe is a relatively new feature; generated model PHPDocs.

You can generate a separate file for all PHPDocs with this command:

php artisan ide-helper:models

The generated metadata will look something like this for each class:

namespace App {
/**
 * AppPost
 *
 * @property integer $id
 * @property integer $author_id
 * @property string $title
 * @property string $text
 * @property CarbonCarbon $created_at
 * @property CarbonCarbon $updated_at
 * @property-read User $author
 * @property-read IlluminateDatabaseEloquentCollection|Comment[] $comments
 */
class Post {}
}

This caused issues for me in PHPStorm however, where the software was complaining about multiple class definitions. Luckily an option is readily available for writing directly to the model files:

php artisan ide-helper:models -W

There are a few more options and settings available if you need to tweak the behavior, but this is the gist of it.

Wednesday, March 31, 2021
 
Sanguine
answered 7 Months ago
16

You could use a Many-to-Many relationship between the Listing and the ListingFeatureValue models, then group the related listing features for a given listing by their type using the groupBy Collection method.

The Listing model:

class Listing extends Model {

    protected $hidden = [
        'features'
    ];

    protected $appends = [
        'feature_types'
    ];

    public function features(){
        return $this->belongsToMany(ListingFeatureValue::class, 'listings_features', 'listing_id', 'feature_id');
    }

    public function getFeatureTypesAttribute()
    {
        return $this->features->groupBy(function ($feature, $key) {
            return $feature->type->id;
        })->map(function($features, $key){
            $type = ListingFeatureType::find($key);
            $type->features = $features;
            return $type;
        })->values();
    }

}

The getFeatureTypesAttribute() is the star of the show here, because you can combine that with the appends array to force the Eloquent model to append that to any toArray() calls to the model instance, which is what toJson() uses when converting your model to JSON.

It may seem a little convoluted to first fetch all the listing values then divide them using the groupBy and map collection methods, but there is no native Eloquent mechanism for using hasManyThrough via many-to-many relationships. There's a different approach here if you don't like this one.

The ListingFeatureValue model:

class ListingFeatureValue extends Model
{
    public $table = 'listings_features_values';

    public function type()
    {
        return $this->belongsTo(ListingFeatureType::class, 'feature_type_id');
    }
}

I'm showing this model here because the type() relationship is called in the getFeaturesByTypeAttribute() method above and didn't want there to be any confusion.

And, just for the sake of completeness, the ListingFeatureType model:

class ListingFeatureType extends Model
{
    public $table = "listings_features_types";

    public function listings()
    {
        return $this->hasMany(ListingFeatureValue::class, 'listing_feature_type_id');
    }
}

If you wanted to eager-load the listings with their features and types for a full output of all your listings, you could do so like this:

AppListing::with('features.type')->get()->toJson();

My migration files look like this:

//create_listings_table
Schema::create('listings', function (Blueprint $table) {
    $table->increments('id');
    $table->string('uuid');
    $table->timestamps();
});

//create_listings_features_values_table
Schema::create('listings_features_values', function (Blueprint $table) {
    $table->increments('id');
    $table->string('listing_feature_text');
    $table->integer('listing_feature_type_id')->unsigned();
    $table->timestamps();
});

//create_listings_features_types_table    
Schema::create('listings_features_types', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
});

//create_listings_features_table
Schema::create('listings_features', function(Blueprint $table){
    $table->integer('listing_id')->unsigned();
    $table->integer('listing_feature_id')->unsigned();
});

You can learn more about the Collection methods here:

https://laravel.com/docs/5.3/collections#available-methods

...and eager-loading here:

https://laravel.com/docs/5.3/eloquent-relationships#eager-loading

...and many-to-many relationships here:

https://laravel.com/docs/5.3/eloquent-relationships#many-to-many

Saturday, May 29, 2021
 
aWebDeveloper
answered 5 Months ago
97

Per the bug report linked in the comments by @LazyOne, as of PhpStorm EAP 138.256 (thus in PHPStorm 8) uniform multi-level array doc parsing is now supported.

This means you can now do this:

/**
 * @var $listOfLists Foo[][]
 */
$listOfLists[] = (new FooList())->getFoos();
$listOfLists[] = (new FooList())->getFoos();
$listOfLists[] = (new FooList())->getFoos();
$listOfLists[] = (new FooList())->getFoos();

foreach ($listOfLists as $fooList)
{
    foreach($fooList as $foo)
    {
        // Code hinting, yay!!
        $foo->fooMethod();
    }
}

and get the expected:

Screenshot

Saturday, May 29, 2021
 
OMGKurtNilsen
answered 5 Months ago
69

You can place the cursor (text-cursor, not mouse-cursor) on any PHP function and press Shift + F1 (Menu: View -> External Documentation).

That will open the detailed description incl. examples and user-comments (read: the PHP manual).

Saturday, May 29, 2021
 
dzm
answered 5 Months ago
dzm
69

you need to used many to many relationship

in Category Model:

 public function datas()
 {
        return $this->belongsToMany(Data::class, 'data_childerens', 'category_id', 'data_id');
 }

Then run this Query withCount :

Category::withCount('datas')->get();

Set Data Model:

public function categories()
{
     return $this->belongsToMany(Category::class, 'data_childerens', 'data_id', 'data_id');
}

Then run this Query With and withCount :

Data::with('categories')->withCount('datas')->get();
Saturday, May 29, 2021
 
Gerardo
answered 5 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :