I am proficient in Drupal 7 where I get the current user object from global $user, but how do I get it in Drupal 8 ?
One liner way to get a full drupal user object for the current active user :
$account = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
Why not just Drupal::currentUser() ? Because most of the time it won't be sufficient as you'll need a fully loaded user object while it's not :
\Drupal::currentUser() returns an AccountProxyInterface.
\Drupal\user\Entity\User::load() actually returns a user entity object.
Please use following code to get the current user object in Drupal 8:
$user = \Drupal::currentUser();
According to entity api, we should not use User::load. Instead, use entityTypeManager like so :
$user_id = \Drupal::currentUser()->id();
$user_entity = \Drupal::entityTypeManager()->getStorage('user')->load($user_id);
$user = \Drupal::currentUser();
To get the current userID you can use :
$user = User::load(\Drupal::currentUser()->id());
I've searched everywhere for this and tried to make it happen all day today, but still can't figure it out.
Basically I am trying to use IF statements in routes to display appropriate info to users with appropriate ID.
But I am getting
Function name must be a string
For this
if ($user = $id(8))
I can't figure out how to pass in current users id to that if statement to check it. Sorry if dumb question, but I'm just starting with Laravel.
Route::get('/secret', function()
{
$user = Auth::user();
$id = Auth::id();
if ($user = $id(8))
{
return 'It worked!';
}
return 'Your id is not 8.';
});
Thanks
You cannot use if($user = $id(8)), try to use: if($id == 8) instead. You want to compare two values, so you need to use ==, = means assigning a value.
Hope it works!
By the way: you don't have to use the $user variable as far as I can see. $id is enough in your case ;)
JohnLV's answer is correct, but you look like you might be better off making a route filter - read here for more information:
http://laravel.com/docs/routing#route-filters
This is for when you want to block access to certain pages/routes based on user privileges (i.e. hide admin area from users).
But if you want to change things in you view based on user id, then it is best to put this code in the controller.
Either I don't understand how CCompareValidator works in Yii (sic!) or it doesn't work for me at all.
I want to check, if an ID of row / record / user being updated isn't the same, as an ID of currently logged-in user. And prohibit update, if it is.
I used CCompareValidator at first:
array('id', 'compare', 'compareValue'=>Yii::app()->user->id, 'message'=>'Boom!')
It doesn't work -- it halts editing / update of every row / record / user, no matter, what an ID actually is.
So, I rewrote it to my own, custom validator. In my opinion, the code is the same as in case of built-in one:
array('id', 'compareId', 'compareValue'=>Yii::app()->user->id, 'message'=>'Boom!')
public function compareId($attribute = null, $params = null)
{
if($attribute === 'id')
{
if($this->id == $params['compareValue'])
{
$this->addError($params['message']);
}
}
}
It works like a charm -- allows update of any row / record / user, which ID is different than currently logged-in user's ID. Blocks update, showing defined message, in case compared IDs are equal.
What am I missing? Why original Yii's built in validator fails on such simple example, while my own works?
The validator works, as supposed, my logic have failed:
CCompareValidator, throws an error, when two compared values are not equal. On the other hand, if they're equal -- it passes validation without errors. That is supposed behavior.
I wanted an error, when values are equal (which means, that user is attempting to edit himself or herself) and pass as validated, when both values are different (logged user edits different one).
That's why I need to use 'operator'=>'!=' as configuration of validator. This is the answer.
BTW: All the glory of solving this problem goes to Keith at YiiFramework.com's forum.
I've been working with SugarCRM by creating a custom module and a custom PHP file to that module. I need to display all the Roles available to Users and have the data displayed on the custom PHP page.
I have looked in to getAllRoles() function and...
ACLRole::getAllRoles(boolean $returnAsArray=false);
Can any one help me get these functions to work properly?
(Please answer only if you know the answer and do not close the question with false reasons.)
You can easily get all Roles that aren't deleted, you will find the method in /modules/ACLRoles/ACLRole.php. It will return either an array of array representations of acl roles or an array of ACLRoles.
The query is:
'SELECT acl_roles.* FROM acl_roles WHERE acl_roles.deleted=0 ORDER BY name';
Try this code:
$roles = array();
$roles = ACLRole::getAllRoles(true);
print_r($roles);
sugar_die();
Hope that helps.
I'm thinking of the best way to design an achievements system for use on my site. The database structure can be found at Best way to tell 3 or more consecutive records missing and this thread is really an extension to get the ideas from developers.
The problem I have with lots of talk about badges/achievement systems on this website is just that -- it's all talk and no code. Where's the actual code implemention examples?
I propose here a design that I hope people could contribute to and hopefully create a good design for coding extensible achievement systems. I'm not saying this is the best, far from it, but it's a possible starting block.
Please feel free to contribute your ideas.
my system design idea
It seems the general consensus is to create an "event based system" -- whenever a known event occurs like a post is created, deleted, etc it calls the event class like so..
$event->trigger('POST_CREATED', array('id' => 8));
The event class then finds out what badges are "listening" for this event, then it requires that file, and creates an instance of that class, like so:
require '/badges/' . $file;
$badge = new $class;
It then calls the default event passing the data received when trigger was called;
$badge->default_event($data);
the badges
This is then where the real magic happens. each badge has its own query/logic to determine if a badge should be awarded. Each badge is set out in e.g. this format:
class Badge_Name extends Badge
{
const _BADGE_500 = 'POST_500';
const _BADGE_300 = 'POST_300';
const _BADGE_100 = 'POST_100';
function get_user_post_count()
{
$escaped_user_id = mysql_real_escape_string($this->user_id);
$r = mysql_query("SELECT COUNT(*) FROM posts
WHERE userid='$escaped_user_id'");
if ($row = mysql_fetch_row($r))
{
return $row[0];
}
return 0;
}
function default_event($data)
{
$post_count = $this->get_user_post_count();
$this->try_award($post_count);
}
function try_award($post_count)
{
if ($post_count > 500)
{
$this->award(self::_BADGE_500);
}
else if ($post_count > 300)
{
$this->award(self::_BADGE_300);
}
else if ($post_count > 100)
{
$this->award(self::_BADGE_100);
}
}
}
award function comes from an extended class Badge which basically checks to see if the user has already be awarded that badge, if not, will update the badge db table. The badge class also takes care of retrieving all badges for a user and returning it in an array, etc (so badges can be e.g. displayed on the user profile)
what about when the system is very first implemented on an already live site?
There is also a "cron" job query that can be added to each badge. The reason for this is because when the badge system is very first implemented and initilaised, the badges that should have already been earned have not yet be awarded because this is an event based system. So a CRON job is run on demand for each badge to award anything that needs to be. For example the CRON job for the above would look like:
class Badge_Name_Cron extends Badge_Name
{
function cron_job()
{
$r = mysql_query('SELECT COUNT(*) as post_count, user_id FROM posts');
while ($obj = mysql_fetch_object($r))
{
$this->user_id = $obj->user_id; //make sure we're operating on the right user
$this->try_award($obj->post_count);
}
}
}
As the above cron class extends the main badge class, it can re-use the logic function try_award
The reason why I create a specialised query for this is although we could "simulate" previous events, i.e. go through every user post and trigger the event class like $event->trigger() it would be very slow, especially for many badges. So we instead create an optimized query.
what user gets the award? all about awarding other users based on event
The Badge class award function acts on user_id -- they will always be given the award. By default the badge is awarded to the person who CAUSED the event to happen i.e. the session user id (this is true for the default_event function, although the CRON job obviously loops through all users and awards seperate users)
So let's take an example, on a coding challenge website users submit their coding entry. The admin then judges the entries and when complete, posts the results to the challenge page for all to see. When this happens, a POSTED_RESULTS event is called.
If you want to award badges for users for all the entries posted, lets say, if they were ranked within the top 5, you should use the cron job (although bare in mind this will update for all users, not just for that challenge the results were posted for)
If you want to target a more specific area to update with the cron job, let's see if there is a way to add filtering parameters into the cron job object, and get the cron_job function to use them. For example:
class Badge_Top5 extends Badge
{
const _BADGE_NAME = 'top5';
function try_award($position)
{
if ($position <= 5)
{
$this->award(self::_BADGE_NAME);
}
}
}
class Badge_Top5_Cron extends Badge_Top5
{
function cron_job($challenge_id = 0)
{
$where = '';
if ($challenge_id)
{
$escaped_challenge_id = mysql_real_escape_string($challenge_id);
$where = "WHERE challenge_id = '$escaped_challenge_id'";
}
$r = mysql_query("SELECT position, user_id
FROM challenge_entries
$where");
while ($obj = mysql_fetch_object($r))
{
$this->user_id = $obj->user_id; //award the correct user!
$this->try_award($obj->position);
}
}
The cron function will still work even if the parameter is not supplied.
I've implemented a reward system once in what you would call a document oriented database (this was a mud for players). Some highlights from my implementation, translated to PHP and MySQL:
Every detail about the badge is stored in the users data. If you use MySQL I would have made sure that this data is in one record per user in the database for performance.
Every time the person in question does something, the code triggers the badge code with a given flag, for instance flag('POST_MESSAGE').
One event could also trigger a counter, for instance a count of number of posts. increase_count('POST_MESSAGE'). In here you could have a check (either by a hook, or just having a test in this method) that if the POST_MESSAGE count is > 300 then you should have reward a badge, for instance: flag("300_POST").
In the flag method, I'd put the code to reward badges. For instance, if the Flag 300_POST is sent, then the badge reward_badge("300_POST") should be called.
In the flag method, you should also have the users previous flags present. so you could say when the user has FIRST_COMMENT, FIRST_POST, FIRST_READ you grant badge("NEW USER"), and when you get 100_COMMENT, 100_POST, 300_READ you can grant badge("EXPERIENCED_USER")
All of these flags and badges need to be stored somehow. Use some way where you think of the flags as bits. If you want this to be stored really efficiently, you think of them as bits and use the code below: (Or you could just use a bare string "000000001111000" if you don't want this complexity.
$achievments = 0;
$bits = sprintf("%032b", $achievements);
/* Set bit 10 */
$bits[10] = 1;
$achievements = bindec($bits);
print "Bits: $bits\n";
print "Achievements: $achievements\n";
/* Reload */
$bits = sprintf("%032b", $achievments);
/* Set bit 5 */
$bits[5] = 1;
$achievements = bindec($bits);
print "Bits: $bits\n";
print "Achievements: $achievements\n";
A nice way of storing a document for the user is to use json and store the users data in a single text column. Use json_encode and json_decode to store/retrieve the data.
For tracking activity on some of the users data manipulated by some other user, add a data structure on the item and use counters there as well. For instance read count. Use the same technique as described above for awarding badges, but the update should of course go into the owning users post. (For instance article read 1000 times badge).
UserInfuser is an open source gamification platform which implements a badging/points service. You can check out its API here:
http://code.google.com/p/userinfuser/wiki/API_Documentation
I implemented it and tried to keep the number of functions minimal. Here is the API for a php client:
class UserInfuser($account, $api_key)
{
public function get_user_data($user_id);
public function update_user($user_id);
public function award_badge($badge_id, $user_id);
public function remove_badge($badge_id, $user_id);
public function award_points($user_id, $points_awarded);
public function award_badge_points($badge_id, $user_id, $points_awarded, $points_required);
public function get_widget($user_id, $widget_type);
}
The end result is to show the data in a meaningful way through the use of widgets. These widgets include: trophy case, leaderboard, milestones, live notifications, rank and points.
The implementation of the API can be found here: http://code.google.com/p/userinfuser/source/browse/trunk/serverside/api/api.py
Achievements can be burdensome and even more so if you have to add them in later, unless you have a well-formed Event class.
This segues into my technique of implementing achievements.
I like to split them first into 'categories' and within those have tiers of accomplishment. i.e. a kills category in a game may have an award at 1 for first kill, 10 ten kills, 1000 thousand kills etc.
Then to the spine of any good application, the class handling your events. Again imagining a game with kills; when a player kills something, stuff happens. The kill is noted, etc and that is best handled in a centralized location, like and Events class that can dispatch info to other places involved.
It falls perfectly into place there, that in the proper method, instantiate your Achievements class and check it the player is due one.
As building the Achievements class it is trivial, just something that checks the database to see if the player has as many kills as are required for the next achievement.
I like to store user's achievements in a BitField using Redis but the same technique can be used in MySQL. That is, you can store the player's achievements as an int and then and that int with the bit you have defined as that achievement to see if they have already gained it. That way it uses only a single int column in the database.
The downside to this is you have to have them organized well and you will likely need to make some comments in your code so you will remember what 2^14 corresponds to later. If your achievements are enumerated in their own table then you can just do 2^pk where pk is the primary key of the achievements table. That makes the check something like
if(((2**$pk) & ($usersAchInt)) > 0){
// fire off the giveAchievement() event
}
This way you can add achievements later and it will dovetail fine, just NEVER change the primary key of the achievements already awarded.