What triggers the "Trying to get property of non-object" error - php

Since I started with my first Laravel project I've been having the error
Trying to get property 'column_name' of non-object nonstop, and most of the time I've been able to fix it one way or another, but the problem is, I have no idea of why I get the error, or how can I prevent it. For example,
// In my controller I have this domPDF function...
public function pdfgen(Request $request, $id) {
$data = Table::find($id);
View()->share('data', $data);
if ($request -> has('download')) {
$pdf = PDF::loadView('pdf/pdfgen');
return $pdf ->download('pdfgen.pdf');
}
return view('pdf/pdfgen');
}
// In my blade file I have a table calling this column...
<td>{{ $data->column }}</td>
// and this link making the request in the pdfgen function...
<a class="btn btn-primary" href="{{ route('pdfgen', ['download'=>'pdf']) }}">Download PDF</a>
// And in my routes of web.php...
Route::get('/pdfgen/{id}', array('as' => 'pdfgen', 'uses' => 'PDFController#pdfgen'));
and whenever I press that download link, I get a Whoops page with the trying to get property 'column' of non-object (View: /usr/src/workapp/resources/views/pdf/pdfgen.blade.php). Why am I getting this error and not the open/save dialog?
EDIT: Forgot to add, before trying to get specific data with $id, I called the whole table ($data = Table::all();) and used a #foreach in the blade view to print it in the table
EDIT 2: Adding the model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Table extends Model
{
protected $table = 'table';
protected $primaryKey = 'id';
public $incrementing = false;
protected $fillable = [
// all columns are strings, even id
'id',
'column',
'column2',
'column3',
];
public function table2()
{
return $this->hasMany('App\Table2');
}
}

When you do find($id) and the record is not present, it returns null. So if you try to access any property ->column, it will throw error.
You can either do findOrFail($id) or have condition if (is_null($data)) or on frontend have $data->column ?? 'defaultvalue
'
Now, the second situation where your model is present but you still get error, do :
$data = Table::find($id);
dd(array_keys($data->toArray()));
You should see the column you are trying to access if it is present.
Lastly, if it is not present in above step but is there in the table, then check for protected $hidden = [] setting of your model which essentially hides certain columns.

This happend because your $data might be null and your record with given $id might not exists in your database.
Try to change your code like below:
Table::findOrFail($id);
From now on if your table with given id doesn't exist, it'll automatically return 404 page.

Related

Laravel 6 : Duplicate database entry on polymorphisme relation save

I try to save a morph relationship in my database, but when i try to save it I Have tow entry in every table use for the relation.
here is my client class
class Client extends Model
{
protected $guarded = [];
public function clientelle(){
return $this->morphTo();
}
}
my particulier class
class Particulier extends Model
{
protected $guarded = [];
public function client(){
return $this->morphOne(Client::class,'clientelle');
}
}
So when I try to save like that :
$particulier = new Particulier();
$particulier->nom = $request->nom;
$particulier->prenom = $request->prenom;
$particulier->save();
$particulier->client()->create(['telephone'=>$request->telephone,'adresse'=>$request->adresse,'email'=>$request->email]);
My database save two same recorde. Here is my problem.
So I have try diffrente thing to avoid it but I have error every time
delete $particulier->save(); but SQL error id don't exist
replace create([...]) by save([...]) or sync([...]) but don't work
Thank you in advance
So I have finally find a worst solution...
In your controller add int var and init it to 0 like that :
Private $checkDouble=0;
In place where you want save your relation create if block and put in all of your model save like that :
if($this->checkDouble==0) {
$this->checkDouble = $this->checkDouble + 1; //Increase your var value
$particulier = Particulier::create(['nom' => $request->nom, 'prenom' => $request->prenom]);
$particulier->client()->create(['telephone' => $request->telephone, 'adresse' => $request->adresse, 'email' => $request->email]);
}
And no more duplicate data
I know is really worst solution but I don't see any best solution ^^

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.

one to one relationship in laravel (Error)

I am new in Laravel, when I practice I get an error.
at HandleExceptions->handleError('8', 'Trying to get property of non-object', 'C:\xampp\htdocs\cms\app\Http\routes.php', '144', array('id' => '1')) in routes.php line 144
my routes.php file
Route::get('/user/{id}/post',function ($id){
return User::find($id)->post->title;
});
in my User.php file
public function post(){
return $this->hasOne('App\Post');
}
I have two tables 1-posts 2-users
and I have also Post class
I also google and search different sites but can't understand.
Please me,how to rid this Error.
your posts are one user .
this renlship is "one-to-many" relationship .
you must for this reason using this method in modal user :
public function posts()
{
return $this->hasMany('App\Post');
}
one to many is array from posts .
for show resualt you must using foreach :
$comments = App\Post::find(1)->comments;
foreach ($comments as $comment) {
$comment->title ;
}
and reading this links : https://laravel.com/docs/5.2/eloquent-relationships#one-to-many
1:are you shure the relation is one to one;
2:if you shure add primary and foreign key and add this function in Post model.
public function user(){
return $this->hasOne('App\User','id','user_id');
}

Laravel policy for editing

So I have created a policy and registered it in the AuthServicePRovider, but it always returns false. It is my first time working with policies so I am sure I am doing it wrong, but following a few examples, nothing has worked for me.
I am logged in with user that has an id of 1. I try to edit a label that has a user_id of 1, returns false, and also when trying to edit a label that has a user_id of 2. This last one works as expected, but f the user_id and label->user_id match, I should ave a form displayed. Instead, I get this each time:
This action is unauthorized.
Any ideas?
AuthServiceProvider: (Tried both but both don't work):
protected $policies = [
'App\Label' => 'App\Policies\LabelPolicy'
];
And this one also did not do the trick:
protected $policies = [
Label::class => LabelPolicy::class
];
LabelsController#edit:
public function edit(Label $label)
{
// $this->authorize('edit', $label); // This also returns false
if (auth()->user()->cannot('edit', $label)) {
dd('NO'); // This is always shown
}
}
LabelPolicy:
public function edit(Label $label)
{
dd('test'); // This is never shown anywhere
return auth()->user()->id === $label->user_id;
}
The policies expects actually two inputs, the first input is always the User class, the second input is the Model and defaults to the Model class. So in your case:
LabelPolicy
public function edit(User $user, Label $label)
{
return $user->id === $label->user_id;
}
LabelsController#edit:
public function edit(Label $label)
{
$this->authorize($label);
}
if your $this->authorize inside Controllers always returns false, then double check if your model and model policy namespace was imported in AuthServiceProvider and also your model has been imported into your controller.

Can you populate an Eloquent model without creating an entry in the database using Laravel 5

When I'm adding or editing an entry to my database table websites I load the instance of the website to be modified (or a blank one for creating a website). This works great, this is my controller:
<?php namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Request;
use App\Models\User;
use App\Models\Status;
use App\Models\Website;
class WebsitesController extends Controller {
/**
* Show / Process the create website form to the user.
*
* #return Response
*/
public function create()
{
$statuses = Status::all();
$users = User::all();
$website = Website::find(0);
return view('admin/websites/create', [
'statuses' => $statuses,
'users' => $users,
'website' => $website
]);
}
public function update($id)
{
$statuses = Status::all();
$users = User::all();
$website = Website::findOrFail($id);
return view('admin/websites/update', [
'statuses' => $statuses,
'users' => $users,
'website' => $website
]);
}
}
The problem is when I submit the form and there is an error. The user is returned to the page and the errors displayed. I also pass the users input back so I can repopulate the form with what they entered. But how can I replace the values in website with the values from input if it's present without actually saving to the database? I've been playing around with this all day and not found a working solution.
My create method is this:
public function postCreate(Request $request)
{
$v = Validator::make($request->all(), Website::rules());
if ($v->fails())
{
return redirect()->back()->withInput()->withErrors($v);
}
$website = Website::create($request->all());
return redirect()->action('Admin\HomeController#index')->with('messages', [['text' => 'Website created', 'class' => 'alert-success']]);
}
I'm passing the input back to the original form, but the form populates its values from the Website Eloquent model. **How can I get the input from $request->all() into $website?
I've tried using fill(), but I just get Call to a member function fill() on null when using it in the create function.
The create method attempts to insert a record to the database and returns an instance of the model if it is successful. If you use create() with invalid values, the insert will fail. I think this is why there is a null instead of an instance of the model, which causes your error:
Call to a member function fill() on null
Instead of using create() You could create the website model without the database insert using
$website = new Website;
$website->fill($request->all());
before you run the validation. If the validation passes, then you can insert to your database with $website->save();, otherwise, it will not try to save, but the model should be available for you to use in your form.

Categories