Laravel "Serialization of 'Closure' is not allowed" - php

When I go to store a dataset in Laravel, I sometimes get this error and haven't found a solution to it.
Serialization of 'Closure' is not allowed
Open: ./vendor/laravel/framework/src/Illuminate/Session/Store.php
*/
public function save()
{
$this->addBagDataToSession();
$this->ageFlashData();
$this->handler->write($this->getId(), serialize($this->attributes));
$this->started = false;
Here is the function being called when the error occurs:
public function store()
{
$data = Input::all();
$validator = array('first_name' =>'required', 'last_name' => 'required', 'email' => 'email|required_without:phone', 'phone' => 'numeric|size:10|required_without:email', 'address' => 'required');
$validate = Validator::make($data, $validator);
if($validate->fails()){
return Redirect::back()->with('message', $validate);
} else {
$customer = new Customer;
foreach (Input::all() as $field => $value) {
if($field == '_token') continue;
$customer->$field = $value;
}
$customer->save();
return View::make('admin/customers/show')->withcustomer($customer);
}
}
What is causing this serialization error?

Just replace following line:
return Redirect::back()->with('message', $validate);
with this:
return Redirect::back()->withErrors($validate);
Also, you may use something like this (To repopulate the form with old values):
return Redirect::back()->withErrors($validate)->withInput();
In the view you can use $errors variable to get the error messages, so if you use $errors->all() then you'll get an array of error messages and to get a specific error you may try something like this:
{{ $errors->first('email') }} // Print (echo) the first error message for email field
Also, in the following line:
return View::make('admin/customers/show')->withcustomer($customer);
You need to change the dynamic method to withCustomer not withcustomer, so you'll be able to access $customer variable in your view.

return Redirect::back()->with('message', $validate);
You are telling Laravel to serialize the entire validator object into session. To redirect with errors, use the withErrors method:
return Redirect::back()->withErrors($validate);
This will take the error messages out of the validator and flash those to session prior to redirecting. The way you're doing it now you're trying to store the entire class in Session which is causing your error.
Another issue I see is that I don't think there's a withcustomer method on the View class:
return View::make('admin/customers/show')->withcustomer($customer);
Try changing that to either just with:
return View::make('admin/customers/show')->with('customer', $customer);
or make sure to capitalize the Customer portion:
return View::make('admin/customers/show')->withCustomer($customer);
See also this question.

Related

LARAVEL - Form validation return back to view instead of returning JSON?

I don't remember this is always been so freakin' hard to do in Laravel, but how to return back to form page blade.php instead of displaying the errors as JSON object on the browser?
Controller
public function create()
{
return view('view.to.form');
}
public function store(CreateModelRequest $request)
{
Model::create($request->validated());
}
// CreateModelRequest
protected function failedValidation(Validator $validator)
{
return back()->withErrors($validator);
}
I've tried countless other "solutions" as well, but no matter what,
the failed form request return raw JSON to the browser:
{
message: 'The given data was invalid',
errors: {
first_name: ['The first name field is required.'],
last_name: ['The last name field is required.'],
email: ['The email field is required.'],
},
}
}
Ok, I found one way to return back to the form but damn this is awful:
// Controller's store method
$validator = Validator::make($request->all(), [
// rules
]);
if ($validator->fails()) {
return back()->withErrors($validator->errors());
}
I'd like to extract that code into Request class but apparently we can't return a view and therefore we can't use them outside of API endpoints. Please, correct me if I'm wrong.

Laravel Eloquent $model->save() not saving but no error

When updating my Post model, I run:
$post->title = request('title');
$post->body = request('body');
$post->save();
This does not update my post. But it should according to the Laravel docs on updating Eloquent models. Why is my model not being updated?
I get no errors.
The post does not get updated in the db.
Besides not being updated in the db, nothing else seems odd. No errors. Behavior as normal.
Result of running this test to see if save succeeded was true.
This Laravel thread was no help
Post model:
class Post extends Model
{
protected $fillable = [
'type',
'title',
'body',
'user_id',
];
....
}
Post controller:
public function store($id)
{
$post = Post::findOrFail($id);
// Request validation
if ($post->type == 1) {
// Post type has title
$this->validate(request(), [
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
$post->title = request('title');
$post->body = request('body');
} else {
$this->validate(request(), [
'body' => 'required|min:19',
]);
$post->body = request('body');
}
$post->save();
return redirect('/');
}
Bonus info
Running dd($post->save()) returns true.
Running
$post->save();
$fetchedPost = Post::find($post->id);
dd($fetchedPost);
shows me that $fetchedPost is the same post as before without the updated data.
Check your database table if the 'id' column is in uppercase 'ID'. Changing it to lower case allowed my save() method to work.
I had the same and turned out to be because I was filtering the output columns without the primary key.
$rows = MyModel::where('...')->select('col2', 'col3')->get();
foreach($rows as $row){
$rows->viewed = 1;
$rows->save();
}
Fixed with
$rows = MyModel::where('...')->select('primary_key', 'col2', 'col3')->get();
Makes perfect sense on review, without the primary key available the update command will be on Null.
I had the same problem and changing the way I fetch the model solved it!
Was not saving even though everything was supposedly working just as you have mentioned:
$user = User::find($id)->first();
This is working:
$user = User::find($id);
You have to make sure that the instance that you are calling save() on has the attribute id
Since Laravel 5.5 laravel have change some validation mechanism I guess you need to try this way.
public function store(Request $request, $id)
{
$post = Post::findOrFail($id);
$validatedData = [];
// Request validation
if ($post->type == 1) {
// Post type has title
$validatedData = $request->validate([
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
} else {
$validatedData = $request->validate([
'body' => 'required|min:19',
]);
}
$post->update($validatedData);
return redirect('/');
}
Running dd() inside a DB::transaction will cause a rollback, and the data in database will not change.
The reason being, that transaction will only save the changes to the database at the very end. Ergo, the act of running "dump and die" will naturally cause the script to cease and no therefore no database changes.
Check your table if primary key is not id ("column name should be in small letters only") if you have set column name with different key then put code in your Model like this
protected $primaryKey = 'Id';
So this might be one of the possible solution in your case also if your column name contains capital letters.
Yes this worked for me fine,
You should have column names in small letter,
If you don't have then mention it in the model file, mainly for primaryKey by which your model will try to access database.
For use save () method to update or delete if the database has a primary key other than "id". need to declare the attribute primaryKey = "" in the model, it will work
Try this
public function store($id,Request $request)
{
$post = Post::findOrFail($id);
// Request validation
if ($post->type == 1) {
// Post type has title
$request->validate([
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
$post->update([
'title' => request('title');
'body' => request('body');
]);
} else {
$request->validate([
'body' => 'required|min:19',
]);
$post->update([
'body' => request('body');
]);
}
return redirect('/');
}
In my experience, if you select an Eloquent model from the db and the primary_key column is not part of the fetched columns, your $model->save() will return true but nothing is persisted to the database.
So, instead of doing \App\Users::where(...)->first(['email']), rather do \App\Users::where(...)->first(['id','email']), where id is the primary_key defined on the target table.
If the (sometimes micro-optimization) achieved by retrieving only a few columns is not really of importance to you, you can just fetch all columns by doing \App\Users::where(...)->first(), in which case you do not need to bother about the name of the primary_key column since all the columns will be fetched.
If you using transactions.
Do not forget call DB::commit();
It must look like this:
try{
DB::beginTransaction();
// Model changes
$model->save();
DB::commit();
}catch (\PDOException $e) {
DB::rollBack();
}
I have the same issue although there are try / catch block in controller#action() but there were no response, it just stops at $model->save(); there is no log entry either in apache error.log or laravel.log. I have just wrapped the save() with try / cactch as follows, that helped me to figure out the issue
try{
$model->save();
}
catch (\PDOException $e) {
echo $e->getMessage();
}
I have been experiencing the same issue and found a workaround. I found that I was unable to save() my model within a function called {{ generateUrl() }} on my home.blade.php template. What worked was moving the save() call to the controller that returns the home.blade.php template. (IE, save()ing before the view is returned, then only performing read operations within {{ generateUrl() }}.)
I was (and am) generating a state to put in a URL on page load:
<!--views/home.blade.php-->
Add Character
Below is what did not work.
// Providers/EveAuth.php
function generateUrl()
{
$authedUser = auth()->user();
if (!$authedUser) {
return "#";
}
$user = User::find($authedUser->id);
$user->state = str_random(16);
$user->save();
$baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';
return $baseUrl . $user->state;
}
This was able to find() the User from the database, but it was unable to save() it back. No errors were produced. The function appeared to work properly... until I tried to read the User's state later, and found that it did not match the state in the URL.
Here is what did work.
Instead of trying to save() my User as the page was being assembled, I generated the state, save()d it, then rendered the page:
// routes/web.php
Route::get('/', 'HomeController#index');
Landing at the root directory sends you to the index() function of HomeController.php:
// Controllers/HomeController.php
public function index()
{
$authedUser = auth()->user();
if ($authedUser) {
$user = User::find($authedUser->id);
$user->state = str_random(16);
$user->save();
}
return view('home');
}
Then, when generating the URL, I did not have to save() the User, only read from it:
// Providers/EveAuth.php
function generateUrl()
{
$authedUser = auth()->user();
$user = User::find($authedUser->id);
$baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';
return $baseUrl . $user->state;
}
This worked! The only difference (as far as I see) is that I'm save()ing the model before page assembly begins, as opposed to during page assembly.

how to prevent getting message:Trying to get property of non-object when id is not found

now I have this controller which gets id from db and than list som information from db. but when I go to database and delete the data manually, the controller can't find the id anymore and it returns :Trying to get property of non-object
with planti of privet information. my conde is something like below:
public function saveChanges(Request $request){
$id=$request->input('id');
$this->validate($request, [
'title' => 'required',
'body' => 'required|min:2'
]);
$post=Post::where('id',$id)->first();
if($post->id == $id){
$post->title = $request['title'];
$post->postBody = $request['body'];
if ($post->update())
{
return response()->json([
'type'=>1,
'newtitle'=>$post->title,
'newbody'=>$post->postBody
]);
}
else{
return response()->json(['type'=>0]);
}
}
else {
echo"404";
}
}
the thing I don't like here is going for the id directly like this:
$post=Post::where('id',$id)->first();
I don't have much idea about laravel so do you think I may prevent this situation by any chance?
As suggested, check first if a post was found before trying to access a property:
$post = Post::where('id',$id)->first();
if ($post instanceof Post && $post->id == $id) {
// ...
}
For reference, see:
http://php.net/manual/en/language.operators.type.php
First you should check if object Post exists, for example by function is_object()
http://php.net/is_object

Lumen provide a code for validation errors

Currently in lumen when you use the $this->validate($request, $rules) function inside of a controller it will throw a ValidationException with error for your validation rules(if any fail of course).
However, I need to have a code for every validation rule. We can set custom messages for rules, but I need to add a unique code.
I know there's a "formatErrorsUsing" function, where you can pass a formatter. But the data returned by the passed argument to it, has already dropped the names of the rules that failed, and replaced them with their messages. I of course don't want to string check the message to determine the code that should go there.
I considered setting the message of all rules to be "CODE|This is the message" and parsing out the code, but this feels like a very hacked solution. There has to be a cleaner way right?
I've solved this for now with the following solution:
private function ruleToCode($rule) {
$map = [
'Required' => 1001,
];
if(isset($map[$rule])) {
return $map[$rule];
}
return $rule;
}
public function formatValidationErrors(Validator $validator) {
$errors = [];
foreach($validator->failed() as $field => $failed) {
foreach($failed as $rule => $params) {
$errors[] = [
'code' => $this->ruleToCode($rule),
'field' => $field,
];
}
}
return $errors;
}

Laravel 5 How to perform validation in Controller to check for specific data in data collection

I want to perform custom validation in laravel 5, here is the concept. I have a category controller in which i want to delete a particular category. If category contains any other sub category i want to show validation error in laravel 5. For this concept i have create the program, but the program does not perform required validation. I am getting varies error like valiable not found or validation not performing or Undefined variable: struct. Below is the code that i am using to do that.
CategroyController destroy function, to delete record.
public function destroy(Request $request)
{
if(\Request::ajax()){
$validator = \Validator::make($request->all(), array());
$data = Configuration::findTreeParent($request->input('id'), 'Category');
$selected = $request->input('id');
foreach($data as $struct) {
$validator->after(function($validator) {
if ($selected == $struct->id) {
$validator->errors()->add('field', $request->input('configname').' cannot be assigned to its child category.');
}
});
}
if ($validator->fails()) {
return $validator->errors()->all();
} else{
return \Response::json(['response' => 200,'msg' => $validator->fails()]);
}
}
}
Please look into and help me out from this problem.
When using closure you need to pass a variable to its scope before using it. In your case $struct is not available in the scope of the closure you are passing to $validator->after().
So basically you have to pass the $struct to the closure.
// you can remove this line. $selected = $request->input('id');
$validator->after(function($validator) use ($struct) {
if ($request->input('id') == $struct->id) {
$validator->errors()->add('field', $request->input('configname').' cannot be assigned to its child category.');
}
});
To return the JSON response for the validation errors, update the following ode.
if ($validator->fails()) {
return \Response::json($validator->errors()->all(), 422);
}
Read about closure here.

Categories