Back Button Laravel

Let's Build A Forum with Laravel and TDD

A forum is a deceptively complex thing. Sure, it's made up of threads and replies, but what else might exist as part of a forum? What about profiles, or thread subscriptions, or filtering, or real-time notifications? As it turns out, a forum is the perfect project to stretch your programming muscles. In this series, we'll work together to build one with tests from A to Z.

102 episodes
19:29:26 hrs
Start Series
  • 01

    Episode 1 Run Time 7:59

    Let's begin by reviewing the most minimal requirements for a forum. If you think about it, we couldn't possibly construct a forum without users, threads, and replies. So let's tackle those first.

    View the source code for this lesson on GitHub.

  • 02

    Episode 2 Run Time 9:26

    Now that we have our seed data in place, we can move on to our first small feature: "a user should be able to read threads." Simple enough! We'll start with a basic test, and then scaffold the necessary views to make it pass.

    View the source code for this lesson on GitHub.

  • 03

    Episode 3 Run Time 9:09

    Now that we've added a basic feature for users to read forum threads, we can next move on to viewing all replies associated with each thread. As before, we'll start with a test to describe our desired outcome.

    View the source code for this lesson on GitHub.

  • 04

    Episode 4 Run Time 17:39

    We've implemented the necessary functionality to render a thread with all relevant replies, but we haven't yet allowed a user to type in a reply and submit it to the server. Let's get started on that now.

    View the source code for this lesson on GitHub.

  • 05

    Episode 5 Run Time 5:14

    Now that we've tested the end-point for adding a new reply, the only remaining step is to create the HTML for the form. In the process, we'll also ensure that only logged-in users are able to see it.

  • 06

    Episode 6 Run Time 6:13

    So far, a user can read and reply to threads, but they don't yet have the ability to publish their own threads. Let's begin fixing that in this episode.

    View the source for this lesson on GitHub.

  • 07

    Episode 7 Run Time 5:43

    I'm a big fan of making the process of writing tests as natural as humanly possible. The harder it is to construct a test, the more likely it is that you simply...won't. With that in mind, let's extract a few helpers and snippets to assist us.

    View the source for this lesson on GitHub.

  • 08

    Episode 8 Run Time 7:54

    Now that our endpoint tests are returning green, we can construct the HTML form to publish a new thread. However, in the process, we'll stumble upon an odd exception handling issue that needs to be addressed. Luckily, Adam Wathan has a useful solution that we can implement.

    View the source code for this lesson on GitHub.

  • 09

    Episode 9 Run Time 14:12

    Right now, all threads are thrown into the same "global" namespace, so to speak. Ideally, we should assign each thread to a channel. That way, for a development forum, we may easily filter threads by PHP, or JavaScript, or Servers.

    View the source for this lesson on GitHub.

  • 10

    Episode 10 Run Time 10:41

    We haven't written any validation logic yet for our forum. This means that a user could whip up a request with all sorts of invalid data, and we'd gladly persist it to the database. Let's fix that in this episode, while writing tests to ensure that everything functions as we expect.

    View the source for this episode on GitHub.

  • 11

    Episode 11 Run Time 13:25

    Now that we've associated all threads with a channel, we can now perform the necessary UI updates to allow users to filter threads by their desired channel.

    View the source for this lesson on GitHub.

  • 12

    Episode 12 Run Time 8:24

    In this episode, we need to do a bit of work on the "create thread" page. We'll first add a link to the navigation bar, and then move on to tweaking the form, itself. Specifically, we should provide validation error feedback, and ensure that any text that the user types into the form's various fields will be remembered if a validation error is triggered.

  • 13

    Episode 13 Run Time 3:00

    Currently, we have two different SQL queries for fetching all channels directly in our view layer. Let's fix that by extracting a dedicated view composer.

  • 14

    Episode 14 Run Time 7:37

    It would be nice if any user could have a link that displays only the threads that they've personally created. Even beyond that, why not allow for the ability to view any forum user's threads? Let's figure out how in this episode.

    View the source code for this lesson on GitHub.

  • 15

    Episode 15 Run Time 18:47

    Since it seems that filtering will be an important component to our application, let's take a bit of time to perform some refactoring. Luckily, because we have a set of tests to back us up every step of the way, we can be as bold as we wish. There's no fear of breaking the app, if your tests will notify you the second you make a refactoring error.

    View the source code for this episode on GitHub.

  • 16

    Episode 16 Run Time 9:19

    We should add a sidebar to each thread page for various meta information, such as when the thread was published, how many replies it has, and more. Further, we've yet to add pagination to our app. What happens when a thread has over one hundred replies? Let's ensure that we put the proper pagination links in place.

    View the source code for this episode on GitHub.

  • 17

    Episode 17 Run Time 11:51

    It would be nice if users had the ability to filter all threads by popularity. That way, the most active threads will bubble to the top of the stack. Let's write a test and then implement this very feature.

    View the source code for this lesson on GitHub.

  • 18

    Episode 18 Run Time 15:46

    It would be useful if authenticated users could have the ability to "favorite" any reply within a thread. Let's begin implementing that functionality now, by using polymorphic relations.

    View the source code for this episode on GitHub.

  • 19

    Episode 19 Run Time 7:37

    Now that we've tested the full process of favoriting a reply, we can move on to creating the form to process this action for the user. In the process, we'll begin discussing the N+1 problem.

  • 20

    Episode 20 Run Time 7:06

    Let's review the N+1 problem, as it relates to Eloquent. To do so, we'll install Laravel Debugbar so that we can analyze the exact SQL queries that are being executed for each page load. As you'll learn, there are a variety of simple steps we can follow to reduce our query count by the dozens.

  • 21

    Episode 21 Run Time 8:28

    In this episode, we'll continue optimizing our SQL queries. Specifically, we'll review global Eloquent scopes and the useful $with property to automatically eager load any necessary relationships.

    View the source code for this lesson on GitHub.

  • 22

    Episode 22 Run Time 12:32

    It would be useful if every user in our forum had an associated profile page. That way, we can review more information about them, including all threads that they've personally created.

    View the source for this episode on GitHub.

  • 23

    Episode 23 Run Time 14:07

    One simple ability that we haven't yet implemented is the option to delete threads. If "John Doe" creates a thread and later changes his mind, let's allow him to delete it entirely.

  • 24

    Episode 24 Run Time 10:28

    We must be careful that we don't inadvertently give any registered forum user the ability to delete all threads. Let's create a policy class to ensure that this can't happen.

    View the the source code for this episode on GitHub.

  • 25

    Episode 25 Run Time 16:37

    In this episode, we'll use TDD to drive out an activity feed. That way, we can, for example, track when a user creates a new forum thread, or posts a reply. As always, we'll begin with the most basic possible implementation. Once we get to green, we can then move on to the refactoring stage to clean things up drastically.

    View the source code for this episode on GitHub.

  • 26

    Episode 26 Run Time 16:21

    Now that we've written the necessary code to record all relevant activity, in this episode, we can render it onto the user's profile page, and group all relevant records according to their date.

    View the source code for this episode on GitHub.

  • 27

    Episode 27 Run Time 7:39

    At the moment, we have a long, fluent Eloquent query in our controller. Instead, let's use TDD to extract it into the Activity model.

    View the source code for this episode on GitHub.

  • 28

    Episode 28 Run Time 5:10

    I think we have a bug in our activity feed. What happens if we delete a thread? Will that cascade and delete all relevant activity in the process? And, if not, what happens when we try to view the user's profile page? Hmm, let's write a regression test to find out.

    View the source code for this episode on GitHub.

  • 29

    Episode 29 Run Time 13:59

    In this episode, we'll implement an elegant flash messaging system, using Vue. That way, when a user performs an important action, we can flash a quick message to indicate the outcome.

    View the source code for this episode on GitHub.

  • 30

    Episode 30 Run Time 6:06

    At the moment, a user's activity feed will exclusively display a timeline of their own threads and replies. Let's extend that in this episode to include any replies that they've favorited.

    View the source code for this episode on GitHub.

  • 31

    Episode 31 Run Time 7:59

    We're still missing a very basic piece of functionality. Any authorized user should be able to delete a reply. Let's implement that in this episode.

    View the source code for this episode on GitHub.

  • 32

    Episode 32 Run Time 13:51

    We're starting to realize that each individual forum reply should have a decent amount of behavior associated with it. With that in mind, in this episode we'll create a dedicated Vue component for a reply, and then implement the necessary functionality to quickly edit the body of a reply without requiring a page refresh.

    View the source code for this episode on GitHub.

  • 33

    Episode 33 Run Time 4:22

    Now that each reply is wrapped within a dedicated Vue instance, we can easily swap out the traditional form for deleting the reply with a snappier AJAX version that doesn't require a page refresh.

    View the source code for this episode on GitHub.

  • 34

    Episode 34 Run Time 16:28

    We have one last piece of the puzzle, when it comes to our Reply component. The favoriting functionality still consists of a traditional form. Let's turn that into a dedicated Favorite component to clean things up.

    View the source code for this episode on GitHub.

  • 35

    Episode 35 Run Time 8:31

    I think we've introduced a couple of bugs related to adding and removing activity. Let's work through them in this episode and patch things up, before moving on to a new feature.

    View the source code for this episode on GitHub.

  • 36

    Episode 36 Run Time 21:59

    In this episode, we'll do a decent amount of refactoring to push toward a more data-centric approach, when it comes to our Vue components. As part of this refactor, we'll need to figure out how to rewrite inline-templates that use Blade into JavaScript.

  • 37

    Episode 37 Run Time 11:44

    Now that we're thinking in terms of Vue collections, we can easily turn the form for publishing a new reply into its own component. This way, when the user submits the form, we can simply perform an AJAX call to persist the data, and then push to the "replies" collection - which will, in response, automatically trigger a re-render.

    View the source code for this episode on GitHub.

  • 38

    Episode 38 Run Time 31:02

    Since we're now rendering all replies with JavaScript, we can no longer depend upon rendering pagination links on the server-side. To compensate, let's create a dedicated paginator Vue component to handle all the necessary logic behavior.

    View the source code for this episode on GitHub.

  • 39

    Episode 39 Run Time 12:52

    I've learned from running the Laracasts forum that users often want to filter all threads according to those that have not yet received replies. Let's add that very functionality in this episode.

    View the source code for this episode on GitHub.

  • 40

    Episode 40 Run Time 10:53

    It would be useful if users could subscribe to any number of threads in our forum. That way, each time a reply is left, the user will immediately be notified. Let's get started implementing this very functionality.

  • 41

    Episode 41 Run Time 6:17

    Now that our model tests prove that users can properly subscribe to threads, let's move up a level and right the general feature that describes what should happen when a particular endpoint is triggered.

  • 42

    Episode 42 Run Time 15:12

    Let's take a bit of time to work on the UI side of things. We need to prepare a "Subscribe" Vue component that handles the behavior of toggling the current user's subscription to any given thread.

    View the source code for this episode on GitHub.

  • 43

    Episode 43 Run Time 25:30

    Now that a thread exposes the behavior that it can be subscribed to, we can move on to preparing all relevant user notifications each time the thread receives a new reply. To allow for this, we'll leverage Laravel's native notification functionality.

  • 44

    Episode 44 Run Time 6:15

    Let's take a few moments to refactor the tests in our NotificationsTest class. A handful of tweaks should make this file far more simple to read and understand six months from now.

  • 45

    Episode 45 Run Time 13:22

    We can finally switch over to the client-side, and begin constructing a user-notifications Vue component that will be responsible for fetching all relevant notifications and rendering them within a "bell" dropdown panel.

    View the source code for this episode on GitHub.

  • 46

    Episode 46 Run Time 10:25

    Let's perform a round of refactoring in this episode. But there's a twist! At the conclusion of the refactor, we'll take a very important step. That step is to ask ourselves, "Is the code better as a result of this refactor? Or did we make it more confusing?"

  • 47

    Episode 47 Run Time 5:20

    If you check our ThreadTest class, you'll notice that we don't yet have a test that asserts that, each time a reply is added to a thread, a notification should be prepared for all thread subscribers. Let's use a notification fake to test this functionality.

    Review the source code for this episode on GitHub.

  • 48

    Episode 48 Run Time 15:54

    It would be useful if users could have a small visual cue that any given thread has been updated since they last read it. This indication could be as small as making the title of the thread bold in such instances. So how do we allow for this? Well, while there's countless ways to implement this, let's try using basic caching.

    View the source code for this episode on GitHub.

  • 49

    Episode 49 Run Time 11:08

    Spam is a sad reality of any successful forum, and we can't ignore it. In this episode, let's begin constructing a series of spam detectors. We'll start with basic keyword detection, but this will soon evolve to all sorts of inspections.

  • 50

    Episode 50 Run Time 8:52

    Rather than adding countless inspections to our single Spam class, instead, let's elevate each of these inspections to its own class. Then, our Spam class can simply filter through all registered inspections, and trigger them. Much cleaner!

    View the source code for this episode on GitHub.

  • 51

    Episode 51 Run Time 6:56

    At the moment, we only perform spam detection when the user writes a new reply. But what about when they update the reply, or post a new thread entirely? In this lesson, we'll review some options for performing spam detection for each of these actions.

  • 52

    Episode 52 Run Time 10:16

    At this point, our spam detection is working perfectly. However, our frontend still needs a few updates to properly translate any possible server exceptions into feedback for the user. Let's tackle that in this episode.

  • 53

    Episode 53 Run Time 7:20

    As we've implemented our spam detection layer, have you noticed that we've split the validation process into two steps? First, we trigger Laravel's built-in validators, then we apply our spam detection. What if we could create a custom validation rule instead and clean up our code in the process? Well, we can!

    View the source code for this episode on GitHub.

  • 54

    Episode 54 Run Time 15:10

    At the moment, any spammer can write a program to leave a forum reply every five seconds. Yikes! Let's at the very least limit users to no more than one reply per minute.

    View the source code for this episode on GitHub.

  • 55

    Episode 55 Run Time 12:03

    The RepliesController method that handles the submission of a new reply still feels a bit bloated to me. In this episode, we'll refactor it down to a single method call.

    View the source code for this episode on GitHub.

  • 56

    Episode 56 Run Time 9:28

    The next feature we need to implement is the ability for users to receive automatic notifications each time their username is mentioned within a thread. We'll get started in this episode by preparing the test, and then writing the least amount of code to get it to green.

  • 57

    Episode 57 Run Time 12:14

    Now that we're at green, we can begin refactoring our code. Let's use a basic eventing setup, now that we have multiple actions that need to take place each time a reply is posted.

    View the source code for these last two episode on GitHub.

  • 58

    Episode 58 Run Time 8:02

    An important part of your coding workflow involves file scanning. Yes, your code works. Yes, the tests pass. But, even so, take a third pass and scan all relevant files. Does anything jump out at you? Are there any small tweaks that might add more clarity? Should that variable be inlined? Can we reduce the number of queries over here?

    View the source code for this episode on GitHub.

  • 59

    Episode 59 Run Time 7:34

    Now that we can successfully notify mentioned usernames within a reply, let's begin updating the UI. First up, we'll match any usernames, and wrap them within anchor tags that link to their profile.

    View the source code for this episode on GitHub.

  • 60

    Episode 60 Run Time 13:19

    In this episode, we'll begin researching how to allow for GitHub-style instant @username autocompletion. During the research phase, we'll set up a brand new throw-away project to learn how it will work. Then, once we feel comfortable, in the next episode we'll integrate autocompletion into our forum.

  • 61

    Episode 61 Run Time 13:33

    Now that we understand how the At.js plugin works, we can begin integrating it into our forum. Let's get a working implementation setup in this episode.

    View the source code for this episode on GitHub.

  • 62

    Episode 62 Run Time 7:48

    Before we move on to a few more important new features, let's take some time to perform some smaller tweaks. For instance, on the thread listing page, we should display the author's name. Additionally, we aren't yet using pagination here. Let's fix both of those issues now.

    View the source code for this episode on GitHub.

  • 63

    Episode 63 Run Time 13:50

    We should next allow users to upload avatars for their profile. As always, let's take a test-driven approach to this task. As you'll find, Laravel offers a number of resources to make the process of testing file uploads incredibly easy.

  • 64

    Episode 64 Run Time 14:04

    Now that we've mostly driven out the backend side of things, let's shift our attention to the view layer. We should present a form to the user, so that they may choose an avatar to upload and associate with their profile.

  • 65

    Episode 65 Run Time 28:03

    If we'd like to use AJAX to update a user's profile image, we'll need to take a few somewhat tricky steps. Don't worry, it's not too rough. When we're done, we'll have seamless integration with instant feedback.

    View the source code for this episode on GitHub.

  • 66

    Episode 66 Run Time 14:49

    It would be useful if visitors could instantly see which threads are currently trending on our forum. An incredibly simple way to implement this is through sorted sets with Redis. Let's get started.

  • 67

    Episode 67 Run Time 12:14

    In this episode, we'll continue reviewing our trending threads in Redis logic. Could we possibly extract this code to a dedicated class? And if we did so, what benefits might we encounter as a result?

    View the source code for this episode on GitHub.

  • 68

    Episode 68 Run Time 9:10

    We next need to display the visits/views count for each thread on the page. If only for learning purposes, we'll review three different implementations - one per episode - while discussing the pros and cons for each. To begin, let's assume that the forum we're building will be incredibly popular. If so, we might consider using Redis to track and increment the views count each time the page is loaded. Let's get started.

  • 69

    Episode 69 Run Time 8:23

    In the previous episode, we successfully recorded the views count through a single trait, or concern. However, you may notice that the "visits" suffix is referenced in a number of method names. When you encounter repeated keywords, often it's an indication that a class is requesting to be extracted. Let's tackle that very thing in this episode, and then review the before and after.

  • 70

    Episode 70 Run Time 7:50

    Finally, we've made it to our third and final design choice: KISS. A vital skill for all web developers is to understand when certain optimizations and refactors are necessary, and when it simply doesn't matter. In the case of this particular feature, would it be easier if we simply added a "visits" column to our threads table? Yes, we'd need to increment this count each time a thread is read, but is that necessarily a problem? Are we anticipating a scale and level of traffic that demands such an optimization? If not, keep it simple.

    View the source code for this episode on GitHub.

  • 71

    Episode 71 Run Time 9:46

    If spam is a significant concern, one option is to force all forum users to first confirm their email address before we grant access to publish new threads. Typically, spammers will enter gibberish email addresses during the sign up process. With this modification, a real email address will be required.

    View the source code for this episode on GitHub.

  • 72

    Episode 72 Run Time 23:06

    Now that we have the proper protections in place, we can move on to the next step: sending all new users an email confirmation request upon registration. Once they click back to our website through this link, we can mark their account as confirmed, and they may then begin posting to the forum.

  • 73

    Episode 73 Run Time 15:16

    At this point, everything appears to be working properly. So let's take this episode to simplify a few sections, remove the event listener approach, and clean up our code.

    View the source code for this episode on GitHub.

  • 74

    Episode 74 Run Time 8:02

    Well, we thought we were finished with the email confirmation feature, but, after a second glance, I think we have a few more loose ends to wrap up. In this episode, we'll do a small bit of refactoring, while also ensuring that the generated email token is more unique and will be deleted upon confirmation.

    View the source code for this episode on GitHub.

  • 75

    Episode 75 Run Time 7:25

    So far we've been using the id of each thread as the URI identifier. However, in many cases, regardless of the app you're building, you may not want to expose your primary keys in this way. Instead, let's switch over to a slug-based approach.

  • 76

    Episode 76 Run Time 11:44

    At this point, we are generating slugs for each new thread; however, what happens if multiple threads have the same title? Everything will blow up, that's what! It sounds like we need to detect existing slugs in the database, and apply an increment to the slug.

    View the source code for this episode on GitHub.

  • 77

    Episode 77 Run Time 13:29

    Now that we're properly generating incrementing slugs for threads that have the same title, we should take note of a few edge cases that could break things. If we find a bug along the way, we'll write a regression test to reproduce it, and then refactor as needed to return everything to green.

    View the source code for this episode on GitHub.

  • 78

    Episode 78 Run Time 14:17

    Our next feature to implement is one that allows the creator of a thread to mark any reply as the best answer. Let's begin by implementing the underlying server-side logic. Once complete, in the following episode, we can move on to the front-end side of things.

  • 79

    Episode 79 Run Time 7:57

    Our tests are showing that everything from the AJAX endpoint and forward should work as expected; however, we haven't yet touched the front-end side of this feature. Let's begin writing the necessary Vue logic to allow the thread's creator to mark any reply as "best."

  • 80

    Episode 80 Run Time 6:08

    We still need to finish up the "Best Reply" feature, but let's take a quick break to refactor our authorization setup. Things are beginning to get messy, and I worry that this authorization logic could grow to be split between countless files. In this episode, let's experiment with creating a dedicated authorization module.

  • 81

    Episode 81 Run Time 10:48

    Let's return to the client-side, and add the necessary logic to submit an AJAX request when the owner of a thread marks a new reply as "best." As you'll see, we'll need to review a couple different options for toggling state.

  • 82

    Episode 82 Run Time 11:08

    What happens if a "best reply" is deleted by its owner? Shouldn't we update the owning thread to nullify the best_reply_id column? Otherwise, that column will refer to a reply that doesn't exist. In this episode, we'll add a database constraint to perform this update automatically. However, as we implement it, we'll encounter a few confusing issues that aren't so easy to debug.

    View the source code for this episode on GitHub.

  • 83

    Episode 83 Run Time 6:40

    At the moment, everyone - even guests - can see the button to mark a "Best Reply." Now we do have protection on the backend, but we should certainly hide this button for all users who aren't the creator of the thread. Let's tackle that in this episode, before moving on to something new.

    View the source code for this episode on GitHub.

  • 84

    Episode 84 Run Time 8:00

    Next up, we need to begin adding the ability to lock any forum thread. Whether a conversation veers far off course, or the administrator simply wants to respond to a thread and then close it, this is a common feature for any forum. Let's get started implementing it with TDD.

    View the source code for this episode on GitHub.

  • 85

    Episode 85 Run Time 16:10

    Let's continue fleshing out the routes and controllers that our front-end will expect for this feature. In this episode, we'll review two endpoint approaches for updating a thread's "locked" status.

    View the source code for this episode on GitHub.

  • 86

    Episode 86 Run Time 11:16

    Now that we have the server-side endpoints fully tested, let's switch to the front-end and write the necessary Vue code to allow administrators to toggle a thread's "locked" status.

  • 87

    Episode 87 Run Time 11:58

    The basic UI functionality is in place. At this point, we only need to send the appropriate AJAX requests to toggle the "locked" column within the threads table.

    View the source code for this episode on GitHub.

  • 88

    Episode 88 Run Time 9:30

    Let's allocate some time in this episode to upgrade our Laravel installation from version 5.4 to 5.5. As you'll see, because we have a full suite of tests to back us up, we can perform this upgrade with incredible confidence.

    View the source code for this episode on GitHub.

  • 89

    Episode 89 Run Time 9:32

    If we'd like to add a second layer of spam protection, we could implement reCAPTCHA. Luckily, the basic process is rather easy. In this episode, we'll get everything to work as quickly as possible. Then, in the following lesson, we can do a bit of refactoring to clean things up.

    View the source code for this episode on GitHub.

  • 90

    Episode 90 Run Time 12:50

    Now that we have reCAPTCHA working for our forum, let's take a few minutes to clean things up. I wonder if we can extract that reCAPTCHA API call to a custom validation rule. Now that we're running Laravel 5.5, this should be a cinch!

    View the source code for this episode on GitHub.

  • 91

    Episode 91 Run Time 13:34

    Amazingly enough, we've managed to get this far without adding the ability to edit an existing thread. Before moving on to implementing search, let's knock this out quickly.

    View the source code for this episode on GitHub.

  • 92

    Episode 92 Run Time 12:43

    Now that we have the server side implementation fully under test, we can switch over to the front-end and write the necessary Vue code to toggle the display for editing a thread.

  • 93

    Episode 93 Run Time 15:21

    Everything is looking good for this feature, so the only remaining step is to handle the AJAX request for updating the thread. Along the way, we'll encounter a few small edge cases that should be addressed.

    View the source code for this episode on GitHub.

  • 94

    Episode 94 Run Time 9:06

    It's time to add first-class search to our little forum. Let's begin in this episode with a quick review of Laravel Scout and Algolia.

  • 95

    Episode 95 Run Time 18:10

    Now that we have both Scout and Algolia ready to go, let's implement search into our forum. Along the way, we'll review a few gotchas and roadblocks related to feature testing code that will hit an external API like Algolia's.

    View the source code for this episode on GitHub.

  • 96

    Episode 96 Run Time 5:00

    At this point, we have a fully functional search system in place. However, it might be nice to offer more interactive results. What if the user could instantly filter all search results according to a given facet, such as a tag or channel name? Let's begin preparing for such a thing in this episode.

  • 97

    Episode 97 Run Time 11:50

    In this episode, you'll learn how to display live search results for our forum on the page. We can even integrate the channel facet to provide on-the-fly filtering.

  • 98

    Episode 98 Run Time 11:02

    Now that we have a solid understanding of how to work Algolia and the Vue-InstantSearch plugin, let's fully integrate it into our forum.

    View the source code for this episode on GitHub.

  • 99

    Episode 99 Run Time 15:28

    At the moment, we're using a basic textarea for the body of each forum thread or reply. Let's upgrade these inputs to powerful WYSIWYG text editors, using Trix.

  • 100

    Episode 100 Run Time 12:12

    Let's continue on with our Trix editor implementation. There are a few more places where we'll need to replace a standard textarea with the new wysiwyg component. Along the way, we'll also discuss how a Vue child component can listen and respond to an event on its parent.

  • 101

    Episode 101 Run Time 19:29

    When building web applications, always assume that the user is malicious. As such, any time you accept and display user input, sanitize it first. Think of this as the equivalent of throwing their input into a sink filled with soapy water. The goal is to clean that HTML as best as we can. Scrub it down in preparation for display. Script tag? Sorry, but no. Inline styles? See ya. Click event handlers? Hell no.

    View the source code for this episode on GitHub.

  • 102

    Episode 102 Run Time 1:58

    This series has easily been the most in depth course Laracasts has ever released, but the reality is there's so much more to do. As such, let's migrate the end result of all our work to a brand new series that'll pick up right where we left off: "How to Manage an Open Source Project."

You May Also Enjoy...

Here are some additional series that may be up your alley.

7 Lessons
2:36:09 hrs
10 Lessons
1:59:19 hrs
8 Lessons
1:05:34 hrs
27 Lessons
5:43:35 hrs
5 Lessons
58:10 mins
12 Lessons
2:30:07 hrs
16 Lessons
2:11:21 hrs
19 Lessons
2:47:33 hrs
7 Lessons
28:25 mins
4 Lessons
50:20 mins
8 Lessons
1:43:02 hrs
5 Lessons
57:12 mins
18 Lessons
3:53:32 hrs
18 Lessons
3:26:05 hrs
18 Lessons
2:43:50 hrs
10 Lessons
32:17 mins

PHP Bits

7 Lessons
26:30 mins
7 Lessons
26:30 mins
20 Lessons
1:31:44 hrs