Home > Blockchain >  What makes the "Add article" form in this Laravel 8 application fail?
What makes the "Add article" form in this Laravel 8 application fail?

Time:03-27

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 >
            <label for="title" >{{ __('Title') }}</label>

            <div >
                    <input id="title" type="text" placeholder="Title"  name="title" value="{{ old('title') }}" autocomplete="title" autofocus>

                    @error('title')
                        <span  role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
            </div>
    </div>

    <div >
            <label for="short_description" >{{ __('Short description') }}</label>

            <div >
                    <input id="short_description" type="text" placeholder="Short description"  name="short_description" value="{{ old('short_description') }}" autocomplete="short_description" autofocus>

                    @error('short_description')
                        <span  role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
            </div>
    </div>

    <div >
        <label for="category" >{{ __('Category') }}</label>
    
        <div >
    
            <select name="category_id" id="category" >
                <option value="0">Pick a category</option>
                @foreach($categories as $category)
                    <option value="{{ $category->id }}">{{ $category->name }}</option>
                @endforeach
            </select>
                
                @error('category_id')
                    <span  role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
        </div>
    </div>

    <div >
        <div >
                <p >Featured article?</p>
                <input  type="checkbox" name="featured" id="featured">
                <label  for="featured">{{ __('Toggle') }}</label>
        </div>
    </div>

    <div >
        <label for="image" >{{ __('Article image') }}</label>
    
        <div >
            <input type="file" name="image" id="file" >
    
            @error('image')
                <span  role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
    </div>

    <div >
        <label for="content" >{{ __('Content') }}</label>

        <div >

            <textarea name="content" id="content"  placeholder="Content" cols="30" rows="6">{{ old('content') }}</textarea>

            @error('content')
                <span  role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
    </div>
    
    <div >
            <div >
                    <button type="submit" >
                            {{ __('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?

CodePudding user response:

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

CodePudding user response:

Your column is defined as a tinyInteger that can only accept a single digit, but you seem to be passing a string on to it.

$table->tinyInteger('featured')->default('0');

General error: 1366 Incorrect integer value: 'on' for column 'featured' at row 1

Try setting the value of your checkbox to 1.

<input  type="checkbox" name="featured" id="featured" value="1">

Edit, make sure to add boolean to your validation rules after adding the value to your input element.

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|boolean'
];
  • Related