Hi,
I want to assign multiple categories to a post. But I can get It to work. The post is added in the database including the user. But I get no results in my category_posts table.
Here are my migrations:
Post table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->string('slug')->unique();
$table->string('image', 2048)->nullable();
$table->longText('body');
$table->boolean('active')->nullable()->default(false);
$table->datetime('published_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Category table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('title')->unique();
$table->string('slug')->unique();
$table->boolean('active')->nullable()->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};
Categorie_posts table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('category_posts', function (Blueprint $table) {
$table->id();
$table->foreignId('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->foreignId('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('category_posts');
}
};
I made 3 models, Post, Category and CategoryPost.
In my Model Post I have:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'title',
'image',
'body',
'active',
'published_at',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
in my Model Category I have.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Category extends Model
{
use HasFactory;
protected $fillable = [
'title',
'active',
];
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
This Is my Create Post Blade file
<x-admin-layout>
@push('styles')
<link href="https://unpkg.com/filepond@^4/dist/filepond.css" rel="stylesheet" />
<link href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" rel="stylesheet" />
@endpush
<x-slot name="header">
Posts
</x-slot>
<x-card.default>
<form action="{{ route('admin.posts.store') }}" method="POST" enctype="multipart/form-data" class="space-y-6">
@csrf
<div class="flex justify-between gap-6">
<div class="w-1/2">
<x-form.label for="title" value="Title" />
<x-form.input type="text" name="title" id="title" :value="old('title')" required autofocus />
<x-form.input-error for="name" class="mt-2" />
</div>
<div class="w-1/2">
<x-form.label for="categories" value="Categories" />
<x-form.select id="categories" name="categories[]" multiple="multiple">
@foreach($categories as $category)
<option value="{{ $category->id }}">{{ $category->title }}</option>
@endforeach
</x-form.select>
<x-form.input-error for="post.categories" class="mt-2" />
</div>
</div>
<div>
<x-form.label for="image" value="Image" />
<x-form.input type="file" name="image" id="image" required />
<x-form.input-error for="image" class="mt-2" />
</div>
<div>
<x-form.label for="body" value="Text" />
<x-form.textarea id="body" name="body"/>
<x-form.input-error for="body" class="mt-2" />
</div>
<div class="flex justify-between gap-6">
<div class="w-1/2">
<div class="relative max-w-sm">
<div class="absolute inset-y-0 left-0 flex items-center pl-3.5 pointer-events-none">
<svg class="w-4 h-4 text-gray-700 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
</svg>
</div>
<input datepicker datepicker-format="yyyy-mm-dd" type="text" id="published_at" name="published_at" class="bg-gray-50 border border-gray-300 text-gray-700 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-white dark:text-white dark:focus:ring-orange-500 dark:focus:border-orange-500" placeholder="Select date">
</div>
</div>
<div class="w-1/2">
<label class="relative inline-flex items-center mr-5 cursor-pointer">
<input name="active"
id="active"
value="1"
aria-describedby="active"
type="checkbox"
class="sr-only peer"
checked
>
<div class="w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-focus:ring-4 peer-focus:ring-orange-300 dark:peer-focus:ring-orange-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-orange-500"></div>
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Active</span>
</label>
</div>
</div>
<div class="flex justify-end space-x-2">
<x-button.secondary type="button" onclick="history.back()" class="px-3 py-2 text-xs font-medium">Cancel</x-button.secondary>
<x-button.primary class="px-3 py-2 text-xs font-medium">Save</x-button.primary>
</div>
</form>
</x-card.default>
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.7.0/datepicker.min.js"></script>
<script src="https://unpkg.com/filepond-plugin-file-validate-type/dist/filepond-plugin-file-validate-type.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.js"></script>
<script src="https://unpkg.com/filepond-plugin-file-validate-size/dist/filepond-plugin-file-validate-size.js"></script>
<script src="https://unpkg.com/filepond@^4/dist/filepond.js"></script>
<script>
FilePond.registerPlugin(FilePondPluginImagePreview);
FilePond.registerPlugin(FilePondPluginFileValidateType);
FilePond.registerPlugin(FilePondPluginFileValidateSize);
// Get a reference to the file input element
const inputElement = document.querySelector('#image');
// Create a FilePond instance
const pond = FilePond.create(inputElement, {
acceptedFileTypes: ['image/*'],
server: {
process: '{{ route('admin.filepond.upload') }}',
revert: '{{ route('admin.filepond.revert') }}',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}
});
</script>
@endpush
</x-admin-layout>
Im my Post Controller:
public function create(): View
{
$categories = Category::all();
return view('admin.posts.create', [
'categories'=>$categories
]);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => ['required', 'string', 'max:255', 'unique:posts'],
'image' => ['required'],
'body' => 'nullable|min:10',
'active' => 'nullable',
'published_at' => 'nullable',
]);
$newFilename = Str::after($request->input('image'), 'tmp/');
Storage::disk('public')->move($request->input('image'), "posts/$newFilename");
$slug = SlugService::createSlug(Post::class, 'slug', $request->title);
$post = Post::create([
'user_id' => current_user()->id,
'title' => $request['title'],
'slug' => $slug,
'image' => "posts/$newFilename",
'body' => $request['body'],
'active' => $request['active'],
'published_at' => $request['published_at'],
]);
$post->categories()->attach($request->categories_id);
$request->session()->flash('success', 'Post successfully created.');
return redirect()->route('admin.posts.index');
}
I get the error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table '******.category_post' doesn't exist
Thats correct I need to have the table category_posts
How to store the multiple categories in de CategoryPost table: