Elasticquent icon indicating copy to clipboard operation
Elasticquent copied to clipboard

Issue with pivot relations

Open nonotest opened this issue 8 years ago • 12 comments

Hello,

not sure if it comes from an issue with my models or the last recent batch of commits.

The origin of the error is in loadRelationsAttributesRecursive in ElasticquentTrait.php at $relation->match

$models = static::hydrateRecursive($relation->getModel(), $value, $relation);

                        // Unset attribute before match relation
                        unset($model[$key]);
                        $relation->match([$model], $models, $key);

I am getting the following error

ErrorException in BelongsToMany.php line 503:
Trying to get property of non-object

more specifically

$dictionary[$result->pivot->$foreign][] = $result;

in BelongsToMany, buildDictionary

It is trying to access the pivot which doesnt exist in the $result

In my case the result is a Location object the $foreign is a company_id key the relation with the company table is set but is empty

Before the hydrate pulls it was working fine. Any idea? Thanks!

Let me know if you need more details:

Here is my model setup

Company model, many to many with a Location model. there is a pivot table between both

Company has a locations method

public function locations()
    {
        return $this->belongsToMany('App\Location')->withPivot('is_premium');
    }

Location has a companies method..

/**
     * The companies linked to the locations
     */
    public function companies()
    {
        return $this->belongsToMany('App\Company');
    }

nonotest avatar Apr 19 '16 14:04 nonotest

Sorry for the late response. Could you please show us what your model looks like and how do you add them into index?

chuangbo avatar Apr 26 '16 03:04 chuangbo

@chuangbo Hi there,

I have the same error after updating the package:

"message": "Trying to get property of non-object", "status_code": 500, "debug": { "line": 503, "file": "...\\vendor\\illuminate\\database\\Eloquent\\Relations\\BelongsToMany.php", "class": "ErrorException",

After some digging, it seems like the new package has issue with laravel model's belongstomany()

When I comment out all the belongstomany() then it works fine.

Any idea on how to resolve this issue?

yaofong avatar Apr 26 '16 09:04 yaofong

@yaofong Could you please show us what your model looks like and how do you add them into index too?

chuangbo avatar Apr 26 '16 22:04 chuangbo

@chuangbo

my model:

class Tour extends Model
{
    use SoftDeletes;

    protected $dates = ['deleted_at'];
    protected $table = 'tours';
    protected $hidden = ['created_at', 'updated_at'];

    //elasticsearch setting
    use ElasticquentTrait;

    protected $mappingProperties = [
        'pac_amount' => [
            'type' => 'double'
        ]
    ];

    function getTypeName()
    {
        return 'package';
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['pac_amount'];

    public function country(){
        return $this->hasOne('App\Models\Country','id','over_country_id');
    }
    public function cities()
    {
        return $this->belongsToMany('App\Models\City');
    }

    public function languages()
    {
        return $this->belongsToMany('App\Models\Language');
    }

    public function categories()
    {
        return $this->belongsToMany('App\Models\Category');
    }

add to index:

Tour::select('id','type','over_title','over_country_id',...)
            ->with(array(
                'country' => function($query) {
                    $query->addSelect(array('id','name'));
                },
                'cities' => function($query) {
                    $query->addSelect(array('city_id','name'));
                },
                'languages' => function($query) {
                    $query->addSelect(array('id','name','code'));
                },
               ...
               ...
            ))
            ->where('status','1')
            ->where('admin_approve','1')
            ->get()
            ->addToIndex();
            return;

yaofong avatar Apr 27 '16 03:04 yaofong

@yaofong Thank you. Also would you please tell me the output for code below

$tour = Tour::select('id','type','over_title','over_country_id',...)
            ->with(array(
                'country' => function($query) {
                    $query->addSelect(array('id','name'));
                },
                'cities' => function($query) {
                    $query->addSelect(array('city_id','name'));
                },
                'languages' => function($query) {
                    $query->addSelect(array('id','name','code'));
                },
               ...
               ...
            ))
            ->where('status','1')
            ->where('admin_approve','1')
            ->first();

dump($tour->getAttributes());
dump($tour->getRelations());

chuangbo avatar Apr 27 '16 04:04 chuangbo

@chuangbo

here are parts of the output

array:15 [▼
  "id" => 1
  "type" => 2
  "over_title" => "KL City Tour"
  "over_country_id" => 1
  "rating" => 0
  "avai_booking_confirm" => 1
  "des_introduction" => "Explore the Top Attractions Tours and Things to Do in Kuala Lumpur!"
  "des_details" => "Do you want to explore the most authentic KL experience? Find no further as we will bring you down to experience what the local are doing everyday."
  "iti_duration" => 0
  "iti_duration_hour" => 8
  "loc_destinations" => "[{"title":"Perdana Botanical Gardens","point":{"lat":"3.143678","lng":"101.68607299999996"}},{"title":"National Museum of Malaysia","point":{"lat":"3.137989","lng":"101.68674420000002"}},{"title":"Kuala Lumpur Tower","point":{"lat":"3.152778","lng":"101.70333299999993"}},{"title":"Petronas Twin Towers","point":{"lat":"3.1579","lng":"101.71159999999998"}},{"title":"Bukit Bintang","point":{"lat":"3.1467855","lng":"101.71130429999994"}}]"
  "loc_meet_type" => 1
  "currency" => "MYR"
  "pac_amount" => 60.0
  "user_id" => 2
]
array:7 [▼
  "country" => Country {#312 ▼
    #connection: null
    #table: null
    #primaryKey: "id"
    #perPage: 15
    +incrementing: true
    +timestamps: true
    #attributes: array:2 [▼
      "id" => 1
      "name" => "Malaysia"
    ]
    #original: array:2 [▼
      "id" => 1
      "name" => "Malaysia"
    ]
    #relations: []
    #hidden: []
    #visible: []
    #appends: []
    #fillable: []
    #guarded: array:1 [▼
      0 => "*"
    ]
    #dates: []
    #dateFormat: null
    #casts: []
    #touches: []
    #observables: []
    #with: []
    #morphClass: null
    +exists: true
    +wasRecentlyCreated: false
  }
  "cities" => Collection {#316 ▼
    #items: array:1 [▼
      0 => City {#315 ▼
        #hidden: array:1 [▶]
        #connection: null
        #table: null
        #primaryKey: "id"
        #perPage: 15
        +incrementing: true
        +timestamps: true
        #attributes: array:2 [▼
          "city_id" => 1
          "name" => "Kuala Lumpur"
        ]
        #original: array:4 [▼
          "city_id" => 1
          "name" => "Kuala Lumpur"
          "pivot_tour_id" => 1
          "pivot_city_id" => 1
        ]
        #relations: array:1 [▼
          "pivot" => Pivot {#314 ▼
            #parent: Tour {#283 ▼
              #dates: array:1 [▼
                0 => "deleted_at"
              ]
              #table: "tours"
              #hidden: array:2 [▼
                0 => "created_at"
                1 => "updated_at"
              ]
              #mappingProperties: array:1 [▼
                "pac_amount" => array:1 [▼
                  "type" => "double"
                ]
              ]
              #fillable: array:1 [▼
                0 => "pac_amount"
              ]
              #connection: null
              #primaryKey: "id"
              #perPage: 15
              +incrementing: true
              +timestamps: true
              #attributes: []
              #original: []
              #relations: []
              #visible: []
              #appends: []
              #guarded: array:1 [▼
                0 => "*"
              ]
              #dateFormat: null
              #casts: []
              #touches: []
              #observables: []
              #with: []
              #morphClass: null
              +exists: false
              +wasRecentlyCreated: false
              #forceDeleting: false
              #usesTimestampsInIndex: true
              #isDocument: false
              #documentScore: null
              #documentVersion: null
            }
            #foreignKey: "tour_id"
            #otherKey: "city_id"
            #guarded: []
            #connection: null
            #table: "city_tour"
            #primaryKey: "id"
            #perPage: 15
            +incrementing: true
            +timestamps: false
            #attributes: array:2 [▶]
            #original: array:2 [▶]
            #relations: []
            #hidden: []
            #visible: []
            #appends: []
            #fillable: []
            #dates: []
            #dateFormat: null
            #casts: []
            #touches: []
            #observables: []
            #with: []
            #morphClass: null
            +exists: true
            +wasRecentlyCreated: false
          }
        ]
        #visible: []
        #appends: []
        #fillable: []
        #guarded: array:1 [▶]
        #dates: []
        #dateFormat: null
        #casts: []
        #touches: []
        #observables: []
        #with: []
        #morphClass: null
        +exists: true
        +wasRecentlyCreated: false
      }
    ]
  }
  "languages" => Collection {#313 ▶}
  "categories" => Collection {#323 ▶}
  "photos" => Collection {#310 ▼
    #items: array:1 [▶]
  }
  "packages" => Collection {#328 ▼
    #items: array:1 [▶]
  }
  "reviews" => Collection {#330 ▼
    #items: []
  }
]

yaofong avatar Apr 27 '16 15:04 yaofong

@chuangbo Hi, Also I have the same error after updating the package. Is there any fix?

demirhancosku avatar May 27 '16 15:05 demirhancosku

I'm having this problem too with the BelongsToMany relation.

In the ElasticquentTrait:

public static function loadPivotAttribute(Model $model, Relation $parentRelation = null)
    {
        $attributes = $model->getAttributes();

        foreach ($attributes as $key => $value) {
            if ($key === 'pivot') {
                unset($model[$key]);
                $pivot = $parentRelation->newExistingPivot($value);
                $model->setRelation($key, $pivot);
            }
        }
    }

I don't have pivot key. When I dump $attributes, get:

array:3 [
  "id" => 12
  "name" => "Peter Forsberg"
  "property_id" => 2
]

Indexing: Item::with('user', 'values')->get()->addToIndex();

It is stored as (single item):

"_source": {
   "id": 32,
   "name": "Jarda",
   "description": "bar",
   "order": 1,
   "category_id": 34,
   "user_id": 1,
   "album_id": 5,
   "user": {
      "id": 1,
      "firstname": "John",
      "lastname": "Doe",
      "username": "ecolroy",
      "email": "[email protected]",
      "gender": "male",
      "country": "CS",
      "city": null,
      "remember_token": null,
      "created_at": "2016-08-12 18:22:32",
      "updated_at": "2016-08-19 16:40:49"
   },
   "values": [
      {
         "id" => 12,
         "name" => "Peter Forsberg",
         "property_id" => 2
      }
   ]
}

Item class relationship definition:

public function values()
{
    return $this->belongsToMany(Value::class, 'item_property_value');
}

It results in the error 500 in the BelongsToMany class, here with $result->pivot as NULL (accessing property of non-object)

 protected function buildDictionary(Collection $results)
    {
        $foreign = $this->foreignKey;

        // First we will build a dictionary of child models keyed by the foreign key
        // of the relation so that we will easily and quickly match them to their
        // parents without having a possibly slow inner loops for every models.
        $dictionary = [];

        foreach ($results as $result) {
            $dictionary[$result->pivot->$foreign][] = $result;
        }

        return $dictionary;
    }

jakubkratina avatar Sep 13 '16 10:09 jakubkratina

:-) You just have to load pivot, so instead of:

return $this->belongsToMany(Value::class, 'item_property_value');

load with pivot

return $this->belongsToMany(Value::class, 'item_property_value')
            ->withPivot('item_id', 'value_id');

I think this should be in the documentation. What do you think @chuangbo? Can I make a pull request?

jakubkratina avatar Sep 13 '16 10:09 jakubkratina

With the new update I am also running into the similar issue.

Trying to get property of non-object

I am using Laravel 5.1 version.

More specifically the code breaks at $dictionary[$result->pivot->$foreign][] = $result; in file BelongsToMany.php. It was fine previously.

I have a model Collection and it has belongsToMany relations

public function files() { return $this->belongsToMany(File::class, 'collection_file', 'collection_id', 'file_id') ->withTimestamps(); }

This is where it breaks. Even I have updated my it to

public function files() { return $this->belongsToMany(File::class, 'collection_file', 'collection_id', 'file_id') ->withPivot('collection_id', 'file_id') ->withTimestamps(); }

Is there something I am missing.

jgardezi avatar Dec 12 '16 03:12 jgardezi

Can somebody confirm that the bug is fixed after applying changes: https://github.com/sugalvojau/Elasticquent/blob/de31f93231c80d74660d39f782c811859db9ceb7/src/ElasticquentTrait.php ?

PauliusMacernis avatar Jun 05 '17 13:06 PauliusMacernis

hi****

mahmoodhassouna avatar Aug 11 '20 20:08 mahmoodhassouna