Я новичок в Laravel и пытаюсь изучить структуру. В настоящее время я создаю простую страницу сообщений/таблицы лидеров, на которую пользователи смогут загружать на нее аудиофайл. Все работает нормально, за исключением загрузки звука. Я не уверен, где ошибка. Я также использую vite для использования кода React для своих компонентов.
Для проверки: я пробовал использовать такие мимомы, как audio/mpeg, mp3, mpeg, aac, wav. Ни один из них не работал, когда я загрузил mp3. И при этом он не сохраняет файл. В конце концов я просто попытался сделать звук обнуляемым и не добавлять никаких дополнительных проверок. В этот момент он перенаправляет меня на страницу сообщений, где я могу увидеть данные. Но звук никуда не сохраняется. По сути, оно утрачено.
Ниже добавлю все необходимые файлы. Где я делаю что-то не так?
create_inzending_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('inzendings', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('category');
$table->timestamp('posted_at')->nullable();
$table->string('upvotes')->nullable();
$table->string('description');
$table->string('posted_by');
$table->string('audio');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('inzendingen');
}
};
Запросы/StoreInzending.php:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreInzending extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'audio' =>'nullable',
'title' => ['required', 'string', 'max:255'],
'description' => ['required', 'string', 'max:255'],
'posted_by' => ['required', 'string', 'max:255'],
'posted_at' => ['nullable', 'date'],
'category' => ['required', 'string', 'max:255'],
'upvotes' => ['integer'],
];
}
}
Модели/Inzending.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Inzending extends Model
{
protected $fillable = [
'audio',
'title',
'description',
'imageUrl',
'posted_at',
'posted_by',
'category',
'upvotes'
];
use HasFactory;
}
маршруты/web.php:
Route::get('inzending', [InzendingController::class,'index'])->name('inzending.index');
Route::get('inzending/create', [InzendingController::class,'create'])->name('inzending.create');
Route::post('inzending', [InzendingController::class,'store'])->name('inzending.store');
СоздатьInzendingForm.jsx:
import React, { useState } from 'react';
import { Link, useForm, usePage } from '@inertiajs/react';
import InputError from '@/Components/InputError';
import InputLabel from '@/Components/InputLabel';
import PrimaryButton from '@/Components/PrimaryButton';
import TextInput from '@/Components/TextInput';
import SelectInput from '@/Components/SelectInput';
import FileInput from './FileInput';
export default function CreateInzendingForm({ mustVerifyEmail, status, className }) {
const user = usePage().props.auth.user;
const inzending = usePage()
const { data, setData, patch, post, errors, processing, recentlySuccessful } = useForm({
name: user.name,
email: user.email,
education: user.education,
cohort: user.cohort,
title: inzending.title,
description: inzending.description,
posted_at: inzending.posted_at,
category: inzending.category,
posted_by: user.name,
audio: inzending.audio,
});
const submit = (e) => {
e.preventDefault();
console.info(data);
post(route('inzending.store'));
}
return (
<section>
<header>
<h2 className = "text-lg font-medium text-gray-900 dark:text-gray-100">Create Inzending</h2>
</header>
<form onSubmit = {submit} encType='multipart/form-data' className = "mt-6 space-y-6">
<div>
<InputLabel htmlFor = "title" value = "Title" />
<TextInput
id = "title"
className = "mt-1 block w-full"
onChange = {(e) => setData('title', e.target.value)}
required
isFocused
autoComplete = "title"
/>
<InputError className = "mt-2" message = {errors.title} />
</div>
<div>
<InputLabel htmlFor = "description" value = "Description" />
<TextInput
id = "description"
className = "mt-1 block w-full"
onChange = {(e) => setData('description', e.target.value)}
required
isFocused
autoComplete = "description"
/>
<InputError className = "mt-2" message = {errors.description} />
</div>
<div>
<InputLabel htmlFor = "category" value = "Category" />
<SelectInput
id = "category"
className = "mt-1 block w-full"
onChange = {(e) => setData('category', e.target.value)}
required
isFocused
autoComplete = "category"
/>
<InputError className = "mt-2" message = {errors.category} />
</div>
<div>
<InputLabel htmlFor = "posted_by" value = "Posted By" />
<TextInput
id = "posted_by"
className = "mt-1 block w-full"
value = {data.name}
onChange = {(e) => setData('posted_by', e.target.value)}
required
isFocused
autoComplete = "posted_by"
/>
<InputError className = "mt-2" message = {errors.posted_by} />
</div>
<div>
<InputLabel htmlFor = "audio" value = "Audio" />
<FileInput
id = "audio"
name = "audio"
className = "mt-1 block w-full"
onChange = {(e) => setData('audio', e.target.value)}
required
isFocused
autoComplete = "audio"
/>
<InputError className = "mt-2" message = {errors.audio} />
<div className = "flex items-center gap-4">
<PrimaryButton disabled = {processing}>Save</PrimaryButton>
</div>
</div>
</form>
</section>
);
}
ФайлИнпут.jsx:
import { forwardRef, useEffect, useRef } from 'react';
export default forwardRef(function FileInput({ type = 'file', name, className = '', isFocused = false, ...props }, ref) {
const input = ref ? ref : useRef();
useEffect(() => {
if (isFocused) {
input.current.focus();
}
}, []);
return (
<div className = "flex flex-col items-start">
<input
{...props}
name = {name}
type = {type}
className = {
'border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm ' +
className
}
ref = {input}
/>
</div>
);
});
конфигурация/файловые системы.php:
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('images') => storage_path('app/public/images'),
public_path('videos') => storage_path('app/public/videos'),
public_path('audio') => storage_path('app/public/audio'),
],
Любая помощь очень ценится!
Проблема решена!
Это оказалось простым исправлением, так как в форме я читал e.target.value входного файла, который записывал C:\fakepath\file.mp3. Не сам файл.
Чтобы решить эту проблему, вместо этого прочитайте e.target.files[0].