Laravel How to display $hidden attribute on model on paginate - php

I'm using Laravel 5.5.
I read about this and know this function and it works makeVisible
$hidden = ['password', 'remember_token', 'email'];
I can display email using
$profile = auth()->user()->find($request->user()->id);
$profile->makeVisible(['email']);
On the frontend email is displayed. But it not works on many results like
// Get all users
$users = User::with('role', 'level')->makeVisible(['email'])->paginate(10); // Doesn't work
Also try this method from Laracasts toJson it works but I can't do it using paginate. Can you provide other methods or how to solve this? My aim is to display email column that is hidden. Thanks.

Another, possible easier solution depending on your requirements, is to call makeVisible on the collection:
// Get all users
$users = User::with('role', 'level')->paginate(10)->makeVisible(['email']);
You can also use this with find or get:
$profile = auth()->user()->find($request->user()->id)->makeVisible(['email']);

I solve this using this method.
Users.php on model
public function toArray()
{
// Only hide email if `guest` or not an `admin`
if (auth()->check() && auth()->user()->isAdmin()) {
$this->setAttributeVisibility();
}
return parent::toArray();
}
public function setAttributeVisibility()
{
$this->makeVisible(array_merge($this->fillable, $this->appends, ['enter_relationship_or_other_needed_data']));
}
and on controller just a simple
return User::with('role', 'level')->paginate(10);
I've read where pagination comes from toArray before creating pagination. Thanks for all your help. Also helps

You can use this:
$paginator = User::with('role', 'level')->paginate($pageSize);
$data = $pagination->getCollection();
$data->each(function ($item) {
$item->setHidden([])->setVisible(['email']);
});
$paginator->setCollection($data);
return $paginator;

You can try to use this approach. Using API Resources.
API Resources lets you format the data the way you want. You can create multiple Resource object to format in different ways your collections.
Set visible your parameter (in this case email) and when you need to return that item you can use a different Resource object that returns that elemement.
So when no need for email:
$users = User::with('role', 'level')->paginate(10);
return UserWithoutEmail::collection($users);
when email is needed:
$users = User::with('role', 'level')->paginate(10);
return UserWithEmail::collection($users);

Related

Laravel array key exists in get method

I am trying to fetch the the id and the name of the categories which is related to my services. A service has many categories and a categories belongs to a services. However when I try to get the id and the name as an array to return it gives me this error.
array_key_exists(): The first argument should be either a string or an
integer.
Here is my method or function.
public function getCategories($idService)
{
$service = Service::findOrFail($idService);
return $service->categories->get(['id','name']);;
}
and here is the defined route.
Route::get('service/{service}/categories', 'ServiceController#getCategories');
I tried to look and browse for it but can't find any solution at all.
Use pluck() method instead
return $service->categories->pluck('id','name');
The name of the parameter has to be equal to the wildcard and you need to use pluck() as mentioned in another comment, in your case:
public function getCategories($service)
{
$service = Service::findOrFail($service);
return $service->categories->pluck(['id','name']);
}
If service is a model you can also use eloquent:
public function getCategories(Service $service)
{
return $service->categories->pluck(['id','name']);
}
i guess it related to with eager loading..need to use eager loading to fetch the relationship.. then use laravel collection if you want to filter more
public function getCategories($idService)
{
return Service::with(['categories' => function ($query) {
$query->select('id', 'name');
}])->findOrFail($idService);
}

Dynamic model filter in Laravel's Eloquent

I'm looking for a way to make a dynamic & global model filter in Laravel.
I'm imagining a function like the following in my User.php model:
public function filter() {
return ($someVariable === true);
}
Whenever I do a query using Eloquent's query builder, I only want users to show up in the collection when the filter above returns true. I would have thought a feature like that existed, but a quick look at the documentation suggests otherwise. Or did I miss it?
I believe what you're looking for is Query Scopes.
They are methods that may be defined in a global or local context, that mutate the current query for a given model.
https://laravel.com/docs/5.5/eloquent#query-scopes
For example:
Lets say I have a database table called "Teams" and it has a column on it called "Wins." If I wanted to retrieve all Teams that had a number of Wins between Aand B I could write the following Local scope method on the teams model:
public function scopeWinsBetween($query, int $min, int $max)
{
return $query->whereBetween('wins', $min, $max);
}
And it could be invoked as such:
$teams = Teams::winsBetween(50, 100)->get();
I think you could use Collection macro but you will need to suffix all your eloquent get(); to get()->userDynamicFilter();
Collection::macro('userDynamicFilter', function () {
//$expected = ...
return $this->filter(function ($value) use($expected) {
return $value == $expected;
});
});
Thanks. For now I've simply added a post filter option to the models using the following code:
// Apply a post filter on the model collection
$data = $data->filter(function($modelObject) {
return (method_exists($modelObject, 'postFilter')) ? $modelObject->postFilter($modelObject) : true;
});
in Illuminate/Database/Eloquent/Builder.php's get() function, after creating the collection. This allows me to add a function postFilter($model) into my model which returns either true or false.
Probably not the cleanest solution but a working one for now.

laravel orm: different result from almost same query

I've a very big doubt about how works laravel for a very simple thing:
If I call:
$companies=User::All();
Then I can use statement like this in a forach:
foreach($companies as $company)
$company['new_field']= 'something';
If i'm limiting the output of the query like:
$companies = DB::table('companies')
->select('id','name','email','business_name',...)->get();
The things doesnt work as before,
I try with or without the ->get()
I try to convert with ->toArray() (errors rised)
I try with put() and push() for collections method and agains errors...
How can I add a field in every item of the collection just to pass it to a view?
Try like this, hope it works for you:
$users=User::select('id','name','email','business_name',...)->get()->toArray();
and then use foreach loop like this:
foreach($users as $key => $value ){
$users[$key]['newField'] = "Demo";
}
If you are using Laravel and model in it so there is a better way to add custom attribute or field here is what i do for custom field
For Example :
There is a Model Name User
so in User Model
add a property name appends like :
class User extends Model
{
protected $appends = ['new_field'];
public function getNewFieldAttribute() // defining field logic here
{
return // your code
}
So you no need to use foreach and looping and adding new field
for more have a look on laravel doc : https://laravel.com/docs/5.5/eloquent-mutators#accessors-and-mutators
Suggestion
you can limit your output with Model too.
User::select('id','name','email','business_name',...)->get();
if you are making an array like
User::select('id','name','email','business_name',...)->get()->toArray();
so this will also give you your custom field

How to send multiple variable to a view in laravel when one or more variables are null

When a new user is registered and is redirected to profile page. All these $userconatact , $qualification and $profileimage variables are null. Home page is setup with if (condition) to have buttons to fill form or show available data to user. There are three forms and user has to fill these form one by one. All these variables or one of them could be null but I still want to send the null value to view. Is there any way to make this view happen.
class ProfileController extends Controller
{
public function showprofile($type=null, $id='id'){
$contactquery = Usercontact::where('user_id',Auth::user()->id)->select('*')->get();
$usercontact = $contactquery->toArray();
$qualificationquery = userqualification::where('user_id',Auth::user()->id)->select('*')->get();
$qualification = $qualificationquery->toArray();
$profileimagequery = Profileimage::where('user_id',Auth::user()->id)->select('id','user_id','profileimage')->get();
$profileimage = $profileimagequery->toArray();
return view('home')->withUsercontact($usercontact)->withQualification($qualification)->withProfileimage($profileimage);
}
}
I tried using if statements but if didn't work
return view('home')
if(!empty($usercontact)){->withUsercontact($usercontact)}
if(!empty($qualification)){->withQualification($qualification)}
if(!empty($profileimage)){->withProfileimage($profileimage);}
Is there any way to use if statements like this to make it easy.
1) Use compact which will automatically create key value pairs for you.
return view('home')->compact('usercontact','qualification','profileImage')
2) Here are a few other improvements to your code. You can use the Auth facade to access the logged-in user.
$usercontact = Auth::user();
3) Define relationships on your user model and access the qualifications by this. This will return a Collection.
$qualification = $usercontact->qualifications;
You can use compact to send data from your controllers to views.
return view('home')->compact('usercontact', 'qualification', profileimage');
Your code can be refactored as below.
public function showprofile($type=null, $id='id')
{
$usercontact = Usercontact::where('user_id',Auth::user()->id)->first();
$qualification = Userqualification::where('user_id',Auth::user()->id)->first();
$profileimage = Profileimage::where('user_id',Auth::user()->id)->select('id','user_id','profileimage')->first();
return view('home')->compact('usercontact', 'qualification', 'profileimage');
}
Note the Userqualification model name in the code according to the convention. Try to add relationships to your models to make your query easier.
Try this style to send data to view
return view('home',['Usercontact'=>$usercontact,'Qualification'=>$qualification,'Profileimage'=>$profileimage]);
In view you will be able to get data by array key

Is it possible to use models in laravel routes without static?

For example I need to return comments. I already have a method for this in my model. Is it possible to do something like this?
Route::get('/comments/{page}', function($page) {
$comments = Comments::get($page);
return Response::json($comments);
});
Or do I need to create a facade for each model?
Typically, comments would be associated with a page via an Eloquent relationship, which would allow something like this:
return Response::json($page->comments);
Check Defining A Query Scope on Laravel website:
// In Comments Model
public function scopeGetMessage($query, $page)
{
// You can use $query->where(...)
// return the query for chaining
// You can use $this->where(...)
// Or just return the thing you want
}
Now you may call it like:
$comments = Comments::getMessage($page);

Categories