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".
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
BooksController.php
in app/Http/Controllers
1. Open 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
web.php
in the routes/
directory
1. Open 2. Update the route
Replace the books route with the following:
Route::get('/', 'BooksController@index');
Working with Models
Adding Seussology database
seussology-laravel.sql file
1. Download the2. Use Adminer to import the database to MTM6331 Laravel site
.env
file at the Laravel site root
3. Open 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
app/Http/Controllers/BooksController.php
1. Open 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
books.blade.php
in the resources/views
.
1. Open 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
web.php
in the routes
directory
1. Open 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
BooksController.php
in the app/Http/Controllers
directory
1. Open 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
book.blade.php
in the resources/view
directory
1. Open 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
Book.php
in the /app
directory
1. Open 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
BooksController.php
in the app/Http/Controllers
directory
1. Open 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
book.blade.php
in the resources/views
directory
1. Open 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.
web.php
in the routes/
directory
1. Open 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');
BooksController.php
in the app/Http/Controllers
directory
3. Open 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
BooksController.php
in the app/Http/Controllers
directory
3. Open 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]);
}
form.blade.php
in the resources/views
directory
7. Open 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
web.php
in the routes/
directory
1. Open 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
BooksController.php
in the app/Http/Controllers
directory
1. Open 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
Book.php
in the app/
directory
1. Open 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
web.php
in the routes/
directory
1. Open 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
BooksController.php
in the app/Http/Controllers
directory
1. Open edit
method
2. Add the 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
form.blade.php
in the resources/views
directory
1. Open 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
Book.php
in the app/
directory
1. Open category
method
2. Create a <?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');
}
BookController.php
in the app/Http/Controllers
directory
4. Open edit()
method
5. Update 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
]);
}
form.blade.php
in the resources/views
directory
6. Open 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.
web.php
in the routes
directory
1. Open 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');
BooksController.php
in the app/Http/Controllers/
3. Open update
method
4. Add the 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
web.php
from the routes
directory
1. Open 2. Add the delete route
Route::get('/delete/{id}', 'BooksController@delete');
BooksController.php
from the app/Http/Controllers
directory
3. Open delete()
method
4. Add the 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']]);
}