0

I have two tables: 'Articles' and 'Images'. In my Articles I have:

 `...
'body'
'image-1'
'image-2'
'image-3'
'image-4'
 ...`

I want to relate every article with one, two, three,... images stored in my database. And, of course, all the images can be used by more than one article.

My question is about which kind of relationship should I use between them. I don't know if it would be better to use a pivot table article_image (belongsToMany), or if I'm doing well using other kind of relationship. In that case... It would be good in that way?:

ImageModel.php

public function article()
    {       
        return $this->hasMany('Article', 'article_id');
    }

ArticleModel.php

public function image()
    {       
        return $this->hasMany('Image', 'image_id');
    }

EDIT:

Then, if I use a pivot table... Should I use some extra columns in my pivot table? Like...

$table->increments('id');
$table->integer('article_id')->unsigned()->index();
$table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
$table->integer('image-1')->unsigned()->index();
$table->foreign('image_id')->references('id')->on('images')->onDelete('cascade');
$table->integer('image-2')->unsigned()->index();
$table->foreign('image_id')->references('id')->on('images')->onDelete('cascade');
...
$table->timestamps();

I suppose I should remove onDelete('cascade') to avoid to lose my articles when delete an image?

EDIT 2:

In my Controller, I save the image in this way:

if(Session::get('imagen_1')){
                $imagen = new Imagen;
                $imagen->url = Session::get('imagen_1');
                $imagen->user_id = Sentry::getUser()->id;
                $imagen->save();    

                Session::forget('imagen_1');    

            }

Then, I create my article (I call it 'actividad')

$actividad = new actividad;
            $actividad->titulo = Input::get('titulo');
            $actividad->actividad = Input::get('actividad');            
            (...)
            $actividad->slug = Str::slug(Input::get('titulo'));
            $actividad->user_id = Sentry::getUser()->id;

            $actividad->save();

And, finally, I try to save the relation between both:

$actividad->imagens()->sync($imagen);

But it doesn't work... I'm having the next error message:

Argument 1 passed to Illuminate\Database\Eloquent\Relations\BelongsToMany::formatSyncList() must be of the type array, object given, called in /Applications/XAMPP/xamppfiles/htdocs/webs/lara4/edu1/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php on line 578 and defined

JaviZu
  • 487
  • 1
  • 8
  • 20
  • 3
    Don't go that way. You would end up with several `belongsTo` on the Article, and several `hasMany` on the Image. Create pivot table and use `belongsToMany` instead, which is exactly what you need here. – Jarek Tkaczyk Aug 23 '14 at 08:00
  • I would consider if you are ever going to search for posts that have a particular image. It's not a very usual use case. If not then just have a one way relation ship of article has many images. If you do need the relationship going the other way (image->article) then as Jarek_Tkaczyk_deczo said use a pivot table with belongs to many on both relationships. – Digital Fu Aug 23 '14 at 08:05
  • @JarekTkaczyk_deczo_ I've edited my question. Please, any suggestion? – JaviZu Aug 23 '14 at 08:30

1 Answers1

3

basic setup with additional pivot table data (primary), to show you how to work with it:

// DB
articles: id, title ... timestamps
images: id, url ... timestamps
article_image: id, article_id, image_id, primary, timestamps


// Article
public function images()
{
 return $this->belongsToMany('Image');
}

public function primaryImages()
{
 return $this->images()->wherePivot('primary', 1);
}

// Image
public function articles()
{
 return $this->belongsToMany('Article')->withPivot('primary');
}

// usage
$article->images; // collection

$article->images(); // relation object you can chain query methods on:
$article->images()->where(..)->orderBy(..)->get();

$images->articles; // collection

$article->primaryImages; // collection of related images with pivot primary=1

$image->articles->first()->pivot->primary; // value of the pivot field

// eager loading only chosen images:
$articles = Article::with(['images' => function ($q) {
  $q->wherePivot('primary', 0);
})->get();

// fetch only articles that have any image
$articles = Article::has('images')->get();

and so on..

Jarek Tkaczyk
  • 78,987
  • 25
  • 159
  • 157
  • I don't know if I've understood properly, but I would need to name every image (image-1, image-2, image-3, image-4) in every article, to show it correctly in my view. So, maybe I should create 4 extra columns ('image-1', 'image-2'...) in my pivot_table instead the `primary` column? I have a form to create an article where I can store 4 images, and I would like to store everyone in its place... – JaviZu Aug 23 '14 at 09:12
  • 1
    Definitely not, just add some logic that will take care of adding no more than 4 images, that's all. Having column per each image is very bad idea. Imagine you decide one day that there will be 5, 10 or whatever number you like of images per article.. If you need to order these images, then add `order` column and store 1,2,3,4 there instead. – Jarek Tkaczyk Aug 23 '14 at 10:57
  • I had just arrived at the same conclusion after write my comment... but I'm getting crazy trying to save an image related to my article. I'm gonna edit my question. I'd really appreciate if you can have a look and tell my what I'm doing wrong... – JaviZu Aug 23 '14 at 11:09
  • `attach` takes single `id` or `model` as argument, while `sync` takes array of ids or collection of models. So you just need to use attach in that case. Also mind that `sync` by default resets previous relations, while `attach` adds new relation, even though 2 models may have been already attached. – Jarek Tkaczyk Aug 25 '14 at 06:39