Laravel + Eloquent - Passing through custom function first - laravel

What I want to do is quite simple I think. In my controller I have the code:
$list = SiteCategory::where('type','=','A')->get();
Which returns a standard eloquent collection object. However, sometimes when I retrieve categories, I want them to be ordered in a specific way first. So can I have some function in my model like:
Class SiteCategory extends Eloquent {
public function mySpecialFunction(){
// retrieve all categories, manipulate them in some way and return.
}
}
How do I then call this function? I don't understand, and the tutorials and questions I've read do not help. For example, in this question on SO, he seems to imply he can call his function something like this:
SiteCategory->mySpecialFunction()
I don't get it?

You can use a scope method inside your Model like this
Class SiteCategory extends Eloquent {
public function scopeMySpecialFunction($query){
// retrieve all categories, manipulate them in some way and return.
}
}
Then you can call this function like normal built in Eloquent functions like
SiteCategory::mySpecialFunction();
If you want to pass any arguments into this function then you can add parameters like this
public function scopeMySpecialFunction($query, $param1, $param2){
// retrieve all categories, manipulate them in some way and return.
}
Notice the first $query parameter, it's the first parameter of a scope method and $query is an instance of Illuminate\Database\Eloquent\Builder, you can use $this inside that function and can chain methods like
SiteCategory::mySpecialFunction()->find(1);
In this case you have to return the $query from your function to chain other methods, like:
public function scopeMySpecialFunction($query, $param1, $param2){
// do something
return $query;
}

Related

How can I make pagination of a findorfail method in laravel

I have this function in my controller which is the output of many animals and I would like to paginate it. How am I to do that
controller
public function show($id)
{
$farms = User::with(['animals'])->findOrFail($id);
return view('slaughter.show',compact('farms'));
}
Is there any other way of doing that because I have tried to add the paginate method at the end and I am getting an error
paginate() is a method on the Query Builder instance while findOrFail() returns an Eloquent model, and in this case a single instance, as it is for a single user by the given $id.
You can maybe query the animals through their own model, and paginate it, like this:
public function show($id)
{
$farms = Animal::where('user_id', $id)->paginate(10);
return view('slaughter.show',compact('farms'));
}
I would do this to get a paginated collection of animals for the User. Dependency Injection in the show method as well assuming you also require some user data on the slaughter page.
public function show(User $user)
{
$farms = Animals::where('user_id', $user->id)->paginate();
return view('slaughter.show',compact('farms', 'user'));
}
Your route will need updating, something like this...
Route::get('animals/{user}', 'AnimalsController#show')

Custom method not work on HasMany relation

I trying to call a custom method from a model by relation.
User Model:
class User extends Model
{
public function files()
{
return $this->hasMany(Files::class, 'file_id', 'id');
}
}
File Model:
class Files extends Model
{
public function cover()
{
dd('blah blah');
}
}
In my controller I said:
$user = User::find(1);
$user->files()->cover();
But I will get this error:
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::cover()
What is the problem in my code?
Basically you are calling your cover() method over the collection. That's why that is not working.
You are using hasMany Laravel relationship. And this hasMany returns collection of related records(items). And yo can't call any model function on that directly.
But if you wan to call function on this. you need to firstly loop the items, like below example:-
$user = User::find(1);
foreach($user->files() as $file) {
$file->cover();
}
Above code will provide you output. Try this.
If you want to get all the covers of you files, you can do this :
$user = User::with('files.cover')->find(1);
$covers = $user->files->pluck('cover')->flatten();
I want to use this method to check and then store the cover. because I need to check the cover before insert I couldn't use create method, it will be an alias to create. so I couldn't overwrite to create method?
From this, you can do the following:
foreach($user->files as $file){
$cover = $file->cover()->firstOrCreate(['attribute' => $value]);
// If you want to check if you just created the cover
if($cover->wasRecentlyCreated){
// Do stuff
}
}

Serialize Eloquent collection append sometimes

I want to add value from accessor to collection in specific cases. There is array $appends for it, but I don't want to add the values always. Maybe is there a method like makeVisible for it?
Lets imagine I have models Book and Author:
class Book extends Model
{
protected $fillable = ['title', 'author_id'];
public function author()
{
return $this->belongsTo(App\Author::class);
}
public function getAuthorNameAttribute()
{
return $this->author->name;
}
}
And I want to return books collection with author name just call:
Route::get('books', function () {
return App\Book::all()
->appends(['author_name']);
});
And yes I'm able to use map() but I just find another (more beautiful decision)
Yes, Laravel eloquent has a method called makeVisible().
If you would like to make some typically hidden attributes visible on
a given model instance, you may use the makeVisible method. The
makeVisible method returns the model instance for convenient method
chaining.

Use Eloquent Model with more than one methods

Suppose I have a Model called ManageUser.
I have three methods. public static function registerusr(), public static function updateuser() and public static function removeuser().
In my UserController i called them like
$data=ManageUser::registeruser()
$data=ManageUser::updateuser()
$data=ManageUser::removeuser()
This is the fluent way to call the models methods.I am bit confused about Eloquent relationship over normal fluent query.I understand that its optimized the queries.
If i use Eloquent relationship how can i call the different methods in controller ?
You can use relationships inside any of your model methods. Just an example:
public static function updateUser($user, $roles)
{
$user->update(['status' => 1]);
return $user->roles()->sync($roles);
}
And call the method as you call it now:
ManageUser::updateUser($user, $roles);

Eloquent: Is chaining wheres (wrapped into functions) possible?

I have Project and Task models.
I want to do something like:
$project->tasks()->active()->get()
Where $project is a Project object, tasks() is a hasMany() relation, active() should be a function having return $this->whereCompleted(NULL);.
The question is if the whole idea is possible and where should I place the active() function?
You can use Query Scopes : http://laravel.com/docs/eloquent#query-scopes
You just have to put this method in your Task model :
public function scopeActive($query)
{
return $query->whereCompleted(NULL);
}

Resources