mercredi 23 mai 2018

Working with Laravel Many to Many Polymorphic relations

I have a scenario in which Events and Articles can have Tags, much like how you can add tags to a question on Stack Overflow.

The documentation gives a nice example of this by having two tables: Tags and Taggables which is ideal really.

I am following the documentation, so I have a Tag Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    /**
     * Get all of the posts that are assigned to a tag.
     */
    public function articles()
    {
        return $this->morphedByMany(Article::class, 'taggable');
    }
}

An Article Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    /**
     * Get all of the tags for the Article by finding the Tags for this article.
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

And this is my tags migration

<?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->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');
    }
}

Assuming I have an Article migration I should now be able to do the following between Controllers and Views:

$article = App\Tag::find(1);

foreach ($article->tags as $tag) {
    $tag->name
}

And the opposite

$tag = App\Tag::find(1);

foreach ($tag->articles as $article) {
    $article->title
}

In my view for creating articles I have a form that allows you to create articles and I have an input like the following:

div class="form-group">
    <label for="tags">Enter tags for this article</label>
    <input type="text" class="form-control" id="tags" name="tags" placeholder="Tags">
</div>

Then, when saving an Article I have a store method

/** * 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";
}

$tags = $request->get('tags');

$article->save();

return redirect('editable/news-and-updates')->with('success', 'Article has been added');
}

I have seen that with standard many-to-many relations you can use attach() to add the related elements.

What I'm trying to achieve is essentially what Stack Overflow does: when I type a tag, put a comma, then type another tag and hit save that question is saved with multiple tags, but also if the tag doesn't exist, it should be added and then associated with the Article.

I suppose though, if I make the tags input an array, I could grab the input and where ever there is a comma, create a new element, like this:

$tags = "foo,bar,baz,bat";
$tags_array = explode(",",$tags);

But then how would I both save these as well as add them to the given article?

I've also been looking at: https://selectize.github.io/selectize.js/ as I feel I could use this for the frontend.



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire