Introducing Gravatar Avatars0:00
Okay, let's take a look at adding avatars for our users. I'm going to be making use of Gravatar here, since that's what the Laracast forum is using. So if you take a look at the Laracast forum, and if you take a look at an image, for example, this one, you'll see the Gravatar URL here. So if you're not familiar with Gravatar, it's a service that many sites use for a globally recognized avatar. So you upload your avatar image on the site, associate it with your email address, and you're good to go. So to use it on any third-party site, you just have to hash the user's email and put
Adding Avatar to User1:02
So we can get rid of this. And for now, let me just paste in this URL and make sure this is the correct place. Okay. So we can just do it in here and do some string manipulation, but I'm going to put it on the User model. So let's go to that. And I'm going to make a new method here called getAvatar. Okay. And let's just return that string for now. Okay.
And let's just return that string for now. Okay. And let's use this method in our Blade here. So we have the user, and that comes from the idea. So we can do idea->user->getAvatar(). Okay. Let's try that. And it should be the same thing. But now it's on the User model. Sorry, it should be a method.
But now it's on the User model. Sorry, it should be a method. Okay. So you can also make it an accessor if you want to call it like this, like this, just like you would normally. And we have to change this to an accessor. So that would be getAvatarAttribute, I believe. And I believe that should work now. Okay. But personally, I like leaving it as a method, because when I see this, then that indicates
Okay. But personally, I like leaving it as a method, because when I see this, then that indicates to me that it's a column on the database. And in this case, it's not. So when I see it as a method, I know it's sort of like a computed property. So let's change it back. It doesn't really matter. It's up to you. Just my personal preference. So now let's replace this hash with the actual user's hash email hash.
Hashing Email for Gravatar2:42
Just my personal preference. So now let's replace this hash with the actual user's email hash. So I'm going to put this on its own line. And append the actual user's hash. So let's put this like this md5 is a method on php, and we are in the User model. So we can just grab the user's email like this, and that should work. So let's give this a try. And it does work. But we are getting default images now. So for example, if I change the email address of this Idea, then it should show my avatar.
But we are getting default images now. So for example, if I change the email address of this Idea, then it should show my avatar. So let me change that in the database. So that's the first Idea, and that's userId one. So let me just change this one. Okay. And there it is. Now, if you look here, you can actually define a URL for default images. And you can do that with the default query string. Where is it?
And you can do that with the default query string. Where is it? Right here. Default image. You can either use D or default. And as you saw above, you can even specify the size. So let's add those. So let's say size here. So let's say question mark size equals I'll make it 200. And let's specify a default image.
So let's say $size equals 200. And let's specify a default image. So what is that going to be? Let's add that first. And let's say $d equals URL here. Now, Gravatar has a few defaults that you can choose from down here. For example, mp is mystery person. So we can do that for now. And that should be the new default. So let's try that out.
Setting Default Avatar Images5:42
How about we generate a random integer and then just use one of these images as the default image? So let's do that. So let's just say $randomInteger equals rand(1, 36), because those are the bounds. And I'm just going to paste in the URL here, that same URL that I just showed you. And now we can append this $randomInteger. And it's a .png. So let's add that as well. So .png. Okay.
And we do. So every time I refresh, we get random images. But if the actual email exists, then we get the correct Gravatar image. So that's fine. But like you just saw, this image changes after each new request. So for example, if I click into this, actually, we have to add this as well. This is still using the Unsplash API. So let's add this in our show.blade.php. So I'm going to grab this. I'm going to go to show.blade.php.
So I'm going to grab this. I'm going to go to show.blade.php. So for that image, it is. And let's grab this. Actually, this is a Comment. Sorry, it should be up here. This one. Okay, let's add this. Okay. So it should be an avatar or a default Gravatar image.
Deterministic Default Avatar8:13
zero to nine. So that equals 36. And that's the bounds of these images here. So I wouldn't be surprised if Jeffrey is doing something similar. So let's go ahead and do that. So let's change our User model. So let's grab the user's first character in their email. So first character is this email, and we can just do 0. And now we have to change this letter to a number. So for example, like I just said, A is 1, B is 2, and so on and so forth.
And now we have to change this letter to a number. So for example, like I just said, A is one, B is two, and so on and so forth. So Z should be 26. And then zero should be 27. So how are we going to do that? So after a quick Google search, I came across this Stack Overflow thread. And we can make use of the ord function to return an ASCII value. So all we have to do is subtract 96. And that should give us what we want for characters. So let's tinker, php artisan tinker, and say ord, let's say A minus 96, and that should
And that should give us what we want for characters. So let's tinker, php artisan tinker, and say ORD, let's say A minus 96, and that should be 1, and it is. So B should be 2, Z should be 26. And we have to strtolower, to force lowercase, because it's a different number. So you can just do strtolower, and that should be correct. Okay, so for digits, I had to find the correct number, it's not 96. For example, 1 should be 28, let's start with 0, 0 should be 27. And I just tried a bunch of different numbers until it worked. So 21 is the correct digit.
And I just tried a bunch of different numbers until it worked. So 21 is the correct digit. So 27 and 9 should be 36. Okay, so let's go ahead and implement this. So we have two cases, we have the case when it's a character and when it's a number. So we can use the is_numeric function to check if it's a number. So first character, okay. And if it is, then let's make a new variable, integer, say integer to use instead of this random integer that we have. And that would be what we just did in php artisan tinker.
random integer that we have. And that would be what we just did in Tinker. So we can do this, okay. And this would be first character. And I believe isNumeric works on strings too, let's verify that. So say is, let me just clear this, isNumeric, say one as a string should be true. Okay. But if it's not a string, or sorry, if it's not a number, then it should be a letter. And we can do the other case should be 96. And now we can get rid of this random integer and use integer to use here.
Testing Avatar Generation11:49
Okay, let's see how we can test this. So for this feature in particular, it's pretty obvious when you look in the browser if it's not working correctly. So in my opinion, it wouldn't be the end of the world if you didn't test it. Let's go ahead and do that anyways. So I'm going to make it a unit test for now. So let's say php artisan make:test UserTest. And let's make it a unit test for now, like I said, okay, let's open that up. UserTest. And I'm going to change this use statement to the TestCase in Laravel, because I want
user test. And I'm going to change this use statement to the TestCase in Laravel, because I want to use factories. So this always holds me back for a second when my factories don't work, when I actually do write unit tests. So let's change this. And we don't need this anymore. Okay, so let's write a test here. So I'm just going to test the default image functionality. So let's do that.
So I'm just going to test the default image functionality. So let's do that. So say test, say User can generate Gravatar default image when no email found. That's a long name. But that's fine. Okay, so let's create a User here. UserFactory, create. And we can specify a name, say me, and an email. And for now, let's just say fake@email.com. Because this shouldn't exist in Gravatar, okay.
And for now, let's just say a fake email at fake@email.com. Because this shouldn't exist in Gravatar, okay. So that's our arrange step. Let's go ahead and act. So we want to grab the Gravatar URL. So we can just call that method that we made. So User::getAvatar(), okay. So that's our act step. And let's make sure to import User here. Okay.
And let's make sure to import User here. Okay. And let's just dd the Gravatar URL. Okay, and let's see what we get. So let's run this test. I forgot to use refresh database. So let's do that. Okay. Let's rerun that test. Okay, so we get this.
Let's rerun that test. Okay, so we get this. And notice how the number is one, because the email we used is an A at the first character. So that's what we're going to assert against. So let's do that. So this assertEquals. So I'm going to put it on its own line and paste it in. And the second param is the Gravatar URL. So let's change one thing here. And that's the hash.
So let's change one thing here. And that's the hash. So I want to append the MD5 hash. So let's do MD5. Actually, there should be a quote. There should be a quote, MD5 user email. Okay. Let's remove this. And let's give that a try. It should pass.
And let's give that a try. It should pass. Okay. It does. Let's make sure that if I change the emailAddress here, it should fail because there should be a two now. And we're asserting that it's one. Try it again. It does fail. And you see the diff here, one and two.
It does fail. And you see the diff here, one and two. Now we have 36 total cases here. And if you want to be extremely thorough, you can test against those 36 different cases. But for me, I'm just going to test the bounds. So A is the first one. And we can change the name to first character A. So Z would be the next one. So let's duplicate this. And first character Z. And we can test this email with a Z as the first character.
So I pasted in those cases. Let's run the entire file and everything passes. Now this is fine. But if you want to take it even a step further, you can actually make a request to the endpoint and make sure that image exists. So let me show you what I mean. So let's just do it for the first character here. So we can make use of the HTTP client to make a request. So let's say HTTP::get and the image or the URL is user::getAvatar(). Okay.
So let's say HTTP get and the image or the URL is user getAvatar. Okay. Let's import HTTP. And we have this response assertSuccessful method that we can use to make sure if it actually returns a successful response. So let's use that successful, sorry, not assertSuccessful response successful. There it is. And we can do this assertTrue response successful. And let's make sure to add a semicolon here. And let's go ahead and run this test.
So this should fail if I run the test again. And it does. Actually, no, it's failing because of the unit test portion. So let me just comment that out for now. So let's get rid of this for now. And let's rerun the test. And now you see that it's failing here because this image does not exist. So asserting that false is true, because this is returning false because the image does not exist on the actual server. So let me put that back.
This is just a simple explanation with no code.
I have the unit test portion and the network portion, but I'm okay with that. Do whatever you like or whatever makes you feel confident in your tests. So I'm just adding these here and one more for the nine. And let me just make sure that everything still works. Let's run the entire file. And now the tests do run slower because they're making network requests. But again, if that gives you more confidence, then go ahead and add those tests. So yeah, let's go ahead and make a Feature test instead. So we can do this again. It's not a unit test anymore.
So we can do this again. It's not a unit test anymore. It's a feature test. And I'm just going to call it GravatarTest because that makes more sense to me. Okay. And let's just put all of these methods in there. And we can also get rid of this unit test if you want, because it's no longer a unit test. So let's grab this. Let's go to GravatarTest.
So let's grab this. Let's go to Gravatar test. Let's paste it in here. Let's use refresh database. Okay. And import User. And I believe that should work. Let's give it a try. Run the entire file. We have to import HTTP.
Run the entire file. We have to import HTTP. Okay. Run it again. And everything is passing. So we can get rid of this unit test because we're not using that anymore. So let's delete this. And let's run our entire test suite. So I'm going to do it from the command line. php artisan test.
So I'm going to do it from the command line. php artisan test. Okay. And as you see, it took two seconds, but Laravel recently introduced parallel testing. So that will greatly decrease the time it takes to run your tests. So right now it's running pretty quick. So it shouldn't be too big of a difference. But as we write more tests, you'll see the difference. So to do that, we can just do php artisan test --parallel. Okay.
So to do that, we can just do php artisan test --parallel. Okay. Let's try that. And we have to add a new package here. So let's say yes. And you see it takes this much time. So let's run that again. So you can see it without the package installation. So yeah, not too big of a difference. Let's try it again.
So yeah, let's go ahead and make a commit here as we've done before. What is this? Episode 12. So let's git add, git commit, episode 12 Gravatar images. Okay.
