Issue
I am making a blogging application with Laravel 8 and Bootstrap 5.
I run into a problem with adding an article into the articles
table.
In the migration file that generated the articles
table, I have:
public function up() {
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->unsignedInteger('category_id');
$table->foreign('category_id')->references('id')->on('catergories');
$table->string('title');
$table->string('slug');
$table->string('short_description');
$table->longText('content');
$table->tinyInteger('featured')->default('0');
$table->string('image')->nullable();
$table->timestamps();
});
}
In the Article
model, I have:
class Article extends Model {
use HasFactory;
protected $fillable = [
'user_id',
'category_id',
'title',
'slug',
'short_description',
'content',
'featured',
'image',
];
// Join users to articles
public function user() {
return $this->belongsTo(User::class);
}
// Join categories to articles
public function category() {
return $this->belongsTo(ArticleCategory::class);
}
}
In the controller, I have:
namespace App\Http\Controllers\Dashboard;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Models\ArticleCategory;
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller {
private $rules = [
'category_id' => 'required|exists:article_categories,id',
'title' => 'required|string|max:255',
'short_description' => 'required|string|max:255',
'image' => 'image|mimes:jpeg,png,jpg|max:2048',
'content' => 'required|string',
'featured' => 'required'
];
private $messages = [
'category_id.required' => 'Please pick a category for the article',
'title.required' => 'Please provide a title for the article',
'short_description.required' => 'The article needs a short description',
'content.required' => 'Please add content'
];
public function categories() {
return ArticleCategory::all();
}
public function index() {
$articles = Article::paginate(10);
return view('dashboard/articles',
['articles' => $articles]
);
}
public function create() {
// Load the view and populate the form with categories
return view('dashboard/add-article',
['categories' => $this->categories()]
);
}
public function save(Request $request) {
// Validate form (with custom messages)
$validator = Validator::make($request->all(), $this->rules, $this->messages);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator->errors())->withInput();
}
$fields = $validator->validated();
// Upload article image
$current_user = Auth::user();
if (isset($request->image)) {
$imageName = md5(time()) . $current_user->id . '.' . $request->image->extension();
$request->image->move(public_path('images/articles'), $imageName);
}
// Data to be added
$form_data = [
'user_id' => Auth::user()->id,
'category_id' => $fields['category_id'],
'title' => $fields['title'],
'slug' => Str::slug($fields['title'], '-'),
'short_description' => $fields['short_description'],
'content' => $fields['content'],
'image' => $fields['image'],
'featured' => $fields['featured']
];
// Insert data in the 'articles' table
$query = Article::create($form_data);
if ($query) {
return redirect()->route('dashboard.articles')->with('success', 'Article added');
} else {
return redirect()->back()->with('error', 'Adding article failed');
}
}
}
The form:
<form method="POST" action="{{ route('dashboard.articles.add') }}" enctype="multipart/form-data" novalidate>
@csrf
<div class="row mb-2">
<label for="title" class="col-md-12">{{ __('Title') }}</label>
<div class="col-md-12 @error('title') has-error @enderror">
<input id="title" type="text" placeholder="Title" class="form-control @error('title') is-invalid @enderror" name="title" value="{{ old('title') }}" autocomplete="title" autofocus>
@error('title')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-2">
<label for="short_description" class="col-md-12">{{ __('Short description') }}</label>
<div class="col-md-12 @error('short_description') has-error @enderror">
<input id="short_description" type="text" placeholder="Short description" class="form-control @error('short_description') is-invalid @enderror" name="short_description" value="{{ old('short_description') }}" autocomplete="short_description" autofocus>
@error('short_description')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-2">
<label for="category" class="col-md-12">{{ __('Category') }}</label>
<div class="col-md-12 @error('category_id') has-error @enderror">
<select name="category_id" id="category" class="form-control @error('category_id') is-invalid @enderror">
<option value="0">Pick a category</option>
@foreach($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
@error('category_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-2">
<div class="col-md-12 d-flex align-items-center switch-toggle">
<p class="mb-0 me-3">Featured article?</p>
<input class="mt-1" type="checkbox" name="featured" id="featured">
<label class="px-1" for="featured">{{ __('Toggle') }}</label>
</div>
</div>
<div class="row mb-2">
<label for="image" class="col-md-12">{{ __('Article image') }}</label>
<div class="col-md-12 @error('image') has-error @enderror">
<input type="file" name="image" id="file" class="file-upload-btn">
@error('image')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-2">
<label for="content" class="col-md-12">{{ __('Content') }}</label>
<div class="col-md-12 @error('content') has-error @enderror">
<textarea name="content" id="content" class="form-control @error('content') is-invalid @enderror" placeholder="Content" cols="30" rows="6">{{ old('content') }}</textarea>
@error('content')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-12">
<button type="submit" class="w-100 btn btn-primary">
{{ __('Save') }}
</button>
</div>
</div>
</form>
The routes:
// Article routes
Route::group(['prefix' => 'articles'], function() {
Route::get('/', [ArticleController::class, 'index'])->name('dashboard.articles');
Route::get('/new', [ArticleController::class, 'create'])->name('dashboard.articles.new');
Route::post('/add', [ArticleController::class, 'save'])->name('dashboard.articles.add');
});
The problem:
Even though the form passes validation, and a redirect occurs, the record is not actually added to the articles
table.
Laravel throws the error General error: 1366 Incorrect integer value: 'on' for column 'featured' at row 1
.
What is my mistake?
Solution
When dealing with checkboxes you need to know that;
a) you cannot use required
since the checkbox is not sent with the form data if it is unchecked.
b) the default value is 'on' but actually, the presence of the field in the data means it was checked so what I normally do is like;
'featured' => $request->has('featured')
this will return a boolean true or false, suitable for storing in your db
So you could write
// Turn the 'featured' field value into a tiny integer
//$fields['featured'] = $request->get('featured') == 'on' ? 1 : 0;
// If no image is uploaded, use default.jpg
$fields['image'] = $request->get('image') == '' ? 'default.jpg' : $imageName;
// Data to be added
$form_data = [
'user_id' => Auth::user()->id,
'category_id' => $fields['category_id'],
'title' => $fields['title'],
'slug' => Str::slug($fields['title'], '-'),
'short_description' => $fields['short_description'],
'content' => $fields['content'],
'featured' => $request->has('featured'),
'image' => $fields['image']
];
Answered By - Snapey Answer Checked By - David Goodson (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.