JWT Laravel - Modifying the content of the json output - php

I'm trying to modify the json output of authenticate method of JWT in laravel to make it to display roles as an array.
So here i
created_at
:
"2016-08-18 12:33:14"
email
:
"dhenn.espiritu#gmail.com"
id
:
1
last_logged_in
:
"2016-09-21 16:37:35"
name
:
"Dhenn"
roles
:
"{0: admin,
1: user"}
updated_at
:
"2016-09-21 16:37:35"
But I can't. I tried to modify my jwt.auth php file but it returned me an error that i am setting a non property object.
Here's current setup of the jwt-auth.php
public function authenticate($token = false)
{
$id = $this->getPayload($token)->get('sub');
if (! $this->auth->byId($id)) {
return false;
}
$user = $this->auth->user();
return $user;
}
While, I'm having error trying this:
public function authenticate($token = false)
{
$id = $this->getPayload($token)->get('sub');
if (! $this->auth->byId($id)) {
return false;
}
$user = $this->auth->user();
foreach ($user as $roles) {
$roles->roles = explode(",", $roles->roles);
}
return $user;
}

You said this is your user object:
{ email : "dhenn.espiritu#gmail.com"
id : 1
last_logged_in : "2016-09-21 16:37:35"
name : "Dhenn"
roles : "{0: admin, 1: user"}
updated_at : "2016-09-21 16:37:35" }
Assuming $this->auth->user(); returns this, your iteration foreach ($user as $roles) { is not correct, since $user should be an object not an array. This way you try to go through each property of this object, but I figure you want to iterate of the roles array.
This should be something like:
foreach($user->roles as $role) ... // assuming roles is an array
But roles seems to be a encoded JSON string, so you need to decode it too.
foreach(json_decode($user->roles) as $role) ...
Or directly: $user->roles = json_decode($user->roles)

Try to add
protected $casts = ['roles' => 'array'];
to your User model. That should ensure that the attributes are parsed correctly.
Here is the link to the docs https://laravel.com/docs/5.3/eloquent-mutators#attribute-casting

OK, thanks all for your help. I figured out the answer.
Here's my code that worked finally.
public function authenticate($token = false)
{
$id = $this->getPayload($token)->get('sub');
if (! $this->auth->byId($id)) {
return false;
}
$user = $this->auth->user();
$user->roles = explode(",", $user->roles);
return $user;
}

Related

OctoberCMS Pagination

I use octobercms and User Extended plugin(Clacke). I try to render a pagination because for now i have a lot of registered users and they display on one page.
I use random users function from \classes\UserManager.php
public static function getRandomUserSet($limit = 7)
{
$returner = new Collection;
$userCount = User::all()->count();
if(!isset($userCount) || empty($userCount) || $userCount == 0)
return [];
if($userCount < $limit)
$limit = $userCount;
$users = User::all(); //paginate(5)
if(empty($users))
return $returner;
$users->random($limit);
$friends = FriendsManager::getAllFriends();
foreach($users as $user)
{
$userAdd = true;
if(!$friends->isEmpty())
{
foreach($friends as $friend)
{
if($user->id == $friend->id)
{
$userAdd = false;
break;
}
}
}
if($user->id == UserUtil::getLoggedInUser()->id)
$userAdd = false;
if($userAdd)
{
$returner->push($user);
}
}
return $returner->shuffle();
}
try to do this with changing return $returner->paginate(25); and $users = User::paginate(25); but throws me an error
An exception has been thrown during the rendering of a template
("Method paginate does not exist.").
After that i try to change directly in \components\User.php
public function randomUsers()
{
return UserManager::getRandomUserSet($this->property('maxItems'))->paginate(12);
}
But again the same error.
Tryed and with this code and render in default.htm {{ tests.render|raw }}
public function randomUsers()
{
$test = UserManager::getRandomUserSet($this->property('maxItems'));
return $test->paginate(10);
}
Again with no success. Could anyoune give me some navigation and help to fix this?
If you are using random users function from \classes\UserManager.php
I checked the code and found that its using Illuminate\Support\Collection Object. So, for that Collection Object pagination works differently
You need to use forPage method.
On the other hands paginate is method of Illuminate\Database\Eloquent\Collection <- so both collection are not same
Use forpage
// OLD return UserManager::getRandomUserSet($this->property('maxItems'))
// ->paginate(12);
TO
return UserManager::getRandomUserSet($this->property('maxItems'))
->forPage(1, 12);
forPage method works like forPage(<<PAGE_NO>>, <<NO_OF_ITEM_PER_PAGE>>);
so if you use forPage it will work fine.
if any doubt please comment.

How to get index of element in Laravel collection

How to retrieve the index of an element in a collection ?
My code :
$users = User::has('posts')->withCount('posts')->orderBy('posts_count')->take(50)->get();
if($users->contains(Auth::id())){
//get the index of auth user id
}
Thank's for help
You can use the collection search() method: https://laravel.com/docs/5.7/collections#method-search
$users = User::has('posts')->withCount('posts')->orderBy('posts_count')->take(50)->get();
$userIndex = $users->search(function($user) {
return $user->id === Auth::id();
});
Just be careful, because the index might be 0:
// DON'T do this
if($userIndex) {
// this will get skipped if the user is the first one in the collection
}
// Do this instead
if($userIndex !== false) {
// this will work
}
$users = User::has('posts')->withCount('posts')->orderBy('posts_count')->take(50)->get();
// this return a collection. So can do an if like this: $userIndex->count() > 0
$userIndex = $users->filter(function($user) {
return $user->id === Auth::id()
});

Laravel - store database value to variable in controller

I'm trying to store a database value to a variable in a controller. But i'm getting this error "Object of class Illuminate\Support\Collection could not be converted to int", i know what it means but i don't know how to fix it.
What i want is that if user is banned, then change $banned to true and return it.
private function isBanned() {
$banned = false;
$getBanned = DB::table('Uzivatele')->select('banned')->where('id', Auth::id())->get();
if ($getBanned == 1) $banned = true;
return $banned;
}
if you want to set it directly you can do this way
$getBanned = DB::table('Uzivatele')->where('id', Auth::id())
->update(['banned' => true])->get();
if you want to check the user is banned or not then you can check like this.
private function isBanned() {
$banned = false;
$getBanned = DB::table('Uzivatele')->select('banned')->where('id', Auth::id())->first();
if ($getBanned->banned == 1) $banned = true;
return $banned;
}

Laravel get conversation where users in array

I am making a messaging app, and i need to check if a conversation already exists that has a certain list of users (no more, no less). I have this model:
class Conversation{
public function users(){
return $this->belongsToMany('App\User');
}
public function messages(){
return $this->hasMany('App\Message');
}
}
I have these tables:
conversations:
id
user_id <- the owner of the conversation
users:
id
email
password
conversation_user:
id
conversation_id
user_id
I want to make a post request like this:
{
"users": [1,4,6], <- user ids
"message": "Some message"
}
If a conversation already exists with all and only users 1,4,6, the message should be added to that conversation to avoid having duplicate conversations in the database. Otherwise i will make a new conversation with the specified users.
This is the best i have been able to do so far:
$existing_conversation = $user->conversations()->whereHas('users',
function($query) use ($data){
$query->whereIn('user_id', $data['users']);
}
)->has('users', '=', count($data['users']));
But it just returns the conversations that has exactly the amount of users that was in the users array. It ignores the inner query..
Does anyone have an idea for this? :)
You can try the following query
$existing_conversation = $user->conversations()->wherePivotIn('user_id', $data['users'])->has('users', count($data['users'])->get();
Haven't tested, should work I think.
UPDATE
Not a very elegant solution, however it works. You can add some helper methods in your controller like
//Get user's conversations with no of users equal to count($data['users']);
protected function get_conversations_with_equal_users(User $user, array $user_ids)
{
return $user->conversations()
->wherePivotIn('user_id', $user_ids)
->has('users', '=', count($user_ids))
->get();
}
//Get the id of a user conversation with exactly same users as $data['users'] if it exists otherwise it will return 0;
protected function get_existing_conversation_id(User $user, array $user_ids)
{
$existing_conversation_id = 0;
$user_conversations_with_equal_users = $this->get_conversations_with_equal_users($user, $user_ids);
foreach($user_conversations_with_equal_users as $conv)
{
$ids = [];
foreach($conv->users as $user)
{
$ids[] = $user->id;
}
if($this->array_equal($user_ids, $ids))
{
$existing_conversation_id = $conv->id;
}
}
return $existing_conversation_id;
}
//Function to compare two arrays for equality.
protected function array_equal($a, $b) {
return (
is_array($a) && is_array($b) &&
count($a) == count($b) &&
array_diff($a, $b) === array_diff($b, $a)
);
}
The you can use the following in your controller to get the existing conversation for user (if it exists)
$existing_conversation_id = $this->get_existing_conversation_id($user, $data['users']);
if($existing_conversation_id)
{
$existing_conversation = Conversation::with('users')
->whereId($existing_conversation_id)
->get();
}

Laravel - Multi fields search form

I'm builind a form with laravel to search users, this form has multiple fields like
Age (which is mandatory)
Hobbies (optional)
What the user likes (optional)
And some others to come
For the age, the user can select in the list (18+, 18-23,23-30, 30+ etc...) and my problem is that i would like to know how i can do to combine these fields into one single query that i return to the view.
For now, i have something like this :
if(Input::get('like')){
$users = User::where('gender', $user->interested_by)->has('interestedBy', Input::get('like'))->get();
if(strlen(Input::get('age')) == 3){
$input = substr(Input::get('age'),0, -1);
if(Input::get('age') == '18+' || Input::get('age') == '30+' )
{
foreach ($users as $user)
{
if($user->age($user->id) >= $input){
$result[] = $user;
// On enregistre les users étant supérieur au if plus haut
}
else
$result = [];
}
return view('search.result', ['users' => $result]);
}
elseif (strlen(Input::get('age')) == 5) {
$min = substr(Input::get('age'), 0, -3);
$max = substr(Input::get('age'), -2);
$result = array();
foreach($users as $user)
{
if($user->age($user->id) >= $min && $user->age($user->id) <= $max)
$result[] = $user;
}
return view('search.result', ['users' => $result]);
}
}
else
$users = User::all();
And so the problem is that there is gonna be 2 or 3 more optional fields coming and i would like to query for each input if empty but i don't know how to do it, i kept the age at the end because it's mandatory but i don't know if it's the good thing to do.
Actually this code works for now, but if i had an other field i don't know how i can do to query for each input, i know that i have to remove the get in my where and do it at the end but i wanna add the get for the last query..
Edit: my models :
User.php
public function interestedBy()
{
return $this->belongsToMany('App\InterestedBy');
}
And the same in InterestedBy.php
class InterestedBy extends Model{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'interested_by';
public function users()
{
return $this->belongsToMany('App\User');
}
}
you can use query builer to do this as follow
$userBuilder = User::where(DB::raw('1')); //this will return builder object to continue with the optional things
// if User model object injected using ioc container $user->newQuery() will return blank builder object
$hobbies = Request::input('hobbies') // for laravel 5
if( !empty($hobbies) )
{
$userBuilder = $userBuilder->whereIn('hobbies',$hobbies) //$hobbies is array
}
//other fields so on
$users = $userBuilder->get();
//filter by age
$age = Request::input('age');
$finalRows = $users->filter(function($q) use($age){
return $q->age >= $age; //$q will be object of User
});
//$finalRows will hold the final collection which will have only ages test passed in the filter
A way you could possible do this is using query scopes (more about that here) and then check if the optional fields have inputs.
Here is an example
Inside your User Model
//Just a few simple examples to get the hang of it.
public function scopeSearchAge($query, $age)
{
return $query->where('age', '=', $age);
});
}
public function scopeSearchHobby($query, $hobby)
{
return $query->hobby()->where('hobby', '=', $hobby);
});
}
Inside your Controller
public function search()
{
$queryBuilder = User::query();
if (Input::has('age'))
{
$queryBuilder ->searchAge(Input::get('age'));
}
if (Input::has('hobby'))
{
$queryBuilder->searchHobby(Input::get('hobby'));
}
$users= $queryBuilder->get();
}

Categories