是什么导致此 Laravel 8 应用程序中的 "Add article" 表单失败?

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

我正在使用 Laravel 8 和 Bootstrap 制作博客应用程序 5.

我运行加入一个问题articles table.

在生成 articles table 的迁移文件中,我有:

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();
  });
}

Article模型中,我有:

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

在控制器中,我有:

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

形式:

<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>

路线:

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

问题:

即使表单通过验证并发生重定向,记录实际上并未添加到 articles table。

Laravel 抛出错误 General error: 1366 Incorrect integer value: 'on' for column 'featured' at row 1.

我的错误是什么?

您的列被定义为只能接受一个数字的 tinyInteger,但您似乎向其传递了一个字符串 on

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

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

尝试将复选框的值设置为 1

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

编辑,确保在将值添加到输入元素后将 boolean 添加到验证规则。

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'
];

处理复选框时你需要知道这些;

a) 您不能使用 required,因为如果未选中复选框则不会随表单数据一起发送。

b) 默认值为 'on' 但实际上,数据中存在该字段意味着它已被检查,所以我通常做的是这样的;

'featured' => $request->has('featured')

这将 return 布尔值 true 或 false,适合存储在您的数据库中

所以你可以这样写

        // 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']
        ];

如果它对任何人有帮助,这里是创建文章的工作代码:

路线:

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

在控制器中:

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'
    ];

    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::orderBy('id', 'desc')->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);
        }

        // 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' => $fields['featured'],
            'image' => $fields['image']
        ];

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