В форме у меня есть поле Теги, которое является просто стандартным текстовым полем.Пользователь может ввести имя тега, и оно будет добавлено в статью.
У меня уже есть три таблицы: tags
, taggables
и articles
, и они связаны с помощью методов связи Eloquent, учитывая настройкив на предыдущий вопрос я задавал.
Это мой метод обновления в моем ArticleController
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$validatedData = $request->validate([
'title' => 'required',
'excerpt' => 'required',
]);
$article = Article::find($id);
$article->title = $request->get('title');
$article->author = $request->get('author');
$article->category = $request->get('category');
$article->excerpt = $request->get('excerpt');
$article->content = $request->get('content');
$article->featuredImage = $request->get('featuredImage');
$article->featuredVideo = $request->get('featuredVideo');
$article->readingTime = $request->get('readingTime');
$article->published = $request->get('published');
$article->save();
/**
* Once the article has been saved, we deal with the tag logic.
* Grab the tag or tags from the field, sync them with the article
*/
$tags = $request->get('tags');
$comma = ',';
if (!empty($tags)) {
if (strpos($tags, $comma) !== false) {
$tagList = explode(",", $tags);
// Loop through the tag array that we just created
foreach ($tagList as $tags) {
// Get any existing tags
$tag = Tag::where('name', '=', $tags)->first();
// If the tag exists, sync it, otherwise create it
if ($tag != null) {
$article->tags()->sync($tag->id);
} else {
$tag = new Tag();
$tag->name = $tags;
$tag->slug = str_slug($tags);
$tag->save();
$article->tags()->sync($tag->id);
}
}
} else {
// Only one tag
$tag = Tag::where('name', '=', $tags)->first();
if ($tag != null) {
$article->tags()->sync($tag->id);
} else {
$tag = new Tag();
$tag->name = $tags;
$tag->slug = str_slug($tags);
$tag->save();
$article->tags()->sync($tag->id);
}
}
}
return back();
return redirect()->back();
}
В разделе этого метода, который ищет теги, явыполните следующие действия:
- Проверьте, не является ли поле не пустым
- Проверьте, содержит ли отправленная строка запятую
- Если есть запятая, я использую
explode()
для преобразования строки в массив - Цикл по массиву, чтобы увидеть, существует ли данный тег в строке
- Если его не существует, я создаю его, а затем синхронизируюсо статьей, в противном случае я просто синхронизирую ее
Этот подход кажется очень грязным, однако, есть ли способ, которым я мог бы сделать это чище?
Обновление с учетом предоставленных ответов
Я выбрал следующий подход:
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required',
'excerpt' => 'required',
]);
$article = new Article();
$article->title = $request->get('title');
$article->author = $request->get('author');
$article->category = $request->get('category');
$article->excerpt = $request->get('excerpt');
$article->content = $request->get('content');
$article->featuredImage = $request->get('featuredImage');
$article->featuredVideo = $request->get('featuredVideo');
$article->readingTime = $request->get('readingTime');
$article->published = $request->get('published');
//If no featured image set, automatically create featured image placeholder
if ($request->get('featuredImage') == null) {
$article->featuredImage = "http://via.placeholder.com/350x150";
}
$article->save();
// Handle Tags
$tags = $request->get('tags');
if (!empty($tags)) {
$tagList = array_filter(explode(",", $tags));
// Loop through the tag array that we just created
foreach ($tagList as $tags) {
$tag = Tag::firstOrCreate(['name' => $tags, 'slug' => str_slug($tags)]);
}
$tags = Tag::whereIn('name', $tagList)->get()->pluck('id');
$article->tags()->sync($tags);
}
return redirect('editable/news-and-updates')->with('success', 'Article has been added');
}
И затем, чтобы отобразить теги при обновленииЯ сделал следующее:
/**
* Show the form to edit this resource
*/
public function edit($id)
{
$user = auth::user();
$article = Article::find($id);
// Get the tags associated with this article and convert to a comma seperated string
if ($article->has('tags')) {
$tags = $article->tags->pluck('name')->toArray();
$tags = implode(', ', $tags);
} else {
$tags = "";
}
return view('editable.news.edit', compact('article', 'user', 'tags'));
}
По сути, я просто беру теги, связанные со статьей, преобразую их в массив, а затем использую implode()
.
Это дает мне теги в виде списка через запятую в поле тегов, например:
blue, red, orange
Однако при обновлении, если я пытаюсь сохранить с тем жетеги в поле, которое я получаю:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'sauce' for key 'tags_slug_unique' (SQL: insert into
теги (
имя ,
slug ,
updated_at ,
create_at ) values ( sauce, sauce, 2018-05-26 11:42:17, 2018-05-26 11:42:17))
Вот тег тега для справки
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug')->unique();
$table->timestamps();
});
Schema::create('taggables', function (Blueprint $table) {
$table->increments('id');
$table->integer('tag_id')->unsigned();
$table->integer('taggable_id')->unsigned();
$table->string('taggable_type');
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('taggables');
Schema::dropIfExists('tags');
}
}