Using soft delete in laravel 5 issue - php

This is my model:
namespace App\Models\Admin;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Image extends Model
{
use SoftDeletes;
//table
protected $table = 'images';
}
If I add my trait I cannot find any record if I use my model like this:
$imageFile = ImageModel::where('id', 12)->first();
The $imageFile is always null, if I remove my trait is working . Why ???

From what you've said, it is working as intended. When you use the soft-delete trait in Laravel, the model is NOT deleted from the DB. When you pass the model to destroy(), the only thing that happens is that the deleted_at field becomes non-null.
If you look deeper into Laravel's code, when you call
ImageModel::where('id', 12)->first();
the softdelete trait is adding
where null
to the SQL for the deleted_at column. This means that, as you said, if you turn off the trait, $imageFile will not be null (it is working). Because the softdelete never deleted the model from the DB - it just added a non-null value to the DB for that model and is thus visible to a normal laravel query: when you don't use softdeletes, Laravel doesn't care about the deleted_at field so it sees the model. When you turn softdeletes on, it looks for null values only, and because your model was softdeleted (it has a non-null value), it returns $imageFile as null.
As bytewave said, to properly use the softdeletes to NOT return a null value to $imageFile, you would need to add in the softdeleted models to your query like so:
Image::withTrashed()->where('id', 12')->first();
I think you were looking for slightly different functionality (a roll-back), which is a little different from the softdelete trait's intention. The manual is pretty good: 5.4 soft-deletes, but looking deeper into the trait code might help as well.
Take a look at the ->restore() function as well - this might help you get closer to the intended roll-back you were looking for. But, you need the logic up-front first to know which were deleted.

Related

Laravel: why Eloquent Models methods should be invoked as fields

I am fairly new at Laravel, I have stumbled up on a very interesting concept in Laravel Eloquent Models. When I create a model lets say Tweet.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tweet extends Model
{
use HasFactory;
public function user(){
return $this->belongsTo(User::class);
}
}
Then when I want to call the user method normally Tweet::first()->user() it dose not return the required result instead it returns (which I assume it is a closure or a reference):
Illuminate\Database\Eloquent\Relations\BelongsTo
While it works perfectly when I treated it as a filed and invoked it without the parenthesis Tweet::first()->user then I will get the actual data which is the uses's information.
Would you please let me know what is this concept, how it works, and how can we replicate it with our code.
As explained by #lagbox the difference is described in the manual under Relationship methods vs. dynamic properties
For more detail:
Tweet::first()->user() will return a query which can be used to retrieve the user (or be further refined) e.g. you can do Tweet::first()->user()->where('name', 'Bob')->first() to retrieve the user associated with the first tweet if the user's name is Bob. This makes no sense in this context but makes sense in the reverse direction where you can e.g. do User::first()->tweets()->whereDate('created_at', Carbon::today()) to get all of today's tweets.
When you do Tweet::first()->user this tries to get the relationship user if it's loaded or lazy loads it if it's not loaded. For more information on how to optimise this loading you can check Eager loading in the manual

Trouble understanding laravel eloquent models

It's been a some time since I've programmed with Laravel and I'm stumped by the relations I need in order to create a foreign key -link with 2 models.
I have a database where there's a table "company" containing companies, and I also have a table called "projects", which contains projects.
So the Projects- table contains a column called "employercompany" with a foreign key constraint to the company-table.
I'm trying to print out the company's name in a project page in laravel with
{{$project->employercompany->name}}
But keep getting "Trying to get property of non-object"
My model pages look like this:
//Company
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
public function projects()
{
return $this->hasMany('App\Projects', 'employercompany', 'id');
}
}
and
// Projects
namespace App;
use Illuminate\Database\Eloquent\Model;
class Projects extends Model
{
public function employercompany()
{
return $this->belongsTo('App\Company');
}
}
I know this is an easy problem but I just can't wrap my head around it
*****EDIT*****
I found the solution. Thanks Radical for providing some insight.
I ended up changing the employercompany column to company_id and, all the others as such too.
After that I fiddled around what I'm guessing fixed the thing was that I changed my database search query from
DB::table('projects')->get();
into
Project::all();
Don't know if that was the change needed but it sure feels like it was.
When defining a belongsTo relation like you have done, Laravel will try and 'guess' the keys you are using based on the class name. In this case, it will look for a column company_id on your Projects model since your model is called Company.
Like you have done for the projects() method on your Company model, you should tell Laravel that you are using the employercompany column to reference the Company model:
public function employercompany()
{
return $this->belongsTo('App\Company', 'employercompany');
}
For more information, see the relevant documentation here.
In addition, to make things easier, it might be worthwhile to try - if possible - to adhere to what Laravel 'expects' your database columns to be called, so situations like this are resolved automatically.
It should be like
$project = Project::find($id); //id of project
$compnany_name = ($project->employercompany()->get())->name;

Laravel 5.1 - BelongsTo relationship returns null

\App\User
class User
public function status() {
return $this->belongsTo('App\UserStatus', 'user_status_id', 'id');
}
\App\UserStatus
class UserStatus
protected $fillable = ['id'];
public function user() {
return $this->hasMany('App\User', 'user_status_id', 'id');
}
I already have the $user object from a simple User::find() query with some fields, then I try to access the status object by lazy loading it with $user->load('status') method.
I'm following the docs, but it seems useless since $user->status still returns null.
public function foo(User $user) {
$user->load('status');
$user->status // returns null
}
What am I doing wrong?
--------- SOLUTION ---------
Actually, to lazy load any relationship, the foreign key value needs to be stored in the model object.
In my find operation, I wasn't querying the user_status_id field. When I added this field into the query, the $user->status statement started to return the UserStatus model.
I don't think this information is written on the Laravel docs, it may be simple, but it took me some time to figure that out.
Actually, to lazy load any relationship, the foreign key value needs to be stored in the model object.
In my find operation, I wasn't querying the user_status_id field. When I added this field into the query, the $user->status statement started to return the UserStatus model.
I don't think this information is written on the Laravel docs, it may be simple, but it took me some time to figure that out.
in status() relation replace the line with
return $this->belongsTo('\App\UserStatus', 'user_status_id');
in user() relation with this
return $this->hasMany('\App\User', 'user_status_id');
Long story short add a '\' before App and remove third parameter since it is not many-to-many relationship.
Also make sure that you actually use Eloquent so add on top of models
namespace App;
use Illuminate\Database\Eloquent\Model;
class MODELNAME extends Model
and assign a table
protected $table = 'model_table';
I was using Psy Shell to run it. For the first argument in belongsTo(), that could just be Classname::class. I encountered the case that I cannot perform belongsTo(), but if you restart your Psy Shell, it worked. It is weird though.

Laravel Default Where caluse

In Laravel Eloquent model, is it possible to set the Model so it would always use a default Where clause unless specified otherwise.
So for example turn this:
$activeRecords = Records::where('status','active')->get()
Into this:
$activeRecords = Records::all();
But if I would like to get inactive records I would have to tell it todo so
You might want to take a look at the SoftDelete Trait ( http://laravel.com/docs/5.1/eloquent#soft-deleting ) its not exactly the same as with your status flag but is quite a clean way of doing it.
By adding the deleted_at column to your schema and introducing the trait use SoftDeletes; on your model you can then delete records but they won't actually be removed from the database.
If you then did Records::all() you would see all records that haven't been deleted if you want the ones that have been deleted you can access then with the withTrashed method.
As #ChetanAmeta suggested, I would overwrite newQuery method in the model class:
class Records extends Eloquent {
public function newQuery($excludeDeleted = true) {
return parent::newQuery($excludeDeleted = true)
->where('status', 'active');
}
}

Temporary property for Laravel Eloquent model

I have a Laravel Eloquent model User, which has a table with username and email columns. I need to add a property for the model on runtime, something like $user->secure. This property doesn't need to go to database.
When i add this property and hit $user->save() i get an error saying i don't have database column 'secure'. I can unset 'secure' before save but somehow it feels there should be a better way to do so. Any suggestions?
Just add an attribute to your class.
class User extends Eloquent {
public $secure;
// ...
}
Note that it is better to declare it protected and add corresponding accessors and mutators (getSecure and setSecure methods) to your model.
For those who still find this post (like I did), you may need to explicitly declare the property as null to prevent it from being automatically added to the attributes array, and thus being added to INSERT/UPDATE queries:
class User extends Eloquent {
public $secure = null;
// ...
}
Source: http://laravel.io/forum/02-10-2014-setting-transient-properties-on-eloquent-models-without-saving-to-database
If you intend to make use of that add-on property, then $append will blow your mind.
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/

Categories