user2744115
user2744115

Reputation: 82

Laravel hasOne-belongsToMany relationship?

So, I was struggling to make this schema work (total newbie with laravel, by the way...) I have a 'photos' table and an audio 'tracks' table, and I want to be able to do something like this:

Track model:

// Get the photo associated with this track.
public function cover_art() {
    return $this->hasOne('App\Photo');
}

Photo model:

// Get all the tracks associated with this photo.  
public function tracks() {
    return $this->belongsToMany('App\Track');
}

What's the best solution to represent this relationship (an audio track can have only one photo, and a photo can belong to multiple tracks)?

Well, finally I set up everything and I get the expected errors:

Photos table:

Schema::create('photos', function (Blueprint $table) {
    $table->increments('id');
    $table->string('path');
    $table->string('filename');
    $table->string('original_filename');
    $table->boolean('is_cover')->default(false);
    $table->string('title');
    $table->string('slug')->unique();
    $table->string('caption')->nullable();
    $table->timestamps();
});

Tracks table:

Schema::create('tracks', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('photo_id')->unsigned()->nullable();
    $table->string('path');
    $table->string('filename');
    $table->string('original_filename');
    $table->string('title');
    $table->string('slug')->unique();
    $table->string('caption')->nullable();
    $table->timestamps();
    $table->foreign('photo_id')->references('id')->on('photos')->onDelete('set null');
});

So now, when for example I call the appropriate methods in my views or in my controllers I get these errors:

@foreach($tracks as $track)
    {{ $track->cover_art }}
@endforeach

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'photos.track_id' in 'where clause' (SQL: select * from photos where photos.track_id = 1 and photos.track_id is not null limit 1)

@foreach($photos as $photo)
    {{ $photo->tracks }}
@endforeach

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'iagomarta.photo_track' doesn't exist (SQL: select tracks.*, photo_track.photo_id as pivot_photo_id, photo_track.track_id as pivot_track_id from tracks inner join photo_track on tracks.id = photo_track.track_id where photo_track.photo_id = 1)

Any suggestions?

Upvotes: 1

Views: 5030

Answers (2)

Croisciento
Croisciento

Reputation: 149

Maybe it's just the typo as shown below :

create_table_tracks_migration :

Schema::create('tracks', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('photo_id')->unsigned();
    $table->string('path');
    $table->string('filename');
    $table->string('original_filename');
    $table->string('title');
    $table->string('slug')->unique();
    $table->string('caption')->nullable();
    $table->timestamps();
});

Schema::table('tracks', function(Blueprint $table)
        {
            $table->foreign('photo_id')
                ->references('id')
                ->on('photos')
                ->onDelete('cascade');
        });

It's generally best practice to set the foreign key reference this way as I've ran into some issues myself by not doing that.

And on a side note I really don't like creating nullable foreign keys as it can create a huge mess.

Also what looks weird is that error :

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'photos.track_id' in 'where clause' (SQL: select * from photos where photos.track_id = 1 and photos.track_id is not null limit 1)

And you shouldn't have a track_id column on your photo table anyway.

In addition to that you could try to set a belongsTo(App\Photo) relationship instead of a hasOne. It would work since a track can only have one photo. Also you don't need a pivot table since it's a one to many relationship and not a many to many relationship.

Upvotes: 1

samlev
samlev

Reputation: 5942

// Track Model
public function cover_art() {
    return $this->belongsTo('App\Photo');
}

// Photo Model
public function tracks() {
    return $this->hasMany('App\Track');
}

Think of it like this - the 'cover art'/'photo' is sitting in place of the album, so the 'album' (photo) has many tracks, and all of the tracks belong to one album.

Upvotes: 0

Related Questions