Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

shiruken's avatar

Eloquent adds data not in model

I have two data sets where I'm comparing the same Model, but for some reason Eloquent is leaving adding in the row that is used for pivoting. Obviously, when I compare it to the original, it fails since the one being called through the hasMany relationship has one extra row. Please help! Many thanks!

the "Collection" model's method:

    public function nouns()
    {
        return $this->hasManyThrough('App\Models\CategoryNouns', 
                                     'App\Models\CollectionNouns',
                                     'collection_id',
                                     'id');
    }

dd of the object:

CategoryNouns {#411 ▼
  +timestamps: false
  #guarded: array:1 [▶]
  #table: "category_nouns"
  #connection: null
  #primaryKey: "id"
  #perPage: 15
  +incrementing: true
  #attributes: array:8 [▼
    "id" => "9"
    "noun" => "lose animal"
    "weight" => "1"
    "category_id" => "12"
    "created_at" => "0000-00-00 00:00:00"
    "updated_at" => "0000-00-00 00:00:00"
    "deleted_at" => null
    "collection_id" => "44"
  ]
  #original: array:8 [▼
    "id" => "9"
    "noun" => "lose animal"
    "weight" => "1"
    "category_id" => "12"
    "created_at" => "0000-00-00 00:00:00"
    "updated_at" => "0000-00-00 00:00:00"
    "deleted_at" => null
    "collection_id" => "44"
  ]
  #relations: []
  #hidden: []
  #visible: []
  #appends: []
  #fillable: []
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
  +wasRecentlyCreated: false
  #forceDeleting: false
}

dd of the original Model being compared:

CategoryNouns {#456 ▼
  +timestamps: false
  #guarded: array:1 [▶]
  #table: "category_nouns"
  #connection: null
  #primaryKey: "id"
  #perPage: 15
  +incrementing: true
  #attributes: array:7 [▼
    "id" => "64"
    "noun" => "testing wrong category system"
    "weight" => "100"
    "category_id" => "1"
    "created_at" => "0000-00-00 00:00:00"
    "updated_at" => "0000-00-00 00:00:00"
    "deleted_at" => null
  ]
  #original: array:7 [▼
    "id" => "64"
    "noun" => "testing wrong category system"
    "weight" => "100"
    "category_id" => "1"
    "created_at" => "0000-00-00 00:00:00"
    "updated_at" => "0000-00-00 00:00:00"
    "deleted_at" => null
  ]
  #relations: []
  #hidden: []
  #visible: []
  #appends: []
  #fillable: []
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
  +wasRecentlyCreated: false
  #forceDeleting: false
}

And now, for the original Model:

class CategoryNouns extends Model {

    use SoftDeletes;

    public $timestamps = false;
    protected $guarded = ['id'];
    protected $table ='category_nouns';

    /* input requirements */
    public static $rules = [
                            'noun'        => 'required|unique:category_nouns',
                            'weight'      => 'required|integer',
                            'category_id' => 'required|integer'
                           ];

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

And now the code used to compare:

            /* now we check for any prior corrections directed to our associations */
            $collections = [];

            //@TODO: check by how much does it match the prior collection
            for($i=0; $i<count($allCatNouns->values()); $i++) {
                $nounsGroup = $allCatNouns->values()->get($i); //make a collection out of the group

                if($col = Collection::where('old_category_id', $nounsGroup[0]->category_id)->get()) {
                    $id = $nounsGroup[0]->category_id; // take the cat id with us
                    foreach($col as $nounObj) {
                        //@TODO ain't necessarily only in one collection
                        $collections[$id] = $nounObj->nouns->values();
                    }
                }
            }

            if(!empty($collections)) {
                // should be a replica of $allCatnouns, if this issue has been submitted before and corrected by staff
                // $collections = collect($collections)->sortBy('category_id');

                for($i=0; $i<count($allCatNouns->values()); $i++) {
                    $nounsGroup = $allCatNouns->values()->get($i); //make a collection out of the group

                    // if it's category id is in Collections, check the noun groups to see if they match
                    if(isset($collections[$nounsGroup[0]->category_id])) {
                                    // this -V- is the category subcollection
                        if($collections[$nounsGroup[0]->category_id][0] == $nounsGroup[0]) {
dd(TRUE);
                        }
                    }
                }
            }
0 likes
12 replies
pmall's avatar

You should explain what you want to achieve, it is very unclear.

shiruken's avatar

@pmall I'm looping through 2 collections, see if the "CategoryNouns" Model match. Sorry about that!

shiruken's avatar

@pmall Because I'm hoping to be able to compare the whole collection at once, as opposed to looping through them.

pmall's avatar

as opposed to looping through them

Isn't it what you do in your last code snippet ?? Compare the ids it is more reliable.

shiruken's avatar

@pmall I'm looping through the collection of groups, not through each group. I don't want to compare each noun, which is what I'd have to do if I compared IDs.

Anyhow, why is Eloquent adding data to the model? It shouldn't be altering the structure for any reason.

jekinney's avatar

I see a lot of confusion and possibly me, a lot of unnecessary code. You want to compare if a noun has been used? Very simple foreach loop and return if a match or return if null (no match).

pmall's avatar

@shiruken I don't understand what you mean by altering structure, be more specific please. Also it is never a good practice in any language to raw compare objects, if you want to compare entities, then compare their ids.

shiruken's avatar

@pmall did you look at the two die dumps? I think I'm being more than specific. "collection_id" isn't supposed to be there. Eloquent is adding that to my data.

Here's my migration:

        Schema::create('category_nouns', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('noun');
            $table->integer('weight');
            $table->integer('category_id')->unsigned()->default(0);
            $table->foreign('category_id')->references('id')->on('categories');
            $table->timestamps();            
            $table->softDeletes();
        });

See? No collection_id row.

@jekinney I'd love to do that, that's the whole point of my question. However, Eloquent/Laravel is adding data to my model, so I can't just do a simple comparison.

I'm off to file yet another bug report.

pmall's avatar

@shiruken No need to get angry. This is not a bug, $attributes attribute of eloquent object doesn't intend to represent table columns but what columns was selected. Eloquent probably makes a join in order to make the hasManyThrough relationship, hence the collection_id. Also collection_id will be needed in order to make eager loading work (needed to associate a collection to the selected collection of nouns).

Still no idea why you are reluctant to compare ids.

shiruken's avatar

@pmall I'm reluctant because I'd like to do this: if($collection1 == $collection2) and move forward. Comparing IDs means I have to stick in two for loops to compare all of the values.

Please or to participate in this conversation.