Вставка данных в сводную таблицу в laravel

#php #laravel #eloquent #pivot-table

#php #laravel #красноречивый #сводная таблица

Вопрос:

У меня есть 3 таблицы: posts , tags , post_tag .

У каждого Post есть много тегов, поэтому я использую hasMany метод для них. Но когда я выбираю, например, 3 тега в моем выпадающем списке, я не могу добавить их в post_tag и в результате я не могу выбрать и показать теги каждой записи.

Моя Post модель:

  class Post extends Eloquent{
 public function tag()
         {
           return  $this->hasMany('Tag');
         }
    }
  

Моя Tag модель:

 class Tag extends Eloquent{
 public function post()
         {
           return  $this->belongsToMany('Post');
         }
  

}

И мой postController :

 class postController extends BaseController{

public function addPost(){

    $post=new Post;

    $post_title=Input::get('post_title');
    $post_content=Input::get('post_content');
    $tag_id=Input::get('tag');

    $post->tag()->sync($tag_id);
    $post->save();
  

Я ожидаю сохранить это post_id сохранить в post_tag таблицу с идентификаторами ее тегов,
но это не работает. Спасибо за ваше время.

Комментарии:

1. Если у отношения есть сводная таблица, то должны быть обе ее стороны belongsToMany . Также вы действительно должны называть метод tags не tag , поскольку это отношение * Many.

2. @alexrussell да, вы правы :). и другая проблема заключалась в том, $post->tag()->sync($tag_id); $post->save(); что эти отправленные данные должны быть заменены. Спасибо

3. Я добавил ответ, который немного подробнее объясняет мой комментарий и включает ваше собственное исправление.

Ответ №1:

У вас есть правильная основная идея, но есть несколько проблем с вашим кодом. Некоторые из них мешают ему работать, а некоторые — просто обычные проблемы.

Во-первых, это belongsTomany связь (у вас есть сводная таблица), поэтому вы должны определить обе стороны связи как belongsToMany (даже если hasMany вы думаете об одной или обеих сторонах этого). Это потому, что Laravel ожидает определенную структуру базы данных с двумя разными типами отношений.

Другая проблема (с которой вы столкнулись сами) заключается в том, что вы добавляете теги к отношению (через ->tag()->sync() до того, как вы фактически сохранили сообщение. Вы должны сначала сохранить post (чтобы laravel знал, для какого идентификатора добавлять в сводную таблицу post_id ), а затем добавить отношения. Если вы беспокоитесь о том, что часть тегов выйдет из строя, а затем у вас будет несогласованная база данных, вам следует использовать транзакции.

Наконец, ошибки «соглашения», с которыми вы сталкиваетесь, заключаются в том, что отношение «принадлежит многим» по определению включает в себя наборы результатов. Таким образом, tag и post должны быть tags и posts соответственно.

Итак, вот моя переписанная версия вашего кода:

 class Post extends Eloquent
{
    public function tags()
    {
        return $this->belongsToMany('Tag');
    }
}

class Tag extends Eloquent
{
    public function posts()
    {
        return $this->belongsToMany('Post');
    }
}

class PostController extends BaseController
{
    public function addPost()
    {
        // assume it won't work
        $success = false;

        DB::beginTransaction();

        try {
            $post = new Post;

            // maybe some validation here...

            $post->title = Input::get('post_title');
            $post->content = Input::get('post_content');

            if ($post->save()) {
                $tag_ids = Input::get('tags');
                $post->tags()->sync($tag_ids);
                $success = true;
            }
        } catch (Exception $e) {
            // maybe log this exception, but basically it's just here so we can rollback if we get a surprise
        }

        if ($success) {
            DB::commit();
            return Redirect::back()->withSuccessMessage('Post saved');
        } else {
            DB::rollback();
            return Redirect::back()->withErrorMessage('Something went wrong');
        }
    }
}
  

Теперь большая часть кода контроллера сосредоточена вокруг транзакций — если вас это не слишком волнует, тогда вы можете удалить это. Также есть несколько способов выполнить эту транзакцию — я выбрал один, который не идеален, но передает суть с минимальным объемом кода.

Ответ №2:

Чтобы вставить ваши данные в имя сводной таблицы diplome_user, просто следуйте моему примеру: моя сводная таблица выглядит как:

введите описание изображения здесь

 //this is Diplome Model

    class Diplome extends Model
    {
    public function users()
        {
            return $this->belongsToMany('AppUser','diplome_user')->withPivot('etablissement', 'annee', 'mention');;
        }
    }
  

теперь внутри вашего моего DiplomeController я могу выполнить этот запрос:

 $user = Auth::user(); 
  

поскольку мне нужен пользователь, я просто беру подключенного, после него я создаю один экземпляр Diplome, например:

 $diplome = new Diplome();
$diplome->libelle = "the name";
$diplome->decription= "description of the ...";
$diplome->save();
  

теперь самый важный шаг:

    $diplome->users()->attach($user, ['etablissement'=> 'bib',
                                            'annee'=>'2015',
                                            'mention'=>'AB',
                                            ]);
  

Вот результат:

введите описание изображения здесь

Комментарии:

1. Название класса настолько неправильное … «Диплом, принадлежащий множеству пользователей, ошибочен во многих отношениях»… Обычно пользователь имеет множество двоичных файлов, и двоичные файлы принадлежат одному пользователю

Ответ №3:

sync() Методу требуется массив. Это должно сработать, если вы просто поместите идентификатор тега в один, вот так:

 $post->tag()->sync([$tag_id]);
  

Комментарии:

1. Call to undefined method IlluminateDatabaseQueryBuilder::sync() . он появляется всегда:(

2. @joelhinz насколько я могу судить, приведенный выше код действительно отправлял бы форму $tag_id поступления Input::get('tag') массива, во вступлении к которой OP говорит «когда я выбираю, например, 3 тега в моем выпадающем списке», что предполагает, что это ввод, подобный массиву. Тем не менее, я думаю, мы не должны предполагать.