#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 тега в моем выпадающем списке», что предполагает, что это ввод, подобный массиву. Тем не менее, я думаю, мы не должны предполагать.