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');
}
}
Related
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.
\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.
I want to add some joins onto my Auth::user() query. How do I do this without creating a brand new query? I just want to be able to make the default call of Auth::user() different than:
SELECT * FROM `users` WHERE `id` = ?
to
SELECT * FROM users INNER JOIN user_icons ON user_icons.ID = users.iconid WHERE `id` = ?
I'm using the default model User class.
Laravel provides a way for you to extend the Auth functionality. First, you need to create a class that implements the Illuminate\Auth\UserProviderInterface. Once you have your class, you call Auth::extend() to configure Auth with your new class.
For your case, the easiest thing for you to do would be to create a class that extends Illuminate\Auth\EloquentUserProvider. You'll want to update the retrieveBy* methods to add in your custom joins. For example:
class MyEloquentUserProvider extends Illuminate\Auth\EloquentUserProvider {
public function retrieveById($identifier) {
return $this->createModel()->newQuery()->join(/*join params here*/)->find($identifier);
}
public function retrieveByToken($identifier, $token) {
// your code with join added here
}
public function retrieveByCredentials(array $credentials)
// your code with join added here
}
}
Once your class is fleshed out, you need to tell Auth to use it:
Auth::extend('eloquent', function($app) {
return new MyEloquentUserProvider($app['hash'], $app['config']['auth.model']);
});
The first parameter to the Auth::extend method is the name of the auth driver being used as defined in app/config/auth.php. If you want, you can create a new driver (e.g. 'myeloquent'), but you'd need to update your Auth::extend statement and your app/config/auth.php driver.
Once all this is done, Auth::user() will end up calling your MyEloquentUserProvider::retrieveById method.
Fair warning: I have not actually done this myself, and none of this is personally tested. You will probably want to check out the documentation (L4.1 docs, L4.2 docs) and look at the Laravel code.
Other notes:
People have already chimed in that this is probably not what you want to do. However, the this information may be helpful to you and others looking to extend Auth for some other reason.
Considering your inner join, if a user does not have an associated user_icons record, Auth::user() will not return a record anymore, and the user probably won't be able to log in at all.
If you have 1:n relation:
Add a "icons" table to you database with a foreign key "user_id".
Add a "Icon" Model to your models.
<?php
class Icon extends Eloquent{
...
}
?>
In Model Class "User" add a function:
public function icons() {
return $this->hasMany('Icon');
}
Now you can do this:
$userIcons = Auth::user()->icons();
I have News model, when i query news, i want it brings news where status = 1 as default.
News::all(); // select * from news where status = 1
News::where('anotherColumn',2)->get(); // select * from news where status = 1 and where category = 2
Is this possible? What i want is so similar to soft delete feature (it gets where deleted_at is not null and if all data is wanted withTrashed function can be used).
I looked docs but i couldn't find anything helpful. Also, i tried to handle it in construct at News model but it didn't worked either.
Thanks.
I normally override newQuery() for this. newQuery() is the method that Eloquent use to construct a new query.
class News extends Eloquent {
public function newQuery($excludeDeleted = true) {
return parent::newQuery($excludeDeleted)
->where(status, '=', 1);
}
}
Now your News::all() will only output your news with status = 1.
It's been already mentioned but here is a quick example using global scope which might be the best current solution since you wont have to override Eloquent methods and would result into the same behavior but with more control of your model.
Just add this to your model :
protected static function boot()
{
parent::boot();
static::addGlobalScope('exclude_deleted', function (Builder $builder) {
$builder->whereNull('deleted_at');
});
}
You can also create a child Scope class and reuse it for multiple Models.
For more information, Laravel doc explained pretty much everything about it:
https://laravel.com/docs/5.6/eloquent#global-scopes
I think the closes you'll get, without actually going in to change some core files...
is Query Scope...
Scopes allow you to easily re-use query logic in your models. To define a scope, simply prefix a model method with scope:
class News extends Eloquent {
public function scopeStatus($query)
{
return $query->where('status', '=', 1);
}
}
Utilizing that scope
$news = News::status()->get();
$news2 = News::status()->where('anotherColumn',2)->get();
Its not quite what you wanted...but its definitely a little shorter than typing
News::where('status','=',1)->get();
over and over
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/