Creating Seussology App - Part 2

Download Starter Files

So all students are starting from the same point. Download the Seussology Files.

Unzip the file and copy the public, resources, and routes folders replace the existing folders in your laravel project.

Working with Controllers

Creating controller

1. Open Command Line application

Open Local by Flywheel and start the MTM6331 Laravel site. Right click on the MTM6331 Laravel site in the Local Sites menu and select "Open Site SSH".

Open Site SSH

Now, your default command line application should be open to the Local by Flywheel virtual machine. All command must be entered in this command line window.

2. Use Artisan

Type and execute the following command in Local by Flywheel virtual machine command line window.

cd app
php artisan make:controller BooksController

After executing this command, you should find that the file BooksController.php was created in the app/Http/Controllers directory.

Important

Leave the Command Line Window open. We will use it again.

Adding a method to a controller

1. Open BooksController.php in app/Http/Controllers

2. Add index method

Add new method (function) to the BooksController class. The method will have the name index and return the books view.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
      return view('books');
    }
}

Updating Books Route

1. Open web.php in the routes/ directory

2. Update the route

Replace the books route with the following:

Route::get('/', 'BooksController@index');

Working with Models

Adding Seussology database

1. Download the seussology-laravel.sql file

2. Use Adminer to import the database to MTM6331 Laravel site

3. Open .env file at the Laravel site root

4. Update the Database Settings

Starting around line 9, we can find the database settings, which will look like this:

DB_CONNECTION=mysql
DB_HOST=192.168.95.100
DB_PORT=4035
DB_DATABASE=local
DB_USERNAME=root
DB_PASSWORD=root

From this list, DB_PORT and DB_DATABASE will need to be updated. DB_DATABASE should equal seussology and DB_PORT should equal the MySQL remote port number for your version of the MTM6331 Laravel site. That number can be found by going to Local by Flywheel, selecting the MTM6331 Laravel site, and clicking on the database tab.

Defining the Book Model

1. Go to Local by Flywheel virtual machine command line window

2. Enter the following command

php artisan make:model Book

After executing the command, we should find the file Book.php inside the app directory of our Laravel application.

Requesting the Books Data

1. Open app/Http/Controllers/BooksController.php

2. Import the Book Model

Add use App\Book after the namespace declaration.



 

namespace App\Http\Controllers;

use App\Book;

3. Request all the books from the database

To retrieve all the books, we will use the all() method from the Book Model. We will set the results of the query to the variable $books.

$books = BOOK::all();

The above line should be placed right before the return statement of the index() method



 



public function index ()
{
    $books = BOOK::all();
    return view('Books');
}

4. Send the books data to the view

Finally, we will send the data retrieved from the database to view. We do this by placing the $books variable inside an associative array, which itself is the second argument the view() method.

BookController.php














 



<?php

namespace App\Http\Controllers;

use App\Book;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('Books', ['books' => $books]);
    }
}

Replacing Static Content

1. Open books.blade.php in the resources/views.

2. Create a loop

We will create a loop using the @foreach directive around the book div:



 





 



@section('main')
    <main id="main" class="books">
        @foreach ($books as $book)
            <div class="book">
                <a class="book-image" href="/book">
                    <img src="http://www.seussville.com/media/assets/all-book-covers/1.jpg" alt="And to Think That I Saw It on Mulberry Street">
                </a>
            </div>
        @endforeach
    </main>
@endsection

4. Replace static content with $book data

Use the mustache syntax to insert the $book data in the appropriate spots.





 
 






@section('main')
    <main id="main" class="books">
        @foreach ($books as $book)
            <div class="book">
                <a class="book-image" href="/book/{{ $book['id'] }}">
                    <img src="{{ $book['book_image'] }}" alt="{{ $book['book_title'] }}">
                </a>
            </div>
        @endforeach
    </main>
@endsection

Working with Route Parameters

Updating the Route

1. Open web.php in the routes directory

2. Add the book route with parameter

Add a new route for /book with a parameter of id. Parameters are surrounded by curly braces. The route will point to the show() method of the BookController class.

Route::get('/book/{id}', 'BooksController@show');

Creating the Show Method

1. Open BooksController.php in the app/Http/Controllers directory

2. Add the new method

Create a new method in the BookController class with the name of show and it should take the parameter $id.










 
 
 
 


<?php
class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show($id)
    {

    }
 }

3. Request the desired book from the database

Use the find() method from the Book Model, passing the $id as the parameter, to get the desired book. Set results of to the variable $book.



 


public function show($id)
{
    $book = Book::find($id);
}

4. Return the book view with the book data

Return the book view, passing the $book variable inside of an associative array.




 


public function show($id)
{
    $book = Book::find($id);
    return view('book', ['book' => $book]);
}

Updating the Book View

1. Open book.blade.php in the resources/view directory

2. Replace the static content

Replace all the static content with the data receive from the database.

Note

Book quotes come from the quotes table, which we have not access yet.

@section('main')
<main id="main" class="details">
    <div class="details-controls">
    <a href="/edit/{{ $book['id'] }}" class="details-control"><i class="far fa-edit"></i></a>
    <a href="/delete/{{ $book['id'] }}" class="details-control"><i class="far fa-trash-alt"></i></a>
    </div>
    <div class="details-image">
        <img src="{{ $book['book_image'] }}" alt="{{ $book['book_title'] }}">
    </div>
    <div>
        <h2 class="details-title">{{ $book['book_title'] }}</h2>
        <p>{{ $book['book_description'] }}</p>
        <p>Published: {{ $book['book_year'] }}<br>
        Number of Pages: {{ $book['book_pages'] }}</p>
        <blockquote class="details-quote">
            <p>Stop telling such outlandish tales. Stop turning minnows into whales.</p>
        </blockquote>

        <blockquote class="details-quote">
            <p>For I had a story that no one could beat! And to think that I saw it on Mulberry Street!</p>
        </blockquote>
    </div>
</main>
@endsection

Working with Relationships

Defining the Model

1. Go to Local by Flywheel virtual machine command line window

2. Enter the following command

php artisan make:model Quote

After executing the command, we should find the file Quote.php inside the app directory of our Laravel application.

Defining the Relationship

1. Open Book.php in the /app directory

2. Create a new method

Inside the Book class, create a new method with the name quotes.









 
 
 
 


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    public function quotes ()
    {

    }
}

3. Define the relationship

Inside the quotes() method, return hasMany() method passing the path to the Quote model ('App\Quote') as the parameter.

Note

Because the hasMany() method is also part of the Book class, we will use the $this variable to call the hasMany() method.



 


public function quotes ()
{
    return $this->hasMany('App\Quote');
}

Querying with the Relationship

1. Open BooksController.php in the app/Http/Controllers directory

2. Request the quotes

Inside the show() method, request all of the quotes for the selected book by accessing the quotes method Book model. Save the results to the $quotes variable.




 



public function show ($id) 
{
    $book = Book::find($id);
    $quotes = Book::find($id)->quotes;
    return view('book', ['book' => $book]);
}

3. Send the quotes to the view

Add $quotes to the view by adding a new item the array.





 


public function show ($id) 
{
    $book = Book::find($id);
    $quotes = Book::find($id)->quotes;
    return view('book', ['book' => $book, 'quotes' => $quotes]);
}

Adding Quotes to View

1. Open book.blade.php in the resources/views directory

2. Replace the static quotes

Using the @foreach directive, replace the static quotes with the quotes data, stored in the $quotes variable.















 
 
 
 
 




@section('main')
<main id="main" class="details">
    <div class="details-controls">
    <a href="/edit/{{ $book['id'] }}" class="details-control"><i class="far fa-edit"></i></a>
    <a href="/delete/{{ $book['id'] }}" class="details-control"><i class="far fa-trash-alt"></i></a>
    </div>
    <div class="details-image">
        <img src="{{ $book['book_image'] }}" alt="{{ $book['book_title'] }}">
    </div>
    <div>
        <h2 class="details-title">{{ $book['book_title'] }}</h2>
        <p>{{ $book['book_description'] }}</p>
        <p>Published: {{ $book['book_year'] }}<br>
        Number of Pages: {{ $book['book_pages'] }}</p>
        @foreach ($quotes as $quote)
        <blockquote class="details-quote">
            <p>{{ $quote['quote'] }}</p>
        </blockquote>
        @endforeach
    </div>
</main>
@endsection

Working with New Data

Note

To keep things simple, the following example will NOT include any validation. However, in a real world form, you should ALWAYS include validation.

Using the Books Controller

Use the BooksController instead of the routes to handle the logic for New Book page.

1. Open web.php in the routes/ directory

2. Update the route for a new book

Replace the inline function with a call to the new() method in BooksController

Route::get('/new', 'BooksController@new');

3. Open BooksController.php in the app/Http/Controllers directory

4. Add the new method

Add a new method with the name new
























 
 
 
 



<?php

namespace App\Http\Controllers;

use App\Book;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        
    }

}

5. Return the form view

Return the form view inside the new() method, pass an array containing key title and the value New Book.



 



public function new ()
{
    return view('form', ['title' => 'Add Book']);
}

Creating categories dynamically

Replace the categories dropdown when a dynamic one by retrieving the categories from the database.

1. Go to Local by Flywheel virtual machine command line window

2. Enter the following command

php artisan make:model Category

3. Open BooksController.php in the app/Http/Controllers directory

4. Import the Category model

Add the following line belong the import the Category model






 


























<?php

namespace App\Http\Controllers;

use App\Book;
use App\Category;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        return view('form', ['title' => 'Add Book']);
    }

 }

5. Retrieve categories from database

Inside the new() method, use the Category model and the all() method to retrieve all the categories.



 



public function new ()
{
    $categories = Category::all();
    return view('form', ['title' => 'Add Book']);
}

6. Send categories to view

Add another item to data array being sent to the view that will hold that categories.




 


public function new ()
{
    $categories = Category::all();
    return view('form', ['title' => 'Add Book', 'categories' => $categories]);
}

7. Open form.blade.php in the resources/views directory

8. Update the select menu

Use $categories data select menu.

<select class="form-input" name="category_id">
    <option></option>
    @foreach ($categories as $category)
        <option value="{{ $category['id'] }}">{{ $category['category_name'] }}</option>
    @endforeach
</select>

Creating a Submission Route

1. Open web.php in the routes/ directory

2. Create a route for a new book submission

Create a route using the post() method and /new URL. It will point to the store() method in the BooksController.

Route::post('/new', 'BooksController@store');

Creating the store Method

1. Open BooksController.php in the app/Http/Controllers directory

2. Add the store method

Add a new method with the name store and the parameter Request $request.































 
 
 
 



<?php

namespace App\Http\Controllers;

use App\Book;
use App\Category;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        $categories = Category::all();
        return view('form', ['title' => 'Add Book', 'categories' => $categories]);
    }

    public function store (Request $request)
    {
        
    }

}

3. Insert the data into the database

Use the Book::create() method to insert the $request data into the database.



 


public function store (Request $request) 
{
    $book = Book::create($request->all());
}

4. Redirect to the edit page

Return the redirect() padding the "/edit/{$book['id']}" as a parameter.




 


public function store (Request $request) 
{
    $book = Book::create($request->all());
    return redirect("/edit/{$book['id']}");
}

Note

Submitting the form will fail because of security features build into Laravel.

Allowing for New Data

1. Open Book.php in the app/ directory

2. Add fillable inputs









 
 
 
 
 
 
 
 
 
 








<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    protected $fillable = [
        'book_title',
        'book_year',
        'book_pages',
        'book_image',
        'book_description',
        'category_id'
    ];

    public $timestamps = false;

    public function quotes()
    {
        return $this->hasMany('App\Quote');
    }
}

Note

Submitting the form will result in page not found because we have not defined the edit route yet.

Updating Existing Data

Creating an Edit Route

1. Open web.php in the routes/ directory

2. Update the route

Create the edit route with id parameter to the URI and point the route the edit() method of the BooksController.

Route::get('/edit/{id}', 'BooksController@edit');

Creating an Edit Method

1. Open BooksController.php in the app/Http/Controllers directory

2. Add the edit method

Add an edit() method with parameter of $id.





































 
 
 
 



<?php

namespace App\Http\Controllers;

use App\Book;
use App\Category;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        $categories = Category::all();
        return view('form', ['title' => 'Add Book', 'categories' => $categories]);
    }

    public function store (Request $request)
    {
        $book = Book::create($request->all());
        return redirect("/edit/{$book['id']}");
    }

    public function edit ($id)
    {
        
    }

}

3. Retrieve the book data

Use the Book::find() to get book data by $id.



 


public function edit ($id)
{
    $book = Book::find($id);
}

4. Return the form view

Return the form view passing the book data.




 


public function edit ($id)
{
    $book = Book::find($id);
    return view('form', ['book' => $book]);
}

Updating the Form View

1. Open form.blade.php in the resources/views directory

2. Update the form to accept data

Use the @isset and @endisset directive to check if the book data is available, and if so, add the appropriate book data to each input value.

Note

Replace each input with the appropriate one below.

<input class="form-input" type="text" name="book_title" 
value="@isset($book['book_title']){{ $book['book_title'] }}@endisset">
...
<input class="form-input" type="text" maxlength="4" name="book_year" 
value="@isset($book['book_year']){{ $book['book_year'] }}@endisset">
...
<input class="form-input" type="number" name="book_pages" 
value="@isset($book['book_pages']){{ $book['book_pages'] }}@endisset">
...
<input class="form-input" type="text" name="book_image" 
value="@isset($book['book_image']){{ $book['book_image'] }}@endisset">
...
<textarea class="form-input" name="book_description">
@isset($book['book_description']){{ $book['book_description'] }}@endisset
</textarea>

Note

Category has not been updated because we do not have the category data.

Retrieving the Book's Category

1. Open Book.php in the app/ directory

2. Create a category method

























 
 
 
 


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    protected $fillable = [
        'book_title',
        'book_year',
        'book_pages',
        'book_image',
        'book_description',
        'category_id'
    ];

    public $timestamps = false;

    public function quotes()
    {
        return $this->hasMany('App\Quote');
    }

    public function category()
    {
        
    }
}

3. Define the Relationship

Return the belongsTo() method passing the parameter 'App\Category'.



 


public function category()
{
    return $this->belongsTo('App\Category');
}

4. Open BookController.php in the app/Http/Controllers directory

5. Update edit() method

Update the edit method to retrieve the selected book's category as well as all categories. This will allow use to dynamically create the categories select menu. Send the category and categories data to the form view.




 
 
 
 
 
 
 
 


public function edit ($id)
{
    $book = Book::find($id);
    $category = Book::find($id)->category;
    $categories = Category::all();
    return view('form', [
        'title' => 'Edit Book',
        'book' => $book,
        'bookCategory' => $category,
        'categories' => $categories
    ]);
}

6. Open form.blade.php in the resources/views directory

7. Update the select menu

Use $bookCategory preselect the correct option.

<select class="form-input" name="category_id">
    <option></option>
    @foreach ($categories as $category)
        <option value="{{ $category['id'] }}"
            @isset($bookCategory)
                @if ($category['id'] === $bookCategory['id'])
                selected="selected"
                @endif
            @endisset
        >{{ $category['category_name'] }}</option>
    @endforeach
</select>

Updating the Book

Now, that we are displaying all of the book's data in the form, we do set up our application to process any change that we make to the data.

1. Open web.php in the routes directory

2. Add a new route

Add a new route using the post() method. The URL should be /edit/{id} and it should point to store() method of the BooksController

Route::post('/edit/{id}', 'BooksController@update');

3. Open BooksController.php in the app/Http/Controllers/

4. Add the update method

Create an the update method with two parameters, the request data Request $request and the Book $book data.


















































 
 
 
 




<?php

namespace App\Http\Controllers;

use App\Book;
use App\Category;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        $categories = Category::all();
        return view('form', ['title' => 'Add Book', 'categories' => $categories]);
    }

    public function store (Request $request)
    {
        $book = Book::create($request->all());
        return redirect("/edit/{$book['id']}");
    }

    public function edit ($id)
    {
        $book = Book::find($id);
        $category = Book::find($id)->category;
        $categories = Category::all();
        return view('form', [
            'title' => 'Edit Book',
            'book' => $book,
            'bookCategory' => $category,
            'categories' => $categories
        ]);
    }

    public function update (Request $request, $id)
    {
       
    }

 }

5. Update the data

Find the book using the $id and update the data with the $request using the update() method.



 


public function update (Request $request, Book $book)
{
    Book::find($id)->update($request->all());
}

6. Return the edit method

To display the edit book form again, return the edit() passing the $id. Use $this to access the method.




 


public function update (Request $request, Book $book)
{
    Book::find($id)->update($request->all());
    return $this->edit($id);
}

Deleting Existing Data

Deleting a Book

1. Open web.php from the routes directory

2. Add the delete route

Route::get('/delete/{id}', 'BooksController@delete');

3. Open BooksController.php from the app/Http/Controllers directory

4. Add the delete() method

Create the delete() method with the parameter $id
























































 
 
 
 


<?php

namespace App\Http\Controllers;

use App\Book;
use App\Category;

use Illuminate\Http\Request;

class BooksController extends Controller
{
    public function index ()
    {
        $books = Book::all();
        return view('books', ['books' => $books]);
    }

    public function show ($id)
    {
        $book = Book::find($id);
        $quotes = Book::find($id)->quotes;
        return view('book', ['book' => $book, 'quotes' => $quotes]);
    }

    public function new ()
    {
        $categories = Category::all();
        return view('form', ['title' => 'Add Book', 'categories' => $categories]);
    }

    public function store (Request $request)
    {
        $book = Book::create($request->all());
        return redirect("/edit/{$book['id']}");
    }

    public function edit ($id)
    {
        $book = Book::find($id);
        $category = Book::find($id)->category;
        $categories = Category::all();
        return view('form', [
            'title' => 'Edit Book',
            'book' => $book,
            'bookCategory' => $category,
            'categories' => $categories
        ]);
    }

    public function update (Request $request, $id)
    {
        Book::find($id)->update($request->all());
        return $this->edit($id);
    }

    public function delete ($id) 
    {
        
    }
 }

5. Find the book

Using Book::find find the selected book and save the data to the $book variable.



 


public function delete ($id) 
{
    $book = Book::find($id);
}

6. Delete the book

Delete the book using the delete() method of $book




 


public function delete ($id) 
{
    $book = Book::find($id);
    $book->delete();
}

7. Return the delete view

Return the delete view, passing the book title to the view.






 


public function delete ($id) 
{
    $book = Book::find($id);
    $book->delete();

    return view('delete', ['title' => $book['book_title']]);
}