前提
laravelを使ってSPAなwebアプリを作っています。
SNSライクにテキストと画像をDBに新規登録する過程で問題があるので質問させて頂きます。
実現したいこと
DBのテーブルのprimary key(ID)をstringに変更したので、modelを生成する際にID用のランダムな文字列を作りましたが、model(Cards.php)からidの値を取り出した時に$cards->idの中身がありません。
Cardsモデルの中で値が作れていないということでしょうか。
ユーザー認証は成功しております。
発生している問題・エラーメッセージ
AXIOSでapi/cardsというルートにアクセスし、CardControllerのcreate(新規作成)メソッドを実行したところで
エラーになるようで、laravel.logには以下のように".png”ファイルは存在しない、となっています。
[2022-07-05 15:06:27] local.ERROR: The file ".png" does not exist {"userId":1,"exception":"[object] (Symfony\\Component\\HttpFoundation\\File\\Exception\\FileNotFoundException(code: 0): The file \".png\" does not exist at /var/www/html/vendor/symfony/http-foundation/File/File.php:36) [stacktrace]
CardsControllerのdd()の出力をみると、同じように拡張子だけがとれていてランダムな値は生成できていないように見えます。
fffは$cards->postの値。
該当のソースコード
CardsController
php
1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\Request; 6use App\Http\Requests\StoreCards; 7use App\Models\Cards; 8use Illuminate\Support\Facades\Storage; 9use Illuminate\Support\Facades\DB; 10use Illuminate\Support\Facades\Auth; 11 12 13class CardsController extends Controller 14{ 15 16 public function __construct(){ 17 18 $this->middleware('auth'); 19 20 } 21 /** 22 * Display a listing of the resource. 23 * 24 * @return \Illuminate\Http\Response 25 */ 26 public function index() 27 { 28 // 29 } 30 31 /** 32 * 投稿 33 * 34 * @return \Illuminate\Http\Response 35 */ 36 public function create(StoreCards $request) 37 { 38 $extension = $request->posted_image->extension(); //png 39 40 $cards = new Cards(); 41 42 $cards->posted_image = $cards->id . '.' . $extension; //ここで$cards->idの値がないのでエラーになっている 43 $cards->post = $request->post; 44 45 var_dump($cards->posted_image); 46 47 dd($cards->posted_image,$cards->post); 48 49 //中略 50 51 return response($cards,201); 52 } 53
Cards.php
php
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Factories\HasFactory; 6use Illuminate\Database\Eloquent\Model; 7 8use App\Http\Helper; 9 10class Cards extends Model 11{ 12 use HasFactory; 13 14 15 protected $keyType = 'string'; 16 protected $table = 'cards'; 17 public $incrementing = false; 18 protected $guarded =[]; 19 20 21 protected static function boot(){ 22 23 parent::boot(); 24 25 static::creating(function($model){ 26 27 $randomId = Helper::getRandomId(); 28 29 $exists = Cards::where('id',$randomId)->exists(); 30 31 if(!$exists){ 32 $model->id = $randomId; 33 } 34 35 }); 36 } 37 38} 39 40
php
1<?php 2 3namespace App\Http\Helper; 4 5class Helper{ 6 7 function getRandomId(){ 8 9 $characters = array_merge( 10 range(0,9), 11 range('a','z'), 12 range('A','Z'), 13 ['_','-'] 14 ); 15 16 $length = count($characters); 17 18 $id = ''; 19 20 for($i = 0; $i < 12; $i++){ 21 22 $id .= $characters[random_int(0,$length -1)]; 23 } 24 25 return $id; 26 27 } 28 29} 30 31 32
php
1<?php 2 3use Illuminate\Database\Migrations\Migration; 4use Illuminate\Database\Schema\Blueprint; 5use Illuminate\Support\Facades\Schema; 6 7return new class extends Migration 8{ 9 /** 10 * Run the migrations. 11 * 12 * @return void 13 */ 14 public function up() 15 { 16 Schema::create('cards', function (Blueprint $table) { 17 $table->string('id')->primary(); 18 $table->unsignedBigInteger('user_id')->comment('ユーザID'); 19 $table->string('post')->comment('本文'); 20 $table->longtext('posted_image')->comment('投稿画像'); 21 $table->softDeletes(); 22 $table->timestamps(); 23 24 $table->index('id'); 25 $table->index('user_id'); 26 $table->index('post'); 27 28 $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); 29 }); 30 } 31 32 /** 33 * Reverse the migrations. 34 * 35 * @return void 36 */ 37 public function down() 38 { 39 Schema::dropIfExists('cards'); 40 } 41};
php
1<?php 2 3use Illuminate\Http\Request; 4use Illuminate\Support\Facades\Route; 5use App\Http\Controllers\Auth\LoginController; 6use App\Http\Controllers\Auth\RegisterController; 7use App\Http\Controllers\CardsController; 8 9Route::post('/login',[LoginController::class,'login']); 10Route::post('/logout',[LoginController::class,'logout'])->name('login'); 11Route::post('/register',[RegisterController::class, 'register'])->name('register'); 12 13 14Route::middleware('auth:sanctum')->group(function(){ 15 Route::post('/cards',[CardsController::class, 'create'])->name('cards.create'); 16}); 17
Vue
1 2<template> 3 4<v-dialog 5 transition="dialog-bottom-transition" 6 max-width="600"> 7 8 <template v-slot:activator="{ on, attrs }"> 9 10 <v-btn 11 v-bind="attrs" 12 v-on="on"> 13 <span>投稿する</span> 14 <v-icon>mdi-timeline</v-icon> 15 </v-btn> 16 17 </template> 18 <template v-slot="dialog"> 19 <v-card> 20 <v-toolbar> 21 22 </v-toolbar> 23 24 <v-text-field 25 placeholder="ここに投稿" 26 name = "post" 27 required 28 outlined 29 dense 30 v-model="post"> 31 </v-text-field> 32 33 34 <input class="form__item" type="file" @change="onFileChange"> 35 36 <output class="form__output" v-if="preview" > 37 <img :src="preview" alt="" width="400" height="400"> 38 </output> 39 40 41 <v-card-actions class="justify-end"> 42 <v-form ref="form" @submit.prevent ="submit"> 43 <!-- <div class="errors" v-if="errors"> 44 <ul v-if="errors.posted_image"> 45 <li v-for="msg in errors.posted_image" :key="msg">{{ msg }}</li> 46 </ul> 47 </div> --> 48 <v-btn type="submit" color="rgb(106, 118, 171)" class="float-right">投稿する</v-btn> 49 </v-form> 50 <v-btn 51 text 52 @click="dialog.value= false">Close</v-btn> 53 54 </v-card-actions> 55 </v-card> 56 </template> 57</v-dialog> 58 59 60</template> 61 62<script> 63 64import axios from 'axios' 65import { INTERNAL_SERVER_ERROR} from '../../util' 66 67 68export default{ 69 70 name: "PostModal", 71 72 data(){ 73 74 return{ 75 preview: null, 76 posted_image: null, 77 post: null, 78 errors: null 79 } 80 81 }, 82 83 methods: { 84 onFileChange(event){ 85 86 87 const reader = new FileReader() 88 89 reader.onload = e =>{ 90 91 this.preview = e.target.result 92 } 93 94 reader.readAsDataURL(event.target.files[0]) 95 96 this.posted_image = event.target.files[0] 97 98 99 }, 100 reset(){ 101 this.preview = '', 102 this.posted_image = null, 103 this.$el.querySelector('input[type="file"]').value = null 104 }, 105 async submit(){ 106 const formData = new FormData(); 107 108 formData.append('posted_image',this.posted_image); 109 formData.append('post',this.post); 110 111 const response = await axios.post('/api/cards',formData) 112 113 114 if (response.status === INTERNAL_SERVER_ERROR) { 115 this.errors = response.data.errors 116 return false 117 } 118 119 120 } 121 } 122} 123</script> 124 125
試したこと
Logや検証ツールで見るかぎり、フォームからControllerに値はわたっているようです。問題はControllerまたはModelのコードにあるようですが間違いが分かりませんでした。
長文で申し訳ありませんが、ご指摘頂ければと思います。
補足情報(FW/ツールのバージョンなど)
laravel9.18.0
laravel/sail1.14.11
vue2
vuetify2.6.6
php8.1.7
MySQL8.0.29

回答3件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。