gstt / laravel-achievements Goto Github PK
View Code? Open in Web Editor NEWAchievements for Laravel 5.3+
License: MIT License
Achievements for Laravel 5.3+
License: MIT License
When doing a query for user achievements and unlocked ones, the returned data is not pretty optimized. (Personal point of view).
Example of $user->unlockedAchievements()->all()
:
Array ( [0] => Gstt\Achievements\Model\AchievementProgress Object ( [incrementing] => [table:protected] => achievement_progress [guarded:protected] => Array ( ) [casts:protected] => Array ( [unlocked_at] => datetime ) [connection:protected] => mysql [primaryKey:protected] => id [keyType:protected] => int [with:protected] => Array ( ) [withCount:protected] => Array ( ) [perPage:protected] => 15 [exists] => 1 [wasRecentlyCreated] => [attributes:protected] => Array ( [id] => 77352394-32ec-4122-a970-dc2614ae51f6 [achievement_id] => 4 [achiever_id] => 1 [achiever_type] => App\User [points] => 0 [unlocked_at] => 2018-02-21 19:02:54 [created_at] => 2018-03-02 13:32:00 [updated_at] => 2018-03-02 13:32:00 ) [original:protected] => Array ( [id] => 77352394-32ec-4122-a970-dc2614ae51f6 [achievement_id] => 4 [achiever_id] => 1 [achiever_type] => App\User [points] => 0 [unlocked_at] => 2018-02-21 19:02:54 [created_at] => 2018-03-02 13:32:00 [updated_at] => 2018-03-02 13:32:00 ) [changes:protected] => Array ( ) [dates:protected] => Array ( ) [dateFormat:protected] => [appends:protected] => Array ( ) [dispatchesEvents:protected] => Array ( ) [observables:protected] => Array ( ) [relations:protected] => Array ( ) [touches:protected] => Array ( ) [timestamps] => 1 [hidden:protected] => Array ( ) [visible:protected] => Array ( ) [fillable:protected] => Array ( ) ) [1] => Gstt\Achievements\Model\AchievementProgress Object ( [incrementing] => [table:protected] => achievement_progress [guarded:protected] => Array ( ) [casts:protected] => Array ( [unlocked_at] => datetime ) [connection:protected] => mysql [primaryKey:protected] => id [keyType:protected] => int [with:protected] => Array ( ) [withCount:protected] => Array ( ) [perPage:protected] => 15 [exists] => 1 [wasRecentlyCreated] => [attributes:protected] => Array ( [id] => 95d4e3c1-64f2-4649-be50-fa81d90e98fc [achievement_id] => 1 [achiever_id] => 1 [achiever_type] => App\User [points] => 1 [unlocked_at] => 2018-02-21 19:02:54 [created_at] => 2018-02-21 19:02:54 [updated_at] => 2018-02-21 19:02:54 ) [original:protected] => Array ( [id] => 95d4e3c1-64f2-4649-be50-fa81d90e98fc [achievement_id] => 1 [achiever_id] => 1 [achiever_type] => App\User [points] => 1 [unlocked_at] => 2018-02-21 19:02:54 [created_at] => 2018-02-21 19:02:54 [updated_at] => 2018-02-21 19:02:54 ) [changes:protected] => Array ( ) [dates:protected] => Array ( ) [dateFormat:protected] => [appends:protected] => Array ( ) [dispatchesEvents:protected] => Array ( ) [observables:protected] => Array ( ) [relations:protected] => Array ( ) [touches:protected] => Array ( ) [timestamps] => 1 [hidden:protected] => Array ( ) [visible:protected] => Array ( ) [fillable:protected] => Array ( ) ) )
Is really all that data necessary for just 2 achievements? Could be refactored on simpler and more usefull way?
As I see - now it forced to use id attribute in getOrCreateProgressForAchiever method.
Why just not use getKey() instead of id here:
https://github.com/gstt/laravel-achievements/blob/master/src/Achievement.php#L159
Hi Gabriel,
is there another way to get in contact with you?
BR
Jerry
I have two models that I'd like to earn achievements on, is that possible? I'm getting unexpected behavior.
ModelOne
use Gstt\Achievements\Achiever;
use Illuminate\Database\Eloquent\Model;
class ModelOne extends Model
{
use Achiever;
}
ModelTwo
use Gstt\Achievements\Achiever;
use Illuminate\Database\Eloquent\Model;
class ModelTwo extends Model
{
use Achiever;
}
Achievements are working as expected for ModelOne, but ModelTwo is not. This, for example, is getting wrongly saved as being ModelOne...
$model = ModelTwo::first();
$model->unlockIfLocked(new ThisAchievement());
And the achievements relationship is screwy, as well. App\ModelTwo::has('achievements')->first()
does this...
Illuminate/Database/QueryException with message 'SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'achiever_id' cannot be null (SQL: insert into `achievement_progress` (`achievement_id`, `achiever_id`, `achiever_type`, `points`, `id`, `updated_at`, `created_at`) values (1, , App/ModelTwo, 0, d319c898-482c-4833-bc3d-a2c588ba1545, 2018-08-23 12:13:28, 2018-08-23 12:13:28))'
It's possible that it's related to my custom trait that I made:
namespace App\Traits;
use Gstt\Achievements\Achievement;
trait Achievable
{
/**
* Unlock If Locked
*
* @param Achievement $achievement
* @return void
*/
public function unlockIfLocked(Achievement $achievement)
{
if(! $this->hasUnlocked($achievement))
{
$this->unlock($achievement);
}
}
}
@gabriel-simonetti
Thanks for this awesome library.
Any hope for Laravel 6 support? Thanks
How do i make the achiefment multilanguage? I see the achiefment as somethign that is saved in the database, but how do i translate this achiefment?
built in unlocked Achievements counter so can be easily displayed in master/default view. Maybe like so:
<?php $count = Auth::user()->unlockedAchievementsCount(); ?>
with will in return display the count of all the unlocked Achievements that user has?
I'm wondering if there is a way to edit an item in the achievement_progress table specifically? The problem that I have is that I need to reset the number of points back down to 0 if a user gets something wrong in whatever unlocked achievement they currently are working on.
If I just go into the DB table itself and edit the specific row with the code below, I'm able to reset the points, but it also loads every single achievement into the achievement_progress table for the user, and I don't want to clutter this table up with achievements that aren't valid for some time.
$progress = $this->inProgressAchievements()->first();
if($progress) {
$progress->points = 0;
$progress->save()
}
This sends all possible achievements to the achievement_progress table, even though it does reset the achievement in progress.
In order to create stable releases, laravel-achievements will require testing and continuous integration.
A simple way to achieve that is to implement PHPUnit tests and Travis CI.
Hi
Im trying to understand why the id of table achievement_progress uses a unique identifier:
Uuid::uuid4()->toString();
Wouldnt a regular incremented integer suffice?
Thanks
Is there an expected or suggested way to include images to represent the badges? My solution at present is basically
<img src="{{ asset('img/badges/'.str_replace(' ', '_', $achievement->details->name). '.png') }}">
But maybe there's a better way? If so, it seems worth mentioning it in the docs, or maybe including a few different examples of tactics for associating images with your badges. :)
Currently, the Achievements have an undocumented (and untested) functionality: They can implement a onUnlock
method, receiving an instance of AchievementProgress
, that will be called whenever this specific Achievement is unlocked.
This is a bad idea because it does not implement default Laravel conventions. This should be replaced with an implementation that calls Laravel Events.
Problem:
Only for user A a database record was created in the "achievement_progress" table.
$progress = AchievementProgress::where('achiever_type', $className)
->where('achievement_id', $achievementId)
->where('achiever_id', $achiever->id) // i think you forgot this line?
->first();
Is there a way to pass a timestamp to the achievements? I'm trying to add achievements to an existing site and would like to pass a timestamp, so the achievements are recorded as being earned when the old activity happened.
Hi,
I'm about using this package in a new project and I have one suggestion: what about granting permissions when some achievements are reached?
For example, on StackOverflow, you need to have at least 125 reputation to downvote, or 1500 to create tags.
I guess it's rather easy to set it up with a policy, but maybe it could be made with the achievements api?
Hi again,
I've seen there is only a $description
property which seems, according to the examples, to be used to display a message to the user when they reach the achievement.
This is misleading, IMHO, since the description should describe (sic) the achievement and, therefore, be displayed in the list of achievements, so that users know what they have to do to reach the achievement.
The $description
should then describe the achievement, and a $message
property should be displayed when the user unlocks the achievement.
Since the property is public, we can obviously add another property to achieve this. But the examples in the documentation are not very explicit about the contexts.
Also, since the package is designed for Laravel, what about adding localization? Rather than using description property, we could have a getDescription()
method which would return the description translated (or not, depending on configuration). Also, a getMessage()
method would display the message.
A getter would allow developer to add some logic before returning the message/description (maybe you want to return the text with a different vocabulary, for example for adults or children users).
I'd be happy to submit proposals and PRs after discussing this.
A way to display a list of all achievements that are locked so users can see what they have yet to accomplish.
something like so:
http://imgur.com/tJf5DQE
Progress for Locked Achievements would always be Locked by Default. As once its not locked its removed from locked list and added to Completed Achievements list
Currently i am working on new project and i have to create Made 20 appointments in one month achievement. So how can i set the unlocked_at field in achievement_progress table of one month timestamp from current date of making an appointment
Is there a way to configure the used database for the achievements (details and progress)?
I use a system containing multiple databases, and the achievement tables should not necessarily reside in the default database.
I got a working version by directly editing the source code, but this would not be future proof, as newer versions would just overwrite it.
Hello to all users of the laravel-achievements package!
I'm currently writing a new version of the documentation and would like to hear feedback from everyone.
Please consider leaving a comment letting me know about:
Thank you very much!
Hi,
when i run composer update i got the following error:
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'Gstt\Achievements\AchievementsServiceProvider' not found
Script php artisan optimize handling the post-update-cmd event returned with error code 1
composer.json
...
"gstt/laravel-achievements": "^0.0.3",
...
config/app.php
...
Gstt\Achievements\AchievementsServiceProvider::class,
...
Laravel Framework 5.4.15
Looks like php artisan optimize crashed
It seems the author has stopped supporting this repository.
If someone wants to, you can use:
https://github.com/assada/laravel-achievements
PHP 7.2+
Laravel 6/7/8
Auto-discovery package
Code style improvements
Gamerscore is a feature used on Xbox Live tied to the Achievement System.
Achievers are rewarded with a specified amount of points (usually a number between 5 and 100 which reflects how hard the achievement is to obtain) whenever they unlock an Achievement. The score is added to the Achiever's Gamerscore, defined as a sum of all points obtained upon unlocking Achievements.
I am looking for a way to lock achievement. Is is possible?
Is there a way down the road to make logic/frontend so one can create/edit achievements on the fly which could be integrated into a existing admin panel or something. That way staff of site could add new Achievements from site and not have to use terminal and edit code in like sublime text?
I know this is long shot and probably not easy todo with how the Achievements system works now but thought i would throw the idea out there as it would make it more user friendly.
Hello. How am I able to use sweetalert2 for these events?I would like a popup like this when progress or a unlock is made.
https://codepen.io/anon/pen/yXXGPy
Is this possible and if not what to you recommend for alerts? I use toastr for my sites alerts but wanted something little pronounced for achievement alerts.
Thanks.
I saw that achievement generation is quite inefficient when it comes to database usage.
The culprit is getModel
method that is called 3 times for each achievement progress modification:
getOrCreateProgressForAchiever
to fetch achievement idgetOrCreateProgressForAchiever
to associate newly created progress with details modelThen in this getModel
method we have 2 database calls: read
and save
That makes 6 database calls (8 if there is an update) for each achievement update.
My suggestion would be to make a dedicated command for synchronizing achievement details with database and remove save
call from getModel
as well as getModel
call from constructor (possibly as a config option for backword compatibility) .
An extra improvement would be to reuse results of getModel
instead of calling it each time.
Another suggestion would be to add an option for having stable ids
(eg. calculated from md5 of achievement fully qualified class name or just provided by user)
and assume that those will match model's id,
but that is something to be discussed
and since its a super breaking change, definitely require a config option.
Make it so Achievements can be categorized.
Create methods to show only achievements of a specific category.
Possible to add some samples that will work with this package out the box so noobs like me have a base starting point?
Hi, I have recently installed the package, I when I tried to run the following command, the terminal return mi the next error:
domain@hl361:~/www$ php artisan make:achievement UserMadeAPost
Command "make:achievement" is not defined.
Did you mean one of these?
make:auth
make:chart
make:command
make:controller
make:event
make:exception
make:factory
make:job
make:listener
make:mail
make:middleware
make:migration
make:model
make:notification
make:policy
make:provider
make:request
make:resource
make:rule
make:seeder
make:test
Several Achievements use some DB data for their progress, how can I update the point progress of the achievements?
I was thinking on a cron job every X time that checks the DB and sets the progress. How can I implement something like that in Laravel?
Thank you, great job!
Sometimes, there are multiple achievements that track the exact same thing, but with different points to obtain.
For example, an user can obtain a "Newcomer" achievement when creating their first comment on the site, a "Regular Commenter" achievement when they reached 10 comments and a "Regular Commenter" achievement when they reached 100 comments.
Currently, these achievements need to be tracked separately, something like this:
<?php
use App\Achievements\Newcomer;
use App\Achievements\RegularCommenter;
use App\Achievements\VeteranCommenter;
public function createComment($user, $comment){
// Some logic to be processed when the user creates a comment...
$user->addProgress(Newcomer, 1);
$user->addProgress(RegularCommenter, 1);
$user->addProgress(VeteranCommenter, 1);
}
And this would quickly grow out of hand when there are many achievements tracking the same thing. In order to solve this problem, I propose a feature called "Achievement Chain". It would work in the following way:
AchievementChain
will be created. This class will be defined only by a list of achievements.A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.