Hi I am trying to create a post using form data, because I have a file input to upload images. I am really struggling with getting the upload file to work. I get an error 500 when I try to create a post, with the message
SQLSTATE[HY000]: General error: 1364 Field 'title' doesn't have a default value (SQL: insert into posts ('updated_at', 'created_at') values (2018-01-30 12:31:18, 2018-01-30 12:31:18).
I am not sure what is meant by default value. I checked my $fillables and title is definitely there. When I run the following code in my controller right at the top it passes:
$request->all();
return response()->json('passed');
But when I have the following in my controller it gives the error:
public function create(Request $request)
{
Post::create($request->all());
$response = [
'response' => 'Post Created Successfully',
'error' => 'Something went wrong'
];
return response()->json($response);
}
Here is my HTML:
<div class="container">
<div class="row">
<h1>Create your post</h1>
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" id="title" class="form-control">
</div>
<div class="form-group">
<label for="post">Post</label>
<textarea name="post" rows="8" cols="80" id="post" class="form-control"></textarea>
</div>
<div class="form-group">
<label for="image">Add image</label>
<input type="file" name="image" id="image" class="form-control">
</div>
<input type="submit" name="submit" value="Submit Post" id="submit" class="btn btn-primary">
</div>
</div>
AJAX:
<script>
$(document).ready(function() {
$("#submit").on("click", function(e) {
e.preventDefault();
var formData = new FormData();
var fileData = $('#image').prop('files')[0];
var title = $('#title').val();
var post = $('#post').val();
formData.append('fileData', fileData);
formData.append('title', title);
formData.append('post', post);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr("content")
}
});
$.ajax({
url:'/post/create/create',
type: "POST",
data: {
formData: formData
},
processData: false,
contentType: false,
dataType: 'json',
success:function(response){
toastr.success(response.response);
},
error: function(error){
toastr.error(error.error)
}
});
});
});
</script>
Here is my Post model with the fillables:
protected $fillable = ['title', 'post', 'user_id', 'uploadImage'];
In-order to obtain the data from your ajax in your controller, pass the data as
data: formData
instead of
data: {
formData: formData
}
and you could process the information in your controller as
public function create(Request $request)
{
$path = '';
if ($request->hasFile('fileData')) {
if ($request->file('fileData')->isValid()) {
// Upload the file
$path = $request->fileData->store('your directory');
}
}
$post = Post::create([
'title' => $request->title,
'post' => $request->post,
'user_id' => auth()->user()->id,
'uploadImage' => $path
]);
if ($post) {
return response()->json([
'response' => 'Post Created Successfully!'
]);
}
return response()->json([
'error' => 'Something went wrong!'
], 500)
}
Documentation on storing uploaded files
Related
Scenario:
I am developing CMS system and I wan to add some categories to the objects (pages, posts, media etc.). In my view, to save a new category I use HTML form placed in Bootstrap modal which is sent via AJAX to my controller. The CSRF protection is enabled on the entire site.
While sending the data for the first time, I pass the CSRF token name and hash via form. Once being processed by PHP code in controller, I want to pass CSRF values in the response so I will be able to "re-use" the form in the modal (e.g. display error messages or/and create another category).
Yet, I am not able to access the get_csrf_token_name() and get_csrf_hash() methods to pass values back to the view.
In my view admmin/category/create.php:
...
<!-- CREATE CATEGORY MODAL MODAL -->
<div class="modal" id="createCategory" tabindex="-1">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Nová kategorie</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
</div>
<div class="modal-body">
<form action="" method="post" id="createCategoryForm">
<input type="hidden" value="<?= csrf_hash(); ?>" name="<?= csrf_token(); ?>" id="csrf">
<div class="form-group mb-3">
<label for="title" class="form-label">Název kategorie</label>
<input type="text" class="form-control" name="title" id="title" value="">
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" id="createCategoryConfirm">Vytvořit novou kategorii</button>
</form>
</div>
</div>
</div>
</div>
...
<script>
$('#head').on('click', '.create', function() {
$('#createCategory').modal('show');
$('#createCategoryForm').attr('action', '<?= base_url(); ?>/admin/category/create');
$('#createCategoryConfirm').click(function(e) {
e.preventDefault();
var url = $('#createCategoryForm').attr('action');
var csrfElement = $('#csrf');
var csrfName = csrfElement.attr('name');
var csrfHash = csrfElement.attr('value');
var categoryTitle = $('input[name=title]').val();
var data = {
[csrfName]: csrfHash,
'title': categoryTitle
};
console.log(data);
$.ajax({
type: 'ajax',
method: 'POST',
url: url,
data: data,
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
headers: {'X-Requested-With': 'XMLHttpRequest'},
success: function(result) {
console.log(result);
},
error: function(result) {
console.log(result);
},
});
});
});
</script>
In my controller Category.php:
<?php
namespace App\Controllers\Admin;
use App\Controllers\BaseController;
use App\Models\CategoryModel;
use CodeIgniter\I18n\Time;
class Category extends BaseController {
protected $model;
protected $validator;
protected $security;
public function __construct() {
$this->model = new CategoryModel();
$this->validation = \Config\Services::validation();
$this->security = \Config\Services::security();
helper(['form', 'date', 'url']);
}
...
public function create() {
$response = [];
// This part of code returns error
//
// $response['csrf'] = array(
// 'name' => $this->security->get_csrf_token_name(),
// 'hash' => $this->security->get_csrf_hash()
// );
$response['security'] = $this->security;
if ($this->request->isAJAX()) {
$newCategory = [
'title' => $this->request->getVar('title'),
'slug' => url_title($this->request->getVar('title')),
'author' => session()->get('id'),
'created_at' => Time::now('Europe/Prague')->toDateTimeString(),
'updated_at' => Time::now('Europe/Prague')->toDateTimeString(),
'parent' => '0'
];
$this->validation->run($newCategory, 'categoryRules');
if (!empty($this->validation->getErrors())) {
$this->model->save($newCategory);
$response['errors'] = $this->validation->getErrors();
echo json_encode($response);
} else {
$this->model->save($newCategory);
$response['success'] = 'New category was created';
echo json_encode($response);
}
}
}
...
In the browser console, the AJAX response is POST http://localhost/admin/category/create 500 (Internal Server Error) with full response:
code: 500
file: "D:\Web\XAMPP\htdocs\lenka\app\Controllers\Admin\Category.php"
line: 38
message: "Call to undefined method CodeIgniter\Security\Security::get_csrf_token_name()"
title: "Error"
Could anyone please see the issue here? Is there any good solution on how to reuse CSRF tokens in CI4? I tried set config values of CSRF regenerate both to true and false, with no effect.
update this line cod in .ENV
or
app/config/security
CSRF Regenerate = false
In his life, he only encountered an ajax 2 times and here again our paths intertwined with him and he gave me 422 errors. I googled and realized that 422 error is a validation error, but in what specific place the error, I just can not understand.
This is my script
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$( "#form" ).submit(function( e ) {
e.preventDefault();
var message = $('#message').val();
var img = $('#img').val();
var user_id = $('#user_id').val();
$.ajax({
type: "POST",
url: "{{route('profile.store', ['id' => Auth::user()->id])}}",
data: {message:message, img:img, user_id:user_id},
success: function (data) {
$("#textpost").html($(data).find("#textpost").html());
},
});
});
</script>
And my method
public function store(Request $request) {
$validator = $this->validate($request,[
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
if($validator ) {
$post = new Profile();
$post->message = $request->message;
$post->user_id = Auth::user()->id;
if($request->file('img')) {
$path = Storage::putFile('public', $request->file('img'));
$url = Storage::url($path);
$post->img = $url;
}
$post->save();
}
return redirect()->back();
}
And my form
<div class="card-header">
<div class="input-group">
<form action="{{route('profile.store', ['id' => Auth::user()->id])}}" method="post" enctype="multipart/form-data" id="form">
#csrf
<textarea class="form-control" id="message" name="message" cols="100" rows="4" placeholder="О чем думаешь?"></textarea>
<input type="file" id="img" name="img" value="Прикрепить изображение" class="mt-2">
<div class="text-right">
{{-- <input type="submit" id="btn" value="Отправить" class="btn btn-outline-dark btn-sm mt-4">--}}
<button type="submit" id="btn" class="btn btn-outline-dark btn-sm mt-4">Отправить</button>
</div>
</form>
</div>
</div>
$validator = $this->validate($request,[
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
This portion of your code throws a validation errors exception which returns 422.
If you wish to handle validation on your own, try this logic instead:
$validator = validator($request->all(), [
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
if($validator->fails()) {
// return as appropriate
return response()->son($validatior->errors(), 422);
}
// rest of your code
There is a problem with your Ajax call, because you are uploading text and file at the same time you can pass it through FormData. You were also missing
contentType: false,
processData: false,
Here is the updated ajax call:
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$( "#form" ).submit(function( e ) {
e.preventDefault();
var formData = new FormData(this); //set formData to selected instance
var message = $('#message').val();
var img = $('#img').val();
var user_id = $('#user_id').val();
$.ajax({
type: "POST",
url: "{{route('profile.store', ['id' => Auth::user()->id])}}",
data: formData, //pass to our Ajax data to send
success: function (data) {
$("#textpost").html($(data).find("#textpost").html());
},
contentType: false,
processData: false,
});
});
</script>
Setting processData makes it so your FormData is not converted to a string. Setting contentType to false is used for forms that pass files, when false, no header will be added to the request, which is exactly what we want when submitting multipart/form-data.
hi im new to coding and ive been watching this youtube tutorial about a simple server side processing crud and datatable in laravel and im getting this error which i have no idea why im getting it.
I am trying to create an update function to my code but cant cuz of this error. I have a feeling this is because of my update url but im using the same syntax in the tutorial so can you god tier people help me.
Missing required parameters for [Route: Clients.update] [URI:
Clients/{Client}]. (View:
C:\xampp\htdocs\project\resources\views\clients\clients.blade.php)
this is my view code
<div id="formmodal" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Client Form</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>{{-- header --}}
<div class="modal-body">
<span class="result" id="result"></span>
<form method="post" id="client_form" enctype="multipart/form-data">
#csrf
<div class="form-group">
<label for="client_name">Name</label>
<input type="text" class="form-control" name="client_name" id="client_name" placeholder="Enter Name">
</div>
<div class="form-group">
<label for="client_address">Addres</label>
<input type="text" class="form-control" name="client_address" id="client_address" placeholder="Enter Addres">
</div>
<div class="form-group">
<label for="client_date">Birth Date</label>
<input type="date" class="form-control" name="client_bdate" id="client_bdate">
</div>
<div class="modal-footer">
<input type="text" name="action" id="action">
<input type="text" name="hidden_id" id="hidden_id">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" name="savebtn" id="savebtn" value="Add">
</div>
</form>
</div>
</div>
</div>
</div>
$('#client_form').on('submit', function(event){
event.preventDefault();
var url;
if($('#action').val() == 'Add')
{
url = "{{ route('Clients.store') }}";
}else{
url = "{{ route('Clients.update') }}";
}
$.ajax({
url: url,
method: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData: false,
dataType: "json",
success:function(data)
{
var html = '';
if(data.errors)
{
html = '<diV class="alert alert-danger">';
for(var count = 0; count < data.errors.length; count++)
{
html += '<p>' + data.errors[count] + '</p>';
}
html += '</div>';
}
if(data.success)
{
alert("add");
html = '<diV class="alert alert-success">' + data.success + '</div>';
$('#client_form')[0].reset();
$('#table_id').DataTable().ajax.reload();
}
$('#result').html(html);
}
})
});
my controller code
public function update(Request $request)
{
$rules = array(
'client_name' => 'required',
'client_address' => 'required',
'client_bdate' => 'required'
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json(['errors'=>$error->errors()->all()]);
}
$form_data = array(
'client_name' => $request->client_name,
'client_address' => $request->client_address,
'client_bdate' => $request->client_bdate
);
Clients::find($request->hidden_id)->update($form_data);
return response()->json(['success' => 'Data Updated']);
}
Edit...
My route
Route::resource('/Clients', 'clientsCont');
In your controller you are missing second parameter.
So try like this:
public function update(Request $request, Client $client)
{
$rules = array(
'client_name' => 'required',
'client_address' => 'required',
'client_bdate' => 'required'
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json(['errors'=>$error->errors()->all()]);
}
$form_data = array(
'client_name' => $request->client_name,
'client_address' => $request->client_address,
'client_bdate' => $request->client_bdate
);
// You should get your client in variable $client
//Clients::find($request->hidden_id)->update($form_data);
$client->update($form_data);
return response()->json(['success' => 'Data Updated']);
}
Also note if you want to your code look simplier you can validate your request like this:
public function update(Request $request, Client $client)
{
$request->validate([
'client_name' => 'required',
'client_address' => 'required',
'client_bdate' => 'required'
])
$client->update($form_data);
return response()->json(['success' => 'Data Updated']);
}
You can read more here.
Good luck!
In your routes file remove the {} from Clients/{Client} or preferably change it to: Clients/update, when you put {} around some text, you are binding some parameter (actually Eloquent Model), and you should provide it (provide the ID) when you call the route.
Read more Laravel Documentations
Firstly, let's put certain conventions in place.
Change your route definition to
Route::resource('clients', 'ClientsCont');
By convention, controller names should be camel case and start with a capital letter. The route names are usually lower case.
Next, ensure that your controller file is correctly named ClientsCont.php and also the class name should be ClientsCont. Finally, you have to provide a second parameter to your update() method to hold the client object to update.
ClientsCont.php
namespace App\Http\Controllers;
use App\Client;
class ClientsCont extends Controller
{
// class definition
public function update(Request $request, Client $client)
{
$rules = array(
'client_name' => 'required',
'client_address' => 'required',
'client_bdate' => 'required'
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json(['errors'=>$error->errors()->all()]);
}
$form_data = array(
'client_name' => $request->client_name,
'client_address' => $request->client_address,
'client_bdate' => $request->client_bdate
);
$client->update($form_data);
return response()->json(['success' => 'Data Updated']);
}
}
Now, setup your Ajax request properly.
$('#client_form').on('submit', function(event){
var url;
if($('#action').val() == 'Add')
{
url = "{{ route('clients.store') }}";
}else{
url = "{{ route('clients.update') }}";
}
$.ajax({
url: url,
method: "POST",
data: new FormData(this),
cache: false,
dataType: "json",
success:function(data)
{
var html = '';
if(data.errors)
{
html = '<diV class="alert alert-danger">';
for(var count = 0; count < data.errors.length; count++)
{
html += '<p>' + data.errors[count] + '</p>';
}
html += '</div>';
}
if(data.success)
{
alert("add");
html = '<diV class="alert alert-success">' + data.success + '</div>';
$('#client_form')[0].reset();
$('#table_id').DataTable().ajax.reload();
}
$('#result').html(html);
}
})
return false;
});
Usually using return false; is the preferred way for stopping default event action and propagation.
[return false;] Usually seen in jQuery code, it Prevents the browsers default behaviour, Prevents the event from bubbling up the DOM, and immediately Returns from any callback.
See this medium write-up for full details.
Also, from your code, certain of your ajax settings are unnecessary and should be omitted so that their default values are used. These default values are usually sufficient for most forms.
For instance, using jQuery Ajax setting of processData: false disables processing the form data and uses the toString() method of the object to form the request data string.
When you set data to a general object other than a string with processData set to false jQuery doesn't process the object. The object is passed to the Ajax call exactly as it is and used as if it was a String. This by default calls the toString method and sends the result to the sever as the data in the Ajax request.
See this for full description. Be sure you need this setting or you discard it all together.
Another Ajax setting you probably need to discard is contentType: false, except you have a good reason for setting it.
I have this error on my browser console: "PUT http://localhost:8000/post/2 500 (Internal Server Error)"
I use resource Controller and my route- Route::resource('post','PostController');
Here resource controller code for update post:
public function update(Request $request, $id)
{
$post = Post::findOrFail($id);
$post->name = $request->name;
$post->content = $request->content;
$post->save();
return response()->json($post);
}
Here my view code:
<form class="form-horizontal" role="form">
<div class="form-group">
<input type="text" class="none" id="id">
<label class="control-label col-sm-2">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">content:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="content">
</div>
</div>
<div class="form-group">
<input type="submit" value="Edit" onclick="mainCatEdit();">
</div>
</form>
Ajax code:
function mainCatEdit() {
$.ajax({
url: '/maincategory/'+id,
type: 'PUT',
data: {
'_token': $('input[name=_token]').val(),
'id': $('#id').val(),
'name': $('#name').val(),
'content': $('#content').val()
},
success:function(data) {
console.log(data);
}
});
}
by the way i use meta token {{ csrf_token() }} on my file header.
but i get 500 internal server error on localhost.so someone help me.
You forgot to fill the data to your model, do this:
public function update(Request $request, $id)
{
$post = Post::findOrFail($id);
$post->fill([
$post->name = $request->name;
$post->content = $request->content;
]);
$post->save();
return response()->json($post);
}
you are trying to get the value of a token you did not set, lets look at your code again without testing, just try this
set this at the top of your page under the meta tags
<meta name="csrf-token" content="{{ csrf_token() }}">
then your ajax should be
function mainCatEdit() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: '/maincategory/'+id,
type: 'PUT',
data: {
'id': $('#id').val(),
'name': $('#name').val(),
'content': $('#content').val()
},
success:function(data) {
console.log(data);
}
});
}
i hope this helps
when i try to upload my file with ajax, the $file is empty.
I tried with:
$file = Input::file('image');
$file= $request->file('image');
jQuery:
$(document).on('submit', '#update_form', function(e){
e.preventDefault(e);
$.ajax({
type: "POST",
url: '{{route('admin/users/update')}}',
data: $(this).serialize(),
dataType: 'json',
success: function (data) {
$('.error').fadeOut();
success(data);
load_data('{{route('admin/users/edit')}}', '{{ $user->id }}', '{{ $user->part }}');
},
error: function (data) {
$('.success').fadeOut();
errors(data);
}
})
});
Controller:
public function updateUser(Request $request){
//$file = Input::file('image');
$file= $request->file('image');
return \Response::json( $file );
}
Route:
Route::post('admin/users/update', ['as' => 'admin/users/update', 'uses' => 'admin\UserController#updateUser']);
Form:
{!! Form::model($user, ['id' => 'update_form', 'files' => true]) !!}
<div class="col-md-12">
<div class="form-group">
{{ Form::label(trans('User image')) }}
{!! Form::file('image', null,['class' => 'form-control', 'placeholder' => trans('Image')]) !!}
</div>
{{ Form::hidden('id') }}
{{ Form::hidden('part', app('request')->input('part')) }}
{!! Form::submit(trans('Save changes'), ['class' => 'pull-right btn btn-success submit', 'id' => 'submit' ]) !!}
</div>
{!! Form::close() !!}
Repsonse is empty or: {}
response image:
https://gyazo.com/04e431f16237dfada40c864df96ad412
Thank you!
param is your server method parameters
FormData fd =new FormData();
fd.append('param',$('input[type=file]').files[0]);
Laravel 6.x Ah finally nailed it down, for me the way its worked is first i have get the form by it's form id using jQuery then create a new FormData instance passing form through the constructor then if you need anything pass to server side as key value pair use append function.
<form id="form_id" enctype="multipart/form-data">
<div class="from-group">
<label for="title">App name:</label>
<input type="text" name="title" id ="title_id" class="form-control" placeholder="App name"><br>
</div>
<br>
<div class="form-group">
<input type="file" id="image" name="cover_image" autocomplete="off" class="form-control" />
</div>
<button type="button" onclick="WebApp.CategoryController.onClickAppSubmitButton()" class="btn btn-primary">Submit </button>
</form>
var form = $("#form_id")[0];
var formData = new FormData(form);
formData.append('parent_id','0');
$.ajax({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
url: url_app_post,
method: "POST",
contentType: false,
processData: false,
data: formData,
success: function (result) {
var data_array = $.parseJSON(result);
if (data_array.status == "200") {
messageHtml += WebApp.CategoryController.getAlertMessage("alert-success", data_array.message);
} else {
messageHtml += WebApp.CategoryController.getAlertMessage("alert-danger", data_array.message);
}
$(messageView).html(messageHtml);
},
error: function (jqXHR, exception) {
messageHtml += WebApp.CategoryController.getAlertMessage("alert-danger",
WebApp.CategoryController.getjqXHRmessage(jqXHR, exception));
$(messageView).html(messageHtml);
}
})
function storeCategory(Request $request, $type){
try{
$fileNameToStore='no_image.jpg';
if($request->hasFile('cover_image')){
$fileNameWithExt = $request->file('cover_image')->getClientOriginalName();
$fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
$extension = $request->file('cover_image')->getClientOriginalExtension();
$fileNameToStore=$fileName.'_'.time().'.'.$extension;
$path = $request->file('cover_image')->storeAs('public/cover_images', $fileNameToStore);
}
$cat = new Category();
$cat->title = $request->title;
$cat->parent_id = $request->parent_id;
$cat->cover_image=$fileNameToStore;
$cat->user_id=auth()->user()->id;
$cat->save();
return json_encode(array("message"=>"This ".$type." successfully added", "status" => "200"));
}catch(Exception $e){
return json_encode(array("message"=>$type." failed to insert: ".$e->getMessage(), "status" => "403"));
}
}