Jan
Jan

Reputation: 582

Property doesn't exist in collection: BelongsTo Realtion is empty

I have users and products. Users can save/mark products to see them late on again.

I will post you all of my three models below. I want to access an product which is marked by the user. So, I call $user->markedProducts->product which is defined as a belongsTo relation. However, I cannot access the property product because it's not contained in the collection although I wrote protected $with = ['product']; in the MarkedProduct model.

My question is, how can I access each product object via the MarkedProduct model to print things such as the name, heading and etc. of the product?

Error I get:

Property [product] does not exist on this collection instance.

User model:

class User extends Authenticatable
{
    public function products()
    {
        return $this->hasMany('App\Product');
    }

    public function markedProducts(){
        return $this->hasMany('App\MarkedProduct');
    }
}

Product model:

class Product extends Model
{

    /**
     * The relationships that should always be loaded.
     *
     * @var array
     */
    protected $with = ['comments'];

    /**
     * Get the user that owns the product.
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

MarkedProduct model:

class MarkedProduct extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'products_marks';

    /**
     * The relationships that should always be loaded.
     *
     * @var array
     */
    protected $with = ['product'];

    /**
     * Get the user that owns the comment.
     */
    public function user()
    {
        return $this->belongsTo('App\User', 'user_id');
    }

    /**
     * Get the product that owns the comment.
     */
    public function product()
    {
        return $this->belongsTo('App\Product', 'product_id');
    }
}

Product migration:

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->unsignedBigInteger('user_id')->index();
        $table->unsignedBigInteger('supplier_id')->index()->nullable();
        $table->unsignedBigInteger('dispatch_country_id')->index()->nullable();
        $table->unsignedBigInteger('product_type_id')->index();
        $table->unsignedBigInteger('post_status_id')->index()->default(4);
        $table->string('slug', 400)->index()->unique();
        $table->string('url', 1000)->nullable();
        $table->string('image_url', 1000)->nullable();
        $table->string('voucher')->nullable();
        $table->timestamp('start_date')->nullable();
        $table->timestamp('end_date')->nullable();
        $table->string('heading');
        $table->text('description');
        $table->integer('price')->nullable();
        $table->integer('old_price')->nullable();
        $table->integer('percentage')->nullable();
        $table->integer('price_off')->nullable();
        $table->boolean('free_shipment')->nullable();
        $table->timestamps();

        $table->foreign('user_id')
            ->references('id')
            ->on('users');

        $table->foreign('post_status_id')
            ->references('id')
            ->on('post_statuses');

        $table->foreign('supplier_id')
            ->references('id')
            ->on('suppliers')
            ->onDelete('set null');

        $table->foreign('dispatch_country_id')
            ->references('id')
            ->on('dispatch_countries')
            ->onDelete('set null');

        $table->foreign('product_type_id')
            ->references('id')
            ->on('product_types');
    });
}

User migration:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name')->unique();
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->date('birthday')->nullable();
        $table->integer('follower')->default(0);
        $table->integer('points')->default(0);
        $table->timestamps();
    });
}

MarkedProduct migration:

public function up()
{
    Schema::create('products_marks', function (Blueprint $table) {
        $table->unsignedBigInteger('product_id')->index();
        $table->unsignedBigInteger('user_id')->index();
        $table->timestamps();

        $table->foreign('product_id')
            ->references('id')
            ->on('products')
            ->onDelete('cascade');

        $table->foreign('user_id')
            ->references('id')
            ->on('users')
            ->onDelete('cascade');
    });
}

Upvotes: 0

Views: 60

Answers (2)

Commander
Commander

Reputation: 264

Nice to read, that I could help you.

Explanation

As @baceto90 already mentioned, you don't need a MarkedProducts Model, because you have a many-to-many relationship.

  • "A user has many marked products"
  • "A product is marked by many users"

So, actually you want to receive the users products or products users and not markedProducts products. products_marks is simply a joining table, which is used to find all products or users according to the request. This is not laravel specific, for more information google something like MySQL joining table many to many.

Many-to-many relationships in laravel models are defined by writing a method that returns the result of the belongsToMany method. To determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. You can override this by passing a second parameter to belongsToMany.

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

Solution

  1. Ignore MarkedProducts Model
  2. Update markedProducts relationship in user model. Type return $this->belongsToMany('App\Product', 'products_marks'); .
  3. Get markedProducts like this: User::with('markedProducts')

Hope everything is clear now. If not, just ask.

Upvotes: 1

baceto90
baceto90

Reputation: 33

You dont need model at all for marked products. Just read many to many relationship.

Upvotes: 1

Related Questions