php - Laravel 中添加标签的解决方案

标签 php laravel laravel-5

在一个表单中,我有一个标签字段,它只是一个标准的文本字段。用户可以键入标签名称并将其添加到文章中。

我已经有了三个表:tagstaggablesarticles,它们通过 Eloquent 关系方法链接,给定 a previous question I 中的设置问。

这是我在 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();
}

在这个方法中查找标签的部分,我做了以下事情:

  1. 检查字段是否为空
  2. 检查发送的字符串是否包含逗号
  3. 如果有逗号,我使用explode()将字符串转换成数组
  4. 遍历数组以查看字符串中给定的标签是否已经存在
  5. 如果它不存在,我创建它然后将它与文章同步,否则我就同步它

这种方法感觉很乱,但是,有什么办法可以使它更干净吗?

根据提供的答案进行更新

我采用了以下方法:

/**
 * 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()

这在标签字段中以逗号分隔的列表形式提供了标签,例如:

蓝色、红色、橙色

但是,更新时,如果我尝试在字段中使用相同的标签进行保存,我会得到:

SQLSTATE[23000]:违反完整性约束:1062 键“tags_slug_unique”的重复条目“sauce”(SQL:插入tags(nameslug,updated_at,created_at) 值 ( 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');
    }
}

最佳答案

也许是这样的,只是从头脑中输入,没有经过测试,但我希望它能给你一个想法

public function update(Request $request, Article $article)
{
    $validatedData = $request->validate([
        'title' => 'required',
        'excerpt' => 'required',
        // Make validation for all inputs !
    ]);

    // Fill model with inputs and save (make sure that inputs are in fillable model property)
    $article->fill($request->all())->save();

    // Handle Tags 
    $this->handleTags($request, $article);

    // Return Redirect to previous URL
    return redirect()->back();
}

/**
 * Handle Tags for Article
 * @param  \Illuminate\Http\Request  $request
 * @param \App\Article $article
 * @return void
 */
public function handleTags(Request $request, Article $article){
    /**
     * 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
     */
    $tagsNames = explode(',', $request->get('tags'));

    // Create all tags (unassociet)
    foreach($tagsNames as $tagName){
        Tag::firstOrCreate(['name' => $tagName, 'slug' => str_slug($tagName)])->save();
    }

    // Once all tags are created we can query them
    $tags = Tag::whereIn('name', $tagsNames)->get()->pluck('id')->get();
    $article->tags()->sync($tags);
}

关于php - Laravel 中添加标签的解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50529715/

相关文章:

php - Ubuntu PHP APACHE2 全新安装问题

php - 使用 PHP 和 MySQL 创建相关或类似的帖子

php - 在 Mac 上启动 Laravel cron 作业

php - 数据库记录created_at时间随机变化

php - L5.5 使用 SSH 在共享主机上的存储和公共(public)目录之间创建符号链接(symbolic link)

php - Laravel 登录在边缘和 Internet Explorer 中不起作用

php - 为什么 foreach 在结果对象上不起作用?

laravel - 使用 laravel5.2、vue.js 和 pusher 实时获取数据

php - Laravel v5.2.* (v5.2.29) Auth::guard ('api' )->attempt($user) fatal error

php - 通过 PHP(多维数组)合并非常复杂的 SQL 数据结果