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

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.

Related

Cannot call to a public function of Model (Laravel)

I just started learning Laravel, I'm newbie. I've got a problem, I'm watching Laravel Course for beginners and learning, was doing exactly the same as in he tutorial, but still ended up with a problem. I hope to find a solution soon. I'll explain it a little bit.
The project is kind of a clone of Instagram. Users can post images to page.
I have this function in User model
User.php
public function posts()
{
return $this->hasMany(Post::class);
}
And I'm trying to access it from my PostsController
PostsController.php
class PostsController extends Controller
{
public function create()
{
return view('posts.create');
}
public function store()
{
$user = auth()->user();
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
auth()->user()->posts()->create($data);
\App\Models\Post::create($data);
dd(request()->all());
}
}
I'm doing exactly as in tutorial, but for some reason this line is failing at posts() call.
auth()->user()->posts()->create($data);
I'm getting that it's undefined method. But it is indeed defined in User.php
EDIT:
Exact error I'm getting is:
Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: posts.user_id (SQL: insert into "posts" ("caption", "image", "updated_at", "created_at") values (Caption, C:\xampp\tmp\php2E32.tmp, 2021-05-19 12:16:08, 2021-05-19 12:16:08))
And foreign key is user_id.
Actually I just checked my posts table and it seems it is stored in database, so it's working, but how to get rid of this error then?
this is a silly mistake of you..you are adding same post twice. once with relationship association and again from post model.
auth()->user()->posts()->create($data);
\App\Models\Post::create($data); //this is causing the issue here.
with relationship association auth()->user()->posts()->create($data), post is inserted to the database. as the foreign key user_id is coming from relationship. but in the next line \App\Models\Post::create($data), your $data array is missing user_id and thus the NOT NULL constraint failed error occurs. you can't insert a row with user_id being null. and this line is actually adding duplicate data. remove this line. use either one of the method.
with relationship association
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
auth()->user()->posts()->create($data);
or using model directly
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
$data['user_id'] = auth()->user()->id; //added user_id in the validated data array
\App\Models\Post::create($data);
and vs code always don't know all of your functions. depending on vs code to find a problem is not the best way.
Note:: you need to use Post Model and you can directly create data Using Post::create() method.
//Import Data
use Illuminate\Http\Request;
use App\Modes\Post;
class PostsController extends Controller
{
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
//Check Validation
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
//Get Login User Data in $user variable
$user = auth()->user();
//Store user id into $data variable which we can pass into $data Variable.
$data[‘user_id’] = $user->id;
//Create Data Using create() method.
$post = Post::create($data);
//Final Save Your Data
if( $post->save() ) {
dd(“data save successfully”);
}else{
dd(“something went wrong”);
}
}
}

Laravel 5.5 Method save does not exist when updating entries with modified primary key

I am working with laravel 5.5 to update entries. The problem is after changing the primary key 'id', which is elequoent default pk to 'project_id'. adding an item works fine but updating an item is not working properly. Here is the error I am getting.
Method save does not exist.
Here is my Model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
protected $primaryKey = 'project_id';
public function user()
{
return $this->belongsTo(User::class);
}
public function tasks()
{
return $this->hasMany(Task::class);
}
}
Here is my controller function.
public function editProject($id){
$project = Project::where('project_id', $id)->firstOrFail();
$data = ["project_info" => $project];
return view('projects.edit')->with($data);
}
public function updateProject(Request $request){
$data = $request->all();
$validator = Validator::make($data, [
'project_title' => 'required',
'project_description' => 'required',
'project_start_date' => 'required',
'project_end_date' => 'required',
'project_status' => 'required',
]);
$response = [];
if ($validator->fails()){
$response["errors"] = [$validator->messages()->first()];
$response["success"] = false;
return json_encode($response);
}
else{
$project = Project::where("project_id", $request->input('project_id'))->get();
$project->project_title = $request->project_title;
$project->user_id = Session::get('user_id');
$project->project_description = $request->project_description;
$project->project_start_date = $request->project_start_date;
$project->project_end_date = $request->project_end_date;
$project->project_status = $request->project_status;
$project->save();
return redirect('/listProjects');
}
}
Using get() returns a collection. Despite the fact you are passing in a 'unique' ID, the project_id, it will still return a collection - the collection will simply have one element in it.
Subsequently, your code will not work as you have experienced, or at least not without a few changes to make $project reference the first element in the collection.
It's a quick fix though, just change this:
$project = Project::where("project_id", $request->input('project_id'))->get();
to this:
$project = Project::where("project_id", $request->input('project_id'))->first();
By using first(), eloquent will return the first element that matches the query and actually return the element (as opposed to a collection with one element) and so you can directly edit and save it.
Here is the solution I found.
$project_id = $request->input('project_id');
$project = Project::find($project_id);
$project->save();
You can find it by id using
Project::find($id);
Or get the first element like James said:
$project = Project::where("project_id", $request->input('project_id'))->first();

User doesn't update Laravel

Update Method:
public function update(UserUpdateRequest $request, Users $uzytkownik)
{
$this->authorize('update', $uzytkownik);
if ( $uzytkownik->update([
'birth' => $request->birth,
'sex' => $request->sex,
'about' => $request->about,
]) )
{
return 1;
}
return 0;
}
On update here in page 1 appears. Like it did the thing.
But in db nothing has changed.
$uzytkownik is proper user, and
This is the dd($uzytkownik);
And below dd($request->birth.'---'.$request->sex.'---'.$request->about); which shows proper inputs
Why it doesn't work properly?
As per the documentation
Mass Assignment
You may also use the create method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a fillable or guarded attribute on the model, as all Eloquent models protect against mass-assignment by default.
You need to make sure $fillable or $guarded is correctly set otherwise changes may not be persistant.
You can do what you want like this too:
public function update(UserUpdateRequest $request, Users $uzytkownik)
{
$this->authorize('update', $uzytkownik);
$uzytkownik->birth = $request->birth;
$uzytkownik->sex = $request->sex;
$uzytkownik->about = $request->about;
if ( $uzytkownik->save() )
{
return 1;
}
return 0;
}

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

Laravel 4 database actions - controller or model

just started using Laravel but want to make sure I am using it correctly.
Most of my work is CMS based so read / write / update etc to a database.
An example of what I have done so far is an insertion into the DB:
On the view I have a form with a URL of 'addNewUser'.
In my routes I then do:
Route::post('addnewuser', array('uses' => 'UserController#addNewUser'));
My user controller 'addNewUser' method is (simplified):
public function addNewUser() {
$data = Input::all();
$rules = array(
'username' => 'required|alpha_dash|max:16|unique:users,username',
);
$validator = Validator::make($data, $rules, $messages);
if ($validator->fails())
{
Input::flash();
$errors = $validator->messages();
return Redirect::to('/register')->withErrors($validator)->withInput();
}
$user = new User;
$user->save();
return Redirect::to('/login')->with('successLogin', '1');
}
Is this correct? I have read somewhere that all DB interaction should be in the model?
Likewise when reading from the DB to display a foreach for example, I do the following directly in the view:
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
if ($builds) {
foreach ($builds as $build)
{
$safeURLSlug = stringHelpers::safeURLSlug($build->blogtitle);
echo "
// stuff
";
}
} else {
// no stuff
}
Should I be doing these sort of queries and showing of data directly in the view? or in a model / controller function etc?
Want to check im doing things 100% correct / the standard way of doing things before I get too involved.
I can see a few things that I personally would have done differently.
For example I usually put $rules as a class variable so it can be used in different functions related to your Users.
Have you tested your code yet? Any errors?
In your addNewUser function does it save any data? I know you have "simplified" above the code snippet but there should be $user->username = $data['username']; etc. in between creating your $user variable and running $user->save();, so if you excluded this on purpose then I don't see anything else with your model.
In your view code, $builds = DB::table('blogs')->orderBy('id', 'desc')->get(); should be done in your controller and passed to your view like so return View::make('example', array('builds' => $builds))
I'd also change
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
to
$builds = Blog::orderby('id','desc')->get(); if you have a Blog model, otherwise your code is fine.
You could move:
$rules = array(
'username' => 'required|alpha_dash|max:16|unique:users,username',
);
to User model as static variable, and instead of:
$validator = Validator::make($data, $rules, $messages);
you could use:
$validator = Validator::make($data, User::$rules, $messages);
But definitely you shouldn't get data from database in your View, this code should be in controller, for example:
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
return View::make('someview')->with('builds', $builds);
of course if you have Blog model, you should use here:
$builds = Blog::orderBy('id', 'desc')->get();
return View::make('someview')->with('builds', $builds);
It's also unclear what the following code does:
$safeURLSlug = stringHelpers::safeURLSlug($build->blogtitle);
but probably you could move it to your Blog model and use accessor to make the change:
public function getSafeSlugAttribute($value) {
return stringHelpers::safeURLSlug($this->blogtitle);
}
and now your view could look like this:
#foreach ($builds as $build)
{{{ $build->title }}} {{{ $build->safeSlug }}}
#endforeach
I suggest you take a look on Laravel Generators.
https://github.com/JeffreyWay/Laravel-4-Generators
Install and then run:
php artisan generate:scaffold customer
Laravel line command generator create a basic CRUD for you with controller, model, views and database migrations. That's good to safe time and keep your project with some default organization.

Categories