Unlocking Badges Workshop

Together, in this series we'll add an "Unlockable Badge" feature to the Laracasts website. Perhaps when a user reaches a certain XP threshold, they unlock a badge. Or when they reach 500 "Best Answer" slots, they earn yet another badge. You get the idea.

Let's research and implement this feature using TDD from scratch.

Start Series

Share this series on:

  • 01

    Episode 1 Run Time 9:23

    Begin With an Example Free

    Like so many other things in life, starting a new feature is the hardest part. We're creating something out of nothing. It's not an easy task to define how that "something" should appear. But we'll try. Let's begin with one example of how the system should behave, using TDD.

  • 02

    Episode 2 Run Time 14:06

    Event Fakery

    Let's drop down a level and write a test to ensure that, when experience is awarded to a user, an announcement (or event) is made to the rest of our application. Later, we'll listen for this announcement and grant any necessary achievement badges to the user.

  • 03

    Episode 3 Run Time 6:01

    Use TDD to Construct Migrations and Attributes

    It sounds like we'll need an Achievement Eloquent model, as well as its associated database table. Let's use TDD to construct both.

  • 04

    Episode 4 Run Time 8:24

    A User Can Be Awarded Achievements

    In this episode, we'll construct the relationship between a user and their respective achievements. As you'll see, this is a prime use-case for a generic pivot table.

  • 05

    Episode 5 Run Time 11:54

    What If We Didn't Use a Database?

    Leading up to this episode, I've been doing some thinking. Yes, we can store achievement badges within the database, but where do we put the logic that determines if the given user should be granted that badge? This led me to considering a different path we might consider. In this episode, let's tinker around with that idea. If we like it, we'll keep it. If we don't, we'll revert!

  • 06

    Episode 6 Run Time 4:16


    In the previous episode, we tinkered with the idea of not using a database at all for determining and fetching a user's acquired achievement badges. Let's talk about that refactor - including the pros and cons to such an approach - before ultimately reverting in favor of a better solution for our needs.

  • 07

    Episode 7 Run Time 21:45

    Syncing User Achievements With Collections

    Now that we've reverted the previous lesson's work, we can move on to a clean approach. In this lesson, we'll build the necessary system to register and sync achievements with any given user, based on newly awarded experience.

  • 08

    Episode 8 Run Time 8:22

    Two Ways to Organize a Project

    In this episode, we'll discuss two equally valid ways to organize all of the achievement-related files, including service providers, events, listeners, etc.

  • 09

    Episode 9 Run Time 8:48

    Sensible Defaults With TDD

    In this lesson, let's use TDD to provide a sensible default name for each achievement, based upon the class name.

  • 10

    Episode 10 Run Time 7:24

    An Artisan Command to Generate New Achievements

    It might be nice to offer an Artisan command to quickly scaffold new achievement classes. Though it provides only a small speed boost, conveniences like this are always useful and appreciated.

  • 11

    Episode 11 Run Time 2:44

    Achievement Types Should Live Together

    When we glance at our app/Achievements directory, it's difficult to tell which of the classes are achievement types that can be awarded to a user. Let's move all of those related files to their own directory in this lesson.

  • 12

    Episode 12 Run Time 4:36

    Viewing Achievements: Part 1

    Much of this feature is now working, so let's finally view it in the browser. We'll start by preparing a few sample achievement badges, and then seeding and fetching a user's achievements. Once we have this information, it should be as simple as looping through all available achievements, and toggling a CSS class that indicates if the current user has been awarded the related badge.

  • 13

    Episode 13 Run Time 7:40

    Viewing Achievements: Part 2

    In this lesson, we'll construct a view that displays which achievements the current user has and has not been awarded.

  • 14

    Episode 14 Run Time 9:56

    We Need A Seeder Console Command

    Once we deploy this new feature, initially, it will appear as if all users have zero achievements. This is because the logic that syncs a user's achievements does not take place until they've accrued new experience points. To fix this, let's use TDD to construct an Artisan command to seed all user achievements in our system.

  • 15

    Episode 15 Run Time 5:34

    The Real Laracasts Achievement Badges

    I will now begin constructing the actual achievement badges that you can earn here at Laracasts. The badge designs are ready, so come along as I add them.

  • 16

    Episode 16 Run Time 6:08

    More Sensible Achievement Defaults

    In the previous episode, we noticed that an achievement's icon file name is almost always the kebab-case version of the class name. With that in mind, let's make that the default. Next, we'll turn the achievement's description property into a dedicated method.

  • 17

    Episode 17 Run Time 4:44

    Achievement Caching

    Did you notice that we have a pesky N+1 issue at the moment? Let's resolve it in this episode by caching all achievements forever. If at some point in the future we need to add a new achievement, we'll simply make a note to clear out the cache during our deployment process.

  • 18

    Episode 18 Run Time 7:18

    Custom Achievement Collections

    In some situations, you may find it beneficial to return a custom collection class for your various Eloquent queries. No problem: overriding the newCollection method on your model makes this task a cinch to complete.

  • 19

    Episode 19 Run Time 7:42

    Color Coding Achievements

    At the moment, all achievements exist on the same playing field, which we designate using a blue background. Let's add the necessary logic to specify a beginner, intermediate, or advanced skill level for each achievement type. Then, in our UI, we can visualize these with yellow, blue, and red background colors, respectively.

  • 20

    Episode 20 Run Time 10:59

    Custom Collection Sorting With Lookup Tables

    I'd like to sort all achievements from beginner to advanced. It sounds like we'll need custom sorting logic. Let's tackle that in this lesson by building a lookup table to translate each skill level to a respective number. Finally, we'll finish the lesson by discussing object responsibility and where logic like this should live.

  • 21

    Episode 21 Run Time 6:29

    That's a Wrap

    Take a moment to think how much we've covered in this series. These techniques can be applied to any new component or feature that you're working on. I hope you've found a technique or two to throw into your toolbelt. Thanks for coming along!