Build an online forum with Laravel — Create routes, views, controllers. Generate auth. Write test (Part 2)

Part 1 — Initial setup and database seeding is available here.



Routing and Controller

First create the route for viewing threads. Routes are defined in routes/web.php.

Route::get(‘/threads’, ‘ThreadController@index’);

The ThreadController is in app/Http/Controllers/ThreadController.php.

In that file return the latest threads:

class ThreadController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$threads = Thread::latest()->get();
return view('threads.index', compact('threads'));
}

‘Latest’ is a method that adds an order by to the timestamp. The full list of available methods is here.

Authentication

Next we’re going to add authentication to the application. This will also generate layout view files in the resources directory.

$ php artisan make:auth
Authentication scaffolding generated successfully.
Default authentication system generated by Laravel. Full post on authentication available here.

Solve random error

For some reason I got an error when firing up the server: The only supported ciphers are AES-128-CBC and AES-256-CBC (#9080). If you encounter this error run the below commands:

$ php artisan key:generate
$ php artisan config:clear
$ php artisan serve

Create Threads View

Next we’ll generate a file for the threads view

$ mkdir resources/views/threads
$ touch resources/views/threads/index.blade.php

That view will inherit from the layout template and render the threads data using the blade template engine:

@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Forum Threads</div>
                 <div class="panel-body">
@foreach($threads as $thread)
<article>
<h4>{{ $thread->title }}</h4>
<div class='body'>
{{ $thread->body }}
</div>
</article>
<hr>
@endforeach
</div>
</div>
</div>
</div>
</div>
@endsection

We can then view the threads after we fire up the server: http://localhost:8000/threads

Show Single Thread

Add the route to routes/web.php:

Route::get('/threads/{thread}', 'ThreadController@show');

Then in app/Http/Controllers/ThreadController.php

/**
* Display the specified resource.
*
* @param \App\Thread $thread
* @return \Illuminate\Http\Response
*/
public function show(Thread $thread)
{
return $thread;
}

Using Route Model Binding this will automatically render JSON when we visit http://localhost:8000/threads/1.

JSON response for single Thread

In order to render a view we can update the return value:

public function show(Thread $thread)
{
return view('threads.show', compact('thread'));
}

Markup is in resources/views/threads/show.blade.php:

@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">{{ $thread->title }} </div>
    <div class="panel-body">
{{ $thread->body }}
</div>
</div>
</div>
</div>
</div>
@endsection

Testing

For a Laravel 5.4 application, connection setting for our test database are in ./phpunit.xml.

<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>

We are going to use SQLite for the test database and our data will be stored in memory on our local machine.

To run tests use this command:

$ vendor/bin/phpunit

Then create a Threads test file in tests/Feature/ThreadsTest.php:

<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class ThreadsTest extends TestCase
{
use DatabaseMigrations;
    /** @test */
public function a_user_can_view_all_threads()
{
$thread = factory('App\Thread')->create();
$response = $this->get('/threads');
        $response->assertSee($thread->title);
}
    /** @test */
public function a_user_can_read_a_single_thread()
{
$thread = factory('App\Thread')->create();
$response = $this->get('/threads/' . $thread->id);
        $response->assertSee($thread->title);
}
}

Add Links

Adding links is very straightforward:

<a href='/threads/{{$thread->id}}'>{{ $thread->title }}</a>

Alternatively, you can add a method to the Thread model in app/Thread.php:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Thread extends Model
{
public function path()
{
return '/threads/' . $this->id;
}
}

Then to generate the path to the url you could do:

<a href='{{ $thread->path() }}'>{{ $thread->title }}</a>

Either way works!