|

How To Create User Profiles In Your Application

How To Create User Profiles In Your Application

Most websites that allow a user to sign up and contribute information have a profile page for each user. This application is no different. In this tutorial what we want to do is allow users of the website to click on a user name in the browser, and see more information about that user on their profile page. We’ll setup a basic profile page feature with supporting test cases in our code to make sure it works well. As with the prior tutorials, we will let the results of running our tests direct us on what the next steps to take are when building out the profile page for our users.


Create a User Profile Test

Navigating to the Feature folder of our application, we can add a new Test Class named ProfilesTest. Then go ahead and add the boilerplate for a new test.
create user profile test class
create test class stub


Create The Test Pseudocode

  • Given we have a user in the application
  • When we visit the profile / their name
  • Then we should see their name on the page

Ok sounds reasonable enough. Let’s translate that into a test method and associated code.

Let’s start running the test, and letting the errors direct us on the next steps to take.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 947 ms, Memory: 8.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: GET http://localhost/profiles/Athena Zulauf

/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php:107
/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:326
/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:120
/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:345
/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:168
/home/vagrant/Code/forumio/tests/Feature/ProfilesTest.php:18

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

We are getting a NotFoundHttpException which of course means there is no route to support that request.


Add the necessary route

Open the web.php routes file, and let’s add the route we need as highlighted here. When a user makes a request to /profiles/the user, then the show() method of the ProfilesController should trigger.

Run the test again to see what the error is.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 960 ms, Memory: 8.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
ReflectionException: Class App\Http\Controllers\ProfilesController does not exist

The test gives an error that the ProfilesController does not exist. This does make sense of course, since we have not yet created the controller we need to support profiles.


Create A ProfilesController Class

We can quickly create a new controller with this snippet.

vagrant@homestead:~/Code/forumio$ php artisan make:controller ProfilesController
Controller created successfully.

Since we now have a ProfilesController in place, that error should be fixed in the test. Let’s test again.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 918 ms, Memory: 8.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
BadMethodCallException: Method [show] does not exist on [App\Http\Controllers\ProfilesController].

Now we are getting a BadMethodCallException. Makes sense of course, since there is no show() method on the controller.


Create a show() method

Now we can add the show() method to the ProfilesController class. Here we go:

The show method does exist now. It doesn’t do anything yet, but let’s run our test to see what the message is now.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 881 ms, Memory: 8.00MB

There was 1 failure:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
Failed asserting that '' contains "Forrest Treutel".

/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:236
/home/vagrant/Code/forumio/tests/Feature/ProfilesTest.php:19

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Looks like our good friend Forrest Treutel is not being seen on the page when we visit his profile. Let’s fix up that show() method to fix this error.


Create A View For User Profiles

The show.blade.php for profiles does not yet exist, so we need to create that. Just for grins, let’s confirm that with our test.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 861 ms, Memory: 8.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
InvalidArgumentException: View [profiles.show] not found.

Yep. The view profiles.show is not found. Let’s create that view.
create new view file

We’ll start with this basic markup.

Let’s give that test another whirl.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.26 seconds, Memory: 10.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
ErrorException: Undefined variable: profileUser (View: /home/vagrant/Code/forumio/resources/views/profiles/show.blade.php)

It looks like we have an undefined variable. We need to pass data to the view to fix this. To do this, we can update the show() method in the ProfilesController like so.

Now that we are sharing our variable, we can run the test to see if we fixed it.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_user_has_a_profile
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 911 ms, Memory: 8.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_a_user_has_a_profile
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\User].

So we fixed the previous error, but now we are getting a ModelNotFoundException. The reason is in how Route Model Binding is configured by default.


Configuring Route Model Binding Route Key

If we want the Model to make use of a slug, like we are doing here, then we need to configure the getRouteKeyName() method to support this. Go ahead and open up the User Model, and we can make this adjustment.

Once again, let’s run the test. Yahoo!! Look at that GREEN!
phpunit test passing

This means that if we were to visit a profile page in the Browser, it should actually work at this point. There just so happens to be a user in the system named “Tom” so let’s visit http://forum.io/profiles/tom and see what we get.
user profile page working in browser


Better Styling With Bootstrap

So we see the user name on the page, and we’re not exactly blown away by the design. The logic of the page works just fine, but we want to make things look a little more pleasing. We can update the show.blade.php view to something like this:

which gives a little nicer profile layout.
bootstrap page header example


Displaying Threads A User Has Created

One feature we would like to add is the ability to view all threads created by the user who’s profile you are viewing. In order to add this feature, we will once again build out a test first to support it. In the ProfilesTest class, we can add a new test method of test_profiles_display_all_threads_by_the_user(). Now let’s think of what we want the test to accomplish.

  • Given we have a user
  • Given we have a thread created by that user
  • When we visit their profile page
  • Then we should see their thread

Here is some test code that approximates these steps.

With our test in place we can trigger it to run and observe the results.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_profiles_display_all_threads_by_the_user
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 1.22 seconds, Memory: 10.00MB

There was 1 failure:

1) Tests\Feature\ProfilesTest::test_profiles_display_all_threads_by_the_user
Failed asserting that '(the html)' contains "Alias autem velit atque sit aspernatur.".

/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:236
/home/vagrant/Code/forumio/tests/Feature/ProfilesTest.php:29

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

The test is failing because the title of the thread is actually not appearing on the profile page. We need to build out the code that actually makes that happen. We can add this block of markup to show.blade.php to display the threads of the user.

Once again, we will run our test to see how it works.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_profiles_display_all_threads_by_the_user
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 835 ms, Memory: 10.00MB

There was 1 error:

1) Tests\Feature\ProfilesTest::test_profiles_display_all_threads_by_the_user
ErrorException: Invalid argument supplied for foreach() (View: /home/vagrant/Code/forumio/resources/views/profiles/show.blade.php)

The error is complaining of an invalid argument being passed to the foreach loop. Well, that makes sense actually since we did not yet create the threads relationship on the User Model. We can add that right now. Also note that we add the latest() method to the relation definition so that we we are viewing the user’s threads, the most recent threads appear at the top of the page.

Running our test shows that it is now passing.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_profiles_display_all_threads_by_the_user
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 892 ms, Memory: 10.00MB

OK (1 test, 2 assertions)

When we now visit our sample user Tom’s profile page at http://forum.io/profiles/tom, we do see a recent thread that he created! So it looks like viewing threads on the user’s profile page is now good to go.
viewing users threads on profile page


Paginating Threads On User Profile Page

As users spend more time posting threads on the application, they may amass hundreds and hundreds of threads created. We should paginate these on the profile page instead of trying to load all of them in one shot. This is easy to set up in the show() method of the ProfilesController, as well as the associated view file with a call to $threads->links().
Updating the controller

Updating the view

Now the pagination is working nicely. We set it to only 1 at this point just to demonstrate. Maybe you could bump it up to 20 or 30 in the real application.
pagination in laravel


Linking User Names To Their Profile Page

At this point the user names displayed in our view files do not link anywhere. Let’s update that so that users can click on a user name in the browser, and be brought to their profile page.

In show.blade.php you can swap instances of the first link with the second link.

In reply.blade.php you can swap you can swap instances of the first link with the second link.

Now all the instances of a user name in the browser link back to the user’s profile.


Making Use Of Named Routes

One other option you have in this case is to set up a named route if you like. This way you can use the named route in the href of your anchor tags of the view files. How does this work? Well first off, we need to assign a name to the route in question. We do this in our routes file with the example highlighted here. We are naming this route ‘profile’.

The nice thing about named routes is that you can continue to use the regular links as we have already configured. Additionally however, we can format our links using the name of the route like we see here.

In show.blade.php you can swap instances of the first link with the second link.

In reply.blade.php you can swap instances of the first link with the second link.


How To Create User Profiles In Your Application Summary

What a great tutorial we had here! There were a lot of steps to take in getting our profile page for users set up and working correctly. Thankfully, we took our time and got everything working nicely.