The essential function of any web application framework is to take requests from a user and deliver responses, usually via HTTP(s). This means defining an application's routes is the first and most important project to tackle when learning a web framework; without routes, you have no ability to interact with the end user.
In this chapter we will examine routes in Laravel and show how to define them, how to point them to the code they should execute, and how to use Laravel's routing tools to handle a diverse array of routing needs.
Route Definitions
In a Laravel application, yhou will define your "web" routes in routes/web.php and your "API" routes in routes/api.php. Web routes are those hat will be visited by your end users; API routes are those for your API, if you have one, For now, we'll primaryly focus on the routes in routes/web.php.
In projects running versions of Laravel prior to 5.3, theere will be only one routes file, located at app/Http/routes.php
The simplest way to define a route is to match a path (e.g.,/)with a closure, as seen in Example 3-1.
Example 3-1. Basic route definition
//routes/web.php
Route::get('/', function(){
return 'Hello, World!';
});
What's a Closuer?
Closures are PHP's version of anonymous functions. A closure is a function that you can pass around as an object, assign to a variable, pass as a parameter to other functions and methods, or even serialize.
You've now defined that, if anyone visits / (the root of your domain), Laravel's router should run the closure defined there and return the result. Not tat we return our content and don't echo or print it.
A quick introduction to middleware
You might be wondoering, "Why an I returning 'Hello, World!' instead of echoing it?"
There are quite a few answers, but the simplest is that there are a lot of wrappers around Laravel's request and response cycle, including something called middleware. When your route closure or controller method is done, it's not time to send the output to the browser yet; returning the content allows it to contnue flowing though the response stack and the middleware before it is returned back to the user.
Many simple websites could be defined entirely within the web routes file.With a few simple GET routes combined with some templates as illustrated in Example 3-2, you can serve a classic website easily.
Example 3-2. Sample website
Route::get('/', function(){
return view('welcome');
});
Route::get('about', funciton(){
return view('about');
});
Route::get('products', function(){
return view('products');
});
Route::get('services', function (){
return view('service');
});
Static calls
If you have much experience developing PHP, you might be surprised to see static calls on the Route class. This is not actually a static method per se, but rather service location using Laravel's facades, which we'll cover in Chapter 11.
If you perfer to avoid facades, you can accomplish thes same definitions like this:
$router->get('/', function (){
return 'Hello, World!';
});
HTTP Methods
If you're not familiar with the idea of HTTP methods, read on in this chapter for more information, but for now, just know that every HTTP request has a "verb", or action, along with it. Laravel allows you to define your routes based on which verb was used; the most common are GET and POST, followed by PUT, DELETE, and PATCH.
Each mothod communicates a different thing to the server, and to yhour code, about the intentions of the caller.
Route Verbs
You might've noticed that we've been using Route::get in our route definitions. This means we're telling Laravel to only match for these routes when the HTTP request use the GET action. But what if it's a form POST, or maybe some JavaScript sending PUT or DELETE requests? There are a few other options for methods to call on a route definition, as illustrated in Example 3-3.
Example 3-3. Route verbs
Route::get('/', function(){
return 'Hello, World!';
});
Route::post('/', function () {});
Route::put('/', function (){});
Route::delete('/', function(){});
Route::any('/', function(){});
Route::match(['get','post'], '/', function(){});
Route Handling
As you've probably guessed, passing a closuer to the route definitiion is not the only way to teach it how to resolve a route. Closures are quick and simple, but the larger your application gets, the clumsier it becomes to put all of your routing logic in one file. Additionally, applications using route closures can't tacke advantage of Laravel's route caching (more on that later), which can shave up to hundreds of milliseconds off each request.
The other common option is to pass a controller name and method as a string in place of the closure, as in Example 3-4.
Example 3-4, Routes calling controller methods
Route:: get('/'. 'WelcomeController@index');
This is telling Laravel to pass requests to that path to the index() method of the App \Http\Controllers\WelcomeController controller. This metohd will be passed the same parameters and treated the same way as a closure you might've alternatively put in its place.
Route Parameters
If the route you're defining has parameters-segments in the URL structure that are variable-it's simple to define them in your route and pass them to your closure(see Example 3-5).
Example 3-5. Route parameters
Route::get('users/{id}/friends', function ($id){
//
});
The Naming Relationship Between Route parameters and Closuer/Controller Method Prarameters
As you can see in Example 3-5, it's most common to use the same names for your route parameters ({id}) and the method parameters they inject into your route definition (function ($id)). But is this necessary?
Unless you're using route/model binding, no. The only thing that defines which route parameter matches with which method parameter is their order (left to right), as you can see here:
Route::get('users'/{userId}/comments/{commentId}', function (
$thisIsActuallyTheUserId,
$thisisReallyTheCommentId
){
//
});
That having been said, just because you can make them differnet doesn;t mean you should. I recommend keeping them the same for the sake of future developers, who could get tripperd up by inconsistent naming.
You can also make your route parameters optional by including a question mark(?) after the parameter name, as illustrated in Example 3-6. In this case, you should also provide a default value for the route's corresponding variable.
Example 3-6. Opptional route parameters
Route::get('users/{id?}, function ($id = 'fallbackId'){
//
});
And you can use regular expressions (regexes) to define that a route should only match if a parameter meets particular requirements, as in Example 3-7.
Example 3-7. Regular expression route constraints
Route::get('users/{id}', function($id){
//
})-> where('id', '[0-9]+');
Route::get('users/{username}', function ($username){
//
}) -> where('username', '[A=Za-z]+');
Route::get('posts/{id}/{slug}', function ($id, $slug){
//
})-> where(['id'=> '[0-9]+', 'slug'=>'[A-Za-z]+'])';
As you've probably guessed, if you visit a path that matches a route string, but the regex doesn't match the parameter, it woun't be matched.since routes are matched top to bottom, users/abc would skip the first closure in Example 3-7, but it would be matched by the secound closure, so it would get routed there. On the other hand, posts/abc/123 wouldn't match nay of the closures, so it would returna 404 Not Found error.
Route Names
The simplest way to refer to these routes elsewhere in your application is just by their path. There's a url() helper to simplify that linking in your views, if you need it; see Example 3-8 for an example. The helper will prefix your route with the full donain of your site.
Exmaple 3-8. URL helper
< a href = "">
//outputs
However, Laravel also allows you to name each route, which enables you to refer to it without explicityl referencing the URL. This is helpful because it means you can give simple nkcknames to complex routes, and also becuase linking them by name means you don't have to rewrite your frontend links if the paths change(see Example 3-9)
Example 3-9. Defining route names
//Defining a route with anme in routes/web.php
Route::get('members/{id}', 'MembersController@show')->name('members.show');
//Link the route in a view using the route() helper
This example illustrates a few new concepts. First, we're using fluent route definition to add the name, by chaining the name() method after the get() method. This method allows us to name the route, giving it a short alias to make it easier to reference elsewhere.
Defining custom roeutes in Laravel 5.1
Fluent route definitions don't exist in Laravel 5.1. You'll need to instead pass an array to the second parameter of your route definition; check the Laravel docs to see more about how this works.
Here's Example 3-9 in Laravel 5.1:
Route::get('members/{id}', [
'as' => 'members.show',
'user' => 'Memberscontroller@show'
]);
In our example, we've named this route members.show; resourcePlural.action is a common convention within Laravel for route and view names.
Route Naming Conventions
You can anme your route anything you'd like, but the common conventiion is to use the plural of the resource name, then a period, then the action. So, here are the routes most common for a resource named photo:
photos.index
photos.create
photos.store
photos.edit
photos.update
photos.destroy
To learn more about these conventions, see "Resource Controllers" on page 41.
We also introduced the route() helper. Just like url(), it's intended to be used in views to simplify linking to a named route. If the route has no parameters. You can simply pass the route name: (route('members.index')) and receive a route string http://myapp.com/members/index). If it has parameters, pass them in as an array as teh second parameter like we did in this example.
In general, I recommend using route names instead of paths to refer to your routes, and therefore using the route() helper instread of the url() helper. Somethimes it can get a bit clumsy-for exmapel, if your're working with multiple subdomanins- but it provides an incredible level of flexiblity to later change the application's routing structure without major penality.
Passing Route Parameters to the route() Helper
When your route has parameters(e.g., users/{id}), you need to define thosse parameters when you're using the route() helper to generate a link to the route.
There are a few different way to pass thers parameters. Let's imagine a route defined as users/{userId}/comments/{commentId}. If the user ID is 1 and the comment ID is 2, let's look at a few options we have available to us:
Option 1:
route('users.comments.show', [1,2])
//http://mysqpp.com/users/1/comments/2
Option 2:
route('users.comments.show', ['userId' => 1, 'commentId' =>2]
//http://myapp.com/users/1/comments/2
Option 3:
route('users.comments.show', ['commentId' => 2, 'userId' => 1]
// http://myapp.com/users/1/comments/2
Option 4:
route('users.comments.show', ['userId' => 1, 'commentsId' =>2, 'opt'=>'a'])
//http://myapp.com/users/1/comments/2?opt=a
As you can see, nonkeyed array values are assigned in order; keyed array values are matched with the route parameters matching their keys, and anything left over is added as a query parameter.
Route Groups
Often a group of routes share a particular characteristic - a certain authentication requirement, a path prefix, or perhaps a controller namespace. Defining these shared characteristics again and again on each route not only seems tedious but also can muddy up the shape of your routes file and obscure some of the structures of your application
Route groups allow you to group serveral routes together, and apply any shared configuration settings once to the entire group, to reduce this duplication. Additionally, route groups are visual cues to future develpers ( and to your own brain) that these routes are grouped together.
To group two or more routes together, yo u"surround" the route definitions with a route group, as shwn in Example 3-10. Un reality, you're actually passing a closure to the group definition, and the grouped routes within that closure.
Example 3-10. Defining a route group
By default, a route group doesn't actually do anything. There's no difference between the group in Example 3-10 and separating a segment of your routes with code comments. The empty array that's the first parameter, however, allows you to pass a varierty of configuration settings that will apply to the entire route group.
Middleware
Probably the most common use for route groups is to apply middleware to a group of reoutes. We'll learn more about middleware in Chapter 10, but, among other things, they're what Laravel uses for authenticating users and restricting guest users from using certain parts of a site.
In Exmaple 3-11, we're createing a route group around the dashboard and account view and applying the auth middleware to both. In this example, it means users have to be logged in to the application to view the dashboard or the account page.
Example 3-11. Restricting a group of routes to logged-in users only
Route::group(['middleware' => 'auth'], function (){
Route::get('dashboard', function () }
return view('dashboard');
});
Route::get('account', function(){
return view('account');
});
});
Applying middleware in controllers
Ofter it's clearer and more direct to attach middleware to your reoutes in the controller instead of at the route definition. You can do this by calling the middleware() method in the constructor of your controller. The string your pass to the middleware() method is the name of the middleware, and you can optionally chain modifier methods (only() and except()) to define which methods will receive that middleware:
class DashbardController extends Controller
{
public function __construct()
{
$this- > middleware('auth');
$this -> middleware('admin-auth')
-> only('admin');
$this -> middleware('team-member')
-> except('admin');
}
}
Note that, if you're doing a lot of "only" and "except" customizations, that's ofter a sign that you should break out a new controller for the exceptional routes.
Path Prefixes
If you have a group of routes ghat share a segment of their path-For example, if your site's API is prefixed with /api - you can use route groups to simplify this structure(see Example 3-13).
Example 3-12. Prefixing a group of routes
Route::group(['prefix' => 'api'], function (){
Route::get('/', function(){
//Handles the path / api
});
Route::get('users', function() {
//Handles the path /api/users
});
});
Note that each prefixed group also has a /route that represents the root of the prefix - in Example 3-12 that's /api.
Subdomain Routing
Subdomain routing is the same as route prefixing, but it's scoped by subdomain instead of route prefix. There are two primary uses for this. First, you may want to present different sections of the application (or entirely different applications) to different subdomains. Example 3-13 show how you can achieve this.
Exampel 3-13. Subdomin routing
Route::group(['domain' => 'api.myapp.com'], function(){
Route::get('/', function(){
//
});
});
Second, you might want to set part of the subdomain as a parameter, as illustrated in Example 3-14. This is most often done in cases of multienancy (think Slack or Harverst, where each company gets its own subdomain, like tighten.slack.co).
Example 3-14. Parameterized subdomain routing
Route::grouop(['domain' => '{account}.myapp.com'], function (){
Route::get('/', function($account) {
//
});
Route::get('users/{id}', function ($account, $id){
//
});
});
Note that any parameters for the group get passed into the grouped routes' methods as the first parameter(s).
Namespace Prefixed
When you're grouping routes by subdomain or route prefix, it's likely their controllers have a similar PHP namespace. In the API example, all of the API routes' controllers might be under an API anmespace. By using the route group namespace prefix, as shown in Example 3-15, you can avoid long controller refeerences in groups like "API/ControllerA@index" and "API/ControllerB@index".
Example 3-15. Route group namespace prefixes
//App\Http\Controllers\ControllerA
Route::get('/', 'ControllerA@index');
Route::group(['namespace' => 'API']. function() {
// App\Http\Controllers\API\ControllerB
Route::get('api/', 'ControllerB@index');
});
Name Prefixes
The prefixes don't stop ther. It's common that route names will reflect the inheritance chain of path elements, so users/commments/5 will be served by a route named user.comments.show. In this case, it's common to user a route group around all of the routes that are beneath the users.comments resource.
Just like we can prefix URL segments and controller namespaces, we can aslo prefix strings to the route name. With route group name prefixes, we can define that every route within this group should have a given string prefixed to its name. In this context, we're prefixing "users." to each route name, then "comments." (see Example 3-16).
Example 3-16. Route group name prefixes
Route::group(['as' => 'users.', 'prefix' => 'users'], function(){
Route::group(['as' => 'comments.', 'prefix'=>comments'], function (){
//Route name will be users.comments.show
Route::get('{id};, fuinction (){
//
}) -> name('show');
});
});
Views
In a few of the route closures we've looked at so far, we've seen something along the lines of return view('account'). What's going on here?
If you're not familiar with the Model-View-Controller (MVC) pattern, views(or templates) are files that describe what some particular output should look like. You might have views for JSON or XML or emails, but the most common views in a web framework output HTML.
In Laravel, there are two formats of view you can use out of the box: plain PHP, or Blad templates (see Chapter 4). The difference is in the filename: about.php will be rendered with the PHP engine, and about.blade.php whill be rendered with the Blade engine.
Three ways to load a view()
There are three different ways to return a view. For now, just concern yourself with view(), but if you ever see View::make(), it's the same thisng, and you could also inject the Illuminate\View\ViewFactory if you prefer.
Once you've loaded a view, you have the option to simply return it (As in Example 3-17), which will work fine if the view doesn't rely on any variables from the controller.
Example 3-17. Simple view() usage
Route::get('/', function (){
return view('home');
});
This code looks for a view in resources/views/home/blade.php or resource/views/home/php, and loads its contents and parses any inline PHP or control structures until you have just the view's output. Once you return it, it's passed on to the rest of the response stack and eventualluy returned to the user.
But what if you need to pass in variables? Take a look at Example 3-18.
Example 3-18. Passing variables to views
Route::get('task', function (){
return view('tasks.index')
->with('task', Task::all());
});
This closure laods the resources/views/tasks/index.blade.php or resources/views/tasks/index.php view and passes it a single variable named tasks, which contains the reuslt of the Task::all() method. Task::All() is an Eloquent database query we'll learn about in Chapter 8.
Using View Composers to Share Variables with Every View
Sometimes it can become a hassle to pass the same variables over and voer. There may be a variable that you want accessible to every view in the site, or to a certain class of views or a certain included subview - for example, allviews related to tasks, or the header partial.
It's possible to share certain variables with every template or jeust certain templates, like in the following code:
view() -> share('variableName", 'variableValue');
To learn more, check out "View composers and Service Injectio" on Page64.
Controllers
I've mentioned controllers a few times, but until now most of the exmaples have shown reute closures. If you're not familiar with the MVC pattern(Figure 3-1), controlelrs are essentially clases that organize the logic of one or more routes together in on place. Controllers tend to group similar routes together, especically if your application is structured along a traditionally CRUD-like foramt: in this case, a controller might handle all the actions that can be performed on a particular resource.
What is CRUD?
CRUD stands for create, read, update, delete, which are the four primary operations that web applications most commonly provide on a resource. For example, you can create a new blog post, you can read that post, you can update it, or you can delete it.
It may be tempting to cram all of the applicationn's logic into the controllers, but it's better to think of controllers as the traffic cops that route HTTP requests around your applications. Since there are other ways requests can come into your application - cron jobs, Artisan command-line calls, queue jobs, etc. - it's wise to not rely on controllers for much behavior. This means a controller's primary job is to capture the intent of an HTTP request and pass it on to the rest of the application.
So, let's create a controller. One easy way to do this is with an Artisan command, so from the command line run the following:
php artisan make:controller TasksController
Artisan adn Artisan generators
Laravel comes bundled with a command-line tool called Artisan.
Artisan can be used to run migrations, create users and other database records manual, onetime tasks.
Under the make namespace, Artisan provides tools for generating skeleton files for a variery of system files. That's what allows us to
run php artisan make:controller.
To learn more about theis and toehr Artisan features, see Chapter 7.
This will create a new file named TasksController.php in app/Http/Controllers, with the contents shown in Example 3-19.
Example 3-19. Default generated controller
namespace App\Http\Controllers;
use Illuminate\Http\Reqeust;
use App\Http\Requests;
class TasksController extends Controller
{
}
Modify this file as shown in Example 3-20, creating a new public method called home(). We'll just return some text there.
Example 3-20. Simple controller example
use App\Http\Controllers\Controller;
class TasksController extends Controller
{
public function home()
{
return 'Hello, World!';
}
}
Then like we learned before, we'll hook up a route to it, as shown in Example 3-21.
Example 3-21. Route for the simple controller
// reoutes/web.php
Route::get('/', 'TasksController@home');
That's it. Visit the / route and you'll see the words "Hello, World!"
Controller Namespacing
In Example 3-21 we referenced a controller with the fully qualified class name of App \Http\Controllers\TasksController, but we only used the class name. This isn't because we can simply reference controllers by their class names. Rather, we can ignore the App\Http\Controllers\ when we refuerence controllers; by default, Laravel is configured to look for controllers within that namespace.
This means that if you have a controller with the fully qualified class name of App \Http\Controllers\API\ExercisesController, you'd reference it in a route definition as API\ExercisesController.
The most common use of a controller method, then, will be something like Example 3-22.
Example 3-22. Common controller method example.
//TasksController.php
....
public function index()
{
return view('tasks.index')
->with('tasks', Task::all());
}
This controller method loads the resourcs/views/tasks/index.blade.php or resources/views/tasks/index.php view and passe it a single variable named tasks, which contains the result of the Task::all() Eloquent method.
Generating resource controllers
If you ever use php artisan make:controller in Laravel prior to 5.3, you might be expecting it to autogenerate methods for all of the basic resource routes like create() and update(). You can bring this behavior back in Laravel 5.3 by passing the -- resource flag when you create the controller:
php artisan make:controller TasksController --resource
Getting User Input
The second most common action to perform in a controller method is to take input from the user and act on it. That introduces a few new concepts, so let's take a look at a bit of sample code and walk through the new pieces.
First. let's bind it quickly; see Example 3-23.
Example 3-23. Binding basic form actions
//routes/web.php
Route::get('tasks/create', 'TasksController@create');
Route::post('tasks', 'TasksController@store');
Notice that we're binding the GET action of tasks/create (which shows the form) and the POST action of tasks/ (which is where we POST when we're createing a new task). We can assume the create() method in our controller just shows a form, so let's look at the store() mtthod in Example 3-24.
Example 3.24. Common from input contrller method
// TaskController.php
....
public function store()
{
$task = new Task();
$task -> title = Input::get('title');
$task -> description = Input::get('description');
$task -> save();
return redirect('tasks');
}
This example makes use of Eloquent models and the redirect() functionality, and we'll talk agbout them more later, but you can see what we're doing here: we create a new Task, pull data out of the user input and set it on the task, save it, and then redirect back to the page that shows all task.
There are two main ways to get user input from a POST: the Input facade, which we used here, and the Request object, which we'll talk about next.
Importing facades
If you follow any of these examples, whether in controllers or any other PHP class that is namespaced, you might find errors showing that the facade cannot be found. This is because they're not present in every namespace, but rather they're made available the root namespace.
So, in Example 3-24, we'd need to import the Input facade at the top of the file, There are two ways to do that: either we can import \Input, or we can import Illuminate\Suppert\Facades\Input.
For example:
namespace App\Http\Controllers;
use Illuminate\Support\facades\Input;
class TaskController
{
public function store()
{
$task = new Task();
$task -> title = Input::get('title');
$task -> description = Input::get('description');
$task -> save();
return redirect('tasks');
}
As you can see, we can get the value of any user-provided information, whether from a query parameter or a POST value, using input::get('filedName'). So our user filled out two fields on the "add task" page:"title" and "description." We retrieve both using the Input facade, save them to the database, and then return.
Injecting Dependencies into Controllers
Laravel's facades paresent a simple interface to the most useful classes in Laravel's codebase. You can get information about the current request and user input, the session, caches, and much more.
But if you prefer to inject your dependencies, or if you want to use a service that doesn't have a facade, you'll need to find some way to bring instances of these classes into your controller.
This is our first exposure to Laravel's service container. For now, if this is unfamiliar you can think about it as a little bit of Laravel magic; or, if you want to know more about how it's actually functioning, you can skip ahead to Chapter 11.
All controller methods (including the constructors) are resolved out of Laravel's container, which means anything you typehint that the container knows how to resolve will be automatically injected.
As a nice example, what if you'd refer having an instance of the Request object instead of using the facade? Jest typehint Illuminate\Http\Request in your method parameters, like in Example 3-25.
Example 3-25. Controller method injecting via typehinting
//TasksController.php
.....
public function store(\Illuminate\Http\Request $request)
{
$task = new Task();
$task -> title = $request->input('title');
$task -> description = $request->input('description');
$task -> save();
return redirect('tasks');
}
So, you've defined a parameter that must be passed into the store() method. And since you typehinted it, and since Laravel knows how to resolve that class name, you're going to have the Reqeust object ready for you to use in your method with no work on your parkt. No explicit binding, no anything else-it's just there are the $reqeust variable.
By the way, this is actually how I and many other Laravel developers prefer to get the user input: inject an instance of the Reqeusedt and read the user input from there, instread of relying on the Input facade.
Resource Controllers
Sometimes naming the methods in your controllers can be the hardest part of writing a controller. Thankfully, Laravel has some conventions for all of the routes of a traditional REST/CRUD controller ( called a "resource controller" in Laravel); additionally, it ocmes with a generator out of the box and a convenience route definition that allows you to bind an entire resource controller at once.
To see the mothods that Laravel expects for a resouce controller, let's generate a new controller from the command line:
php aratisan make:controller MySampleResourceController --resource
Now open app/Http/Controllers/MysampleResourceController.php. You'll see it comes prefilled with quite a few methods. Let's walk over what each represents. We'll use a Task as an example.
The methods of Laravel's resource controllers
For each, you can see the HTTP verb, the URL, the controller method name, and the "name". Table 3-1 shows the HTTP verb, the URL, the controller method name, and the "name" for each of these default methods.
Table 3-1. The methods of Laravel's resource controllers
Verb URL Controller method Name Description
GET tasks index() tasks.index Show all tasks
GET tasks/create create() tasks.create Show the create task form
POST tasks store() tasks.store Accept form submission
from the create task form
GET tasks/{task} show() tasks.show Show one task
GET tasks/ edit() tasks.edit Edit one task
{task}/edit
PUT/PATCH tasks/{task} update() tasks.update Accept form submission from
the edit task form
DELETE tasks/{task} destroy() tasks.destroy Delete one task
Binding a resource controller
So, we've seen that these are the conventional route names to sue in Laravel, and also that it's easy to generate a resource controller with methods for each of these controller methods by hand, if you don't want to. Instead, there's a trick for that, and it's called "resource controller binding." Task a look at Example 3-26.
Example 3-26. Resource controller binding
//routes/web.php
Route::resource('tasks', 'TasksController');
This will automatically bind all of the routes for this resource to the appropriate method names on the specified controller. It'll also name these routes appropriately; for example, the index() method on the tasks resource controller will be named tasks.index.
artisan route:list
If you ever find yourself in a situation where you're wondering what routes your current application has available, there's a tool for that: from the command line, run php artisan route:list and you'll get listing of all of the available routes.
Route Model Binding
One of the most common routing patterns is that the first line of any controller method tries to find the resource with the given ID, like in Example 3-27.
Example 3-27. Getting a resource for each route
Route::get('conferences/{id}', function ($id) {
$conference = Conference::findOrFail($id);
});
Laravel provides a feature that simplifies this pattern called "route model binding."
This allows you to define that a particular parameter name (e.g., {conference}) will indicate to the route resolver that it should look up an Eloquent record with that ID and then pass it in as the parameter instead of just passing the ID.
There are two kinkds of route model binding:implicit and custom(or explicit).
Implicit Route Model Binding
The simplest way to use route model binding is to name your route parameter something unique to that model (e.g., name it $conference instead of $id), then typehint that parameter in the closure/controller method and use the same variable name there. It's easier to show than to describe, so take a look at Example 3-28.
Example 3-28. Using an explicit route model binding
Route::get('conferences/{conference}', function(Conference $conference){
return view('conferences.show') ->with('conference', $conference);
});
Because the route parameter ({conference}) is the same as the method parameter ($conference), and the method parameter is typehited with a Conference model (Conference $conference), Laravel sees this as a route model binding. Every time this route is visited, the application will assume that whatever is passes into the URL in place of {conference} is an ID that should be used to look up a Conference, and then that resulting model instance will be passed into your closure or controller method.
Customizing the route key for an Eloquent model
Any time an Eloquent model is looked up via a URL segment (usually because of route model binding), the default column Eloquent will because of route model binding), the default column Eloquent will look it up is its primary key(ID).
To change the column your Eloquent model uses for URL lookups add a method to your model named getRouteKeyName*():
public function getRouteKeyName()
{
return 'slug';
}
Now, a URL like conferences/{conference{ will expect to get the slug instread of the ID, and will perform its lookupas accordingly.
5.2 Implicit route model binding was added in Laravel 5.2, so you won't have access to it in 5.1
Custom Route Model Binding
To manually configure route model bindings, add a line like the one in Example 3-29 to the boot() method in App\Providers\RoutesServiceProvider.
Example 3-29. Adding a route model binding
public function boot(Router $router)
{
// just allows the parent's boot() method to still run
parent::boot($router);
// perform the binding
$router -> model('event', Conference::class);
}
You've now defined that whenever a route has a parameter in its definition named {event}, as demonstrated in Example 3-30, the route resolver will return an instance of the Conference class with the ID of that URL parameter.
Example 3-3-. Using an explicit route model binding
Route::get('events/{event}', function(Conference $event){
return view('events.show') ->with('event', $event);
});
Route Caching
If you're looking to squeeze every millisecond out of your load time, you may wantto take a look at route caching. One of the pieces of Laravel's bootstrap that can take anywhere from a few dozen to a few hundred milliseconds is parsing the routes/* files, and route caching speeds up this process dramatically.
To cache your routes file, you need to be using all controller and resource routes (no routes closures). If you r app isn't using any route closures, you can run php artisan route:cache, Laravel will serialize the results of your routes/* files. If you want to delete the cache, run php artisan route:clear.
Here's the drawback: Laravel will now match routes against that cached file instread of your actual routes/* files. You can make endless changes to those files, and they won't take effect until you run route:cache again. This means you'll have to recache every time you make a change, which introduces a lot of potential for confusion.
Here's what I would recommend instead: since Git ignores the route cache file by default anyway, consider only using route caching on your production server, and run the php artisan route:cache command every time you deploy new code (whether via a Git post-deploy hook, a Forge deploy command, or as a part of whatever other deploy system you use). This way you won't have confusing local development issues, but your remeote environment will still benefit from route caching.
Form Method Soofing
Sometimes, you need to manually define which HTTP verb a from should send as. HTML forms only allow for GET or POST, so if you want any other sort of verb, you'll need to specify that yourself.
An Introduction to HTTP Verbs
We've talked about the GET and POST HTTP verbs already. If you're not familiar with HTTP verbs, the other two most common ones are PUT and DELETE, but rhere's also HEAD, OPTIONS, PATCH, and two others that are pretty much never used in normal web development, TRACE and CONNECT.
Here's the quick rundown: GET requests a resource and HEAD asks for a headers-only version of the GET, POST creates a resource, PUT overwrites a resource and PATCH modifies a resource, DELETE deletes a resource, and OPTIONS asks the server which verbs are allowed at this URL.
HTTP Verbs in Laravel
As we've shown already, you can define which verbs a route will match in the route definition using Route::get(), Route::post(), Route::any(), or Route::match().
You can also match with Route::patch(), Route::put(), and Route::delete().
But how does one send a request other than GET with a web browser? First, the method attribute in an HTML form determines its HTTP verb: if your form has a method of "GET", it will submit via query parameters and a GET method; if the form has a method of "POST", it will submit via the post body and a POST method.
JavaScript frameworks make it easy to send other requests, like DELETE and PATCH. But if you find yourself needing to submit HTML forms in Laravel with verbs other than GET or POST, you'll need to sue form method spoofing, which is spoofing the
HTTP method in an HTML form.
To inform Laravel that the form you're currently submitting should be treated as something other than POST, add a hidden variable named _method with the value of either "PUT", "PATCH", or "DELETE", and Laravel will match and route that form submission as if it were actually a request with that verb.
The form in Example 3-31, since it's passing Laravel the method of "DELETE", will match routes defined with Route::delete() but not those with Route::post().
Example 3-31. Form method spoofing
CSRFJ Protection
If you've tried to create and submit a form in a Laravel application already - including the form in Example 3-31 - you've likely run into the dreaded TokenMismatchException.
By default, all routes in Laravel except "read-only" routes (those using GET, HEAD, or OPTIONS) are protected against cross-site request forgery (CSRF) attacks by requiring a token, in the form of an input named _token, to be passed along with each request.
This token is generated at the start of every session, and every non-read-only route
What is CSFR?
A cross-site request forgery is when one website pretends to be anoher. The goal is for someone to hijack your users' access to your website, by submitting forms from their website to your website via the logged-in user's browser.
The best way around CSRF attacks is to protect all inbound routes -POST, DELETE, etc. -with a token, which Laravel does out of the box.
You have two options for getting around this. The first, and preferred, method is to add the _token input to each of your submissions. In HTML froms, that's simple;
look at Example 3-32.
Example 3-32. CSRF token
In JavaScript applications, it's a bit mroe work, but not much. The most common solution for sites using JavaScript fraeworks is to stre the token on every page in a tag like this one:
Storing the toekn is a tag makes it easy to bind it to the correct HTTP header, shich you can do once globally for all requests from your JavaScript framework, like in Example 3-33.
Example 3-33. Globally binding a header for CSRF
//in jQuery:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
//in vue:
Vue.http.interceptors.push((request, next) => {
request.headers['X-CSRF-TOKEN'] =
document.querySelector('#token').getAttribute('content');
next();
});
Laravel will check the X-CSRF-TOKEN on every request, and valid tokens passed these will mark the CSRF protection as satisfied.
Note that the Vue syntax for CSRF in this example is not necessary if you're working with the 5.3 Vue bootstrap; it already does this work for you.
Redirects
So far the only tings we've returned from a controoler method or route definition have been views. But there are a few other structures we can return to give the browser instructions on how to behave.
First, let's cover the redirect. There are two common ways to generate a redirect; we'll use the redirect global helper here, but you may prefer the facade. Both create an instance of Illuminate\Http\RedirectResponse, perform some convenience methods on it, and then return it. You can also do this manualluy, but you'll have to do a little more work yourself. Take a look at Example 3-34 to see a few ways you can return a redirect.
Example 3-34. Different ways to return a redirect
// Using the global helper to generate a redirect response
Route::get('redirect-with-helper', function(){
return redirect()->to('login');
});
// Using the global helper shortcut
Route::get('redirect-with-helper-shortcut', function(){
return redirect('login')
});
// Using the facade to generate a redirect response
Route::get('redirect-with-facade', function(){
return Redirect::to('login');
});
Note that the redirect() helper exposes the same methods as the Redirect facade, but it also has a shortcut; if you pass parameters directly to the helper, instead of chaining methods after it, it's shortcut to the to() redirect method.
redirect() -> to()
The method signature for the to() method for redirects looks like this:
function to($to = null, $status = 302, $headers = [], #secure = null)
$to is a valid internal path; $status is the HTTP status (defaulting to 302 FOUND); $headers allows you to define which HTTP headers to send along with yhour redirect; and $secure allows you to override the default choice of http versus https(which is normally set based on your current request URL). Example 3-35 shows another example of its use.
Example 3-35. redirect()->to()
Route::get('redirect', function(){
return redirect()->to('home')'
// or sam, useing the shortcut
return redirect('home');
});
redirect()->route()
The route() method is the same as the to() method, but rather than pointing to a particular path, it points to particular route name (see Example 3-36).
Example 3-36. redirect()->route()
Route::get('redirect', function (){
return redirect()->route('conferences.index');
});
Note that, since some route names require paramters, its parameter order is a little dirrerent.route() has an optional second parameter for the route parameters:
function route($to = null, $parameters = [], $status = 302, $headers = [])
So, using it might look a little like Example 3- 37.
Example 3-37. redirect()->route() with parameters
Route::get('redirect', function(){
return redirect()->route('conferences.show', ['conference' => 99]);
});
redirect()->back()
Because of some of the built-in conveniences of Laravel's session implementation, your application will always have knowledge of what the user's previously visited page was. That open up the opportunity for a redirect()->() redirect, which simply reidrects the user to whatever page she came from. there's also a global shortcut for this:back().
Other Redirect Methods
The redirect service provides other methods ghat are less commonly used, but still available:
- home() redirects to a route named home.
- refresh() redirects to the same page the user is currently on.
- away() allows for redirecting to an external URL without the default URL validation.
- secure() is like to() with the secure parameter set to "true"
- action() allows you to link to a controller and method like this: redirect()->action('MyController@myMethod').
- getst() is used internally by the auth system (discussed in Chapter 9); when a user visits a route he's not authenticated for, this captures the "intended" route and then redirects the user (usually to a login page).
- intended() is also used internally by the auth system; after a successful authentication, this grabs the "intended" URL stored by the guest() method and redirects the user there.
redirect()->with()
When you're redirecting users to different pages, you ofter want to pass certain data along with them. You could manually flash the data to the session, but Laravel has some convenience methods to help you with that.
Most commonly, you can pass along either an array of keys and valeus or a single key and value using with(), like in Example 3-38.
Example 3-38. Redirect with data
Route::get('redirect-with-key-value', function(){
return redirect('dashboard')
->with('error', true);
});
Route::get('redirect-with-array', function(){
return redirect('dashbard')
->with(['error' => true, 'message' => 'Whoops!']);
});
Chaining methods on redirects
As with many other facades, most calls to the Redirect facade can accept fluent method chains, like the with() calls in Example 3-38. Learn more about fluency in "What Is a Fluent Interface?" on page 146.
You can also use withInput(), as in Example 3-39, to redirect with the user's form input flashed; this is most common in the case of a validation error, where you want to send the user back to the form she just came from.
Example 3-39. Redirect with form input
Route::get('form', function(){
return view('form');
});
Route::post('form', function(){
return redirect('form')
->withInput()
->with(['error' => true, 'message' => 'Whoops!']);
});
The easiest way to get the flashed input that was passed with withInput() is using the old() helper, which can be used to get all old input (old()) or just the value for a particular key (old('username'), with the second parameter as the default if ehre is no old value). You'll commonly see this in views, which allows this HTML to be used both on the "create" and the "edit" view for this form:
Speaking of validation, there is also a useful method for passing errors along with a redirect response:withErrors(). You can pass it any "provider" of errors, which may be an error string, an array of errors, or, most commonly, an instance of the Illuminate Validator, which we'll cover in Chapter 10. Example 3-40 shows an example of its use.
Example 3-40. Redirect with errors
Route::post('form', function (){
$validator = Validator::make($request->all()), $this->validationRules);
if($validator->fails()){
return redirect('form')
->withErrors($validator)
->withInput();
}
});
withErrors() automatically shares an $errors variable with the views of the page it's redirecting to, for you to handle however you'd liek.
The validate() shortcut in controller methods
Like how Example 3-40 looks? If you're defining your routes in a controller, there's a simple and powerful tool that cleans up that code. Read more in "validate() in the controller Using VlidatesRequests" on page 103.
Aborting the Request
Aside from returning views and redirects, the most common way to exit a route is to about. There are a few globally available methods (abort(), abort_if(), and abort_unless()), which optionally take HTTP status codes, a message, and a headers array as parameters.
As Example 3-41 shows, abort_if() and abort_unless() take a first parameter that is evaluated for its truthiness, and perform the abort depending on the result.
Exampel 3-41. 403 Forbidden aborts
Route::post('something-you-cant-do', function(Illuminate\Http\Request){
abort(403, 'You cannot do that!');
abort_unless($request->has('magicToken'), 403);
abort_if($reqeust->user()->isBannerd, 403);
});
Custom Responses
There are a few other options available for us to return, so let's go over the most common responses after views, redirects, and aborts. Just like with redirects, you can either use the response() helper or the Response facade to run these methods on.
response()->make()
If you want to create an HTTP response manually, just pass your data into the first parameter of response()->make(): e.g., return response()->make('Hello, World!'). Once again, the second parameter is the HTTP status code and the third is your headers.
response()->json()and->jsonp()
To create a JSON-encoded HTTP response manaually, pass your JSON-able content (arrays, collections, or whatever else) to the json() method: e.g., return response()->json(User::all());. It's just liek make(), except it json_encodes your content and sets the appropriate headers.
response()->download() and ->file()
To send a file for the end user to download, pass either an SplFileInfo instance of a string filename to download(), with an optional second parameter of the filename: e.g., return response()->download('file501751.pdf', 'myFile.pdf').
To display the same file in the browser (if it's a PDF or an image or something else the browser cna handle), use response()->file() instead, which takes the same parameters.
Testing
In some other communities, the idea of unit testing controller methods is common, but within Laravel (and most of the PHP community), it't most common to rely on application testing to test the functionality of routes.
For example, to verify that a POST route works correctly, we can write a test liek Example 3-42.
Example 3-42. Writing a simple POST route test
// AssignmentTest.php
public function test_post_creates_new _assignment()
{
$this->post('/assigments', [
'title'=> 'My great assignment'
]);
$this->seeInDatabase('assignments', [
'title'=> 'My great assigment'
]);
}
Did we directly call the controller methods? No. But we ensured that the goal of this route-to receive a POST and save its importnt information to the database-was met.
You can also use similar syntax to visit a route and verify that certain text shows up on the page, or that clicking certain buttons does certain things (see Example 3-43).
Example 3-43. Writing a simple GET route test
// AssignmentTest.php
public function test_list_page_shows_all_assignments()
{
$assigment = Assignment::create([
'title' => 'My great assignmnet'
]);
$this->visit('assignments')
-> see)['My great assignment']);
}
TL;DR
Laravel;s routes are defined in routes/web.php and routes/api.php, where you can define the expected path for each route, which segments are static and which are parameters, which HTTP verbs can access the route, and how to resolve it. You can also attach middleware to reoutes, group them, and give them names.
What is returned from theroute closue or controller method dictates how Laravel responds to the user. If it's a string ro a view, it's presented to the user; if it's other sorts of data, it's converted to JSON and presented to the user; and if it's a redirect, it forces a redirect.
Laravel provides a series of tools and conveniences to simplify common routing-related tasks and structures. These include resource controllers, route model binding and form method spoofing.
2018년 2월 13일 화요일
2018년 2월 11일 일요일
Chapter 2. Setting up a Laravel Development Environment
- Composer
Composer is a dependency manager for PHP, much like NPM for Node or RubyGems for Ruby. You'll need Composer to install Laravel, update Laravel, and bring in external dependencies.
- Local Development Environments
However, Laravel offers two tools for local development, Valet and Homestead, and we'll cover both briefly. If you're unsure of which to use, I'd recommend useing Valet and just skimming the Homested section; however, both tools are valuable and worth understanding.
- Laravel Valet
If you want to use PHP's build-in web server, your simplest option in to serve every site from a localhost URL. If your urn php -S localhost:8000 -t kpublic from yhour Laravel site's root folder, PHP's built-in web server your site a http://localhost:8000/. You can also run php artisan serve once you have your application setup to easily spin up an equivalent server
But if yhou're interrested in tying each of your sites to a specific development domain, you'll need to get comfortabel with your operationg system's host file and use a tool like dnsmasq. Let's instead tyr something simpler.
If your're a Mac user (there are also unofficial forks for Windows and Linux), Laravel Valet takes away the need to connnect yhour domains to your applicaiton folders. Valet install dnsmasq and a series of PHP scripts that make it possible to tyhpe laravel new myapp && open myapp.dev and for it to just work. You'll need to install a few tools using Homebrew, which thedocumentaion will walk you through, but the steps from initial installation to serving your apps are few and simple.
Imstall Valet (see the docs for the latest installation instruction- it's under very active developoment at this time of writing), and point it at one or more directories whrere your sites will live. I ran valet park from my ~/Sites directory, which is where I put all of my under-development apps. Now, you can just add .dev to the end of the directory name and visit it in your browser.
Valet makes it easy to serve all folders in a given folder a "FOLDERNAME.dev" using valet park, to server just a single folder using valet link, to open the Valetserved domain for qa folder using valet open, to serve the Valet site with HTTPS using valet secure, and to open an ngrok tunnel so you can share your site with others with valet share.
- Laravel Homestead
Homestead is another tool you might want to use to set up your local developement environment. It't configuration tool that site on top of Vagrant and providers a preconfigured virtual machine image that i perfectly set up for Laravel developemnt, and mirrors the most common production environment that many Laravel sites run on.
Setting up Homestead
If your choose to use Homestead, it's going to take a bit more work to set up than something like MAMP or Valet. The benefits are myriad, however: configured correctly, your local environment can be incredibly close to your ermote working environmnent; you won't have to worry about updating yuour dependencies on your local machine; and you can learn all about the structure of Ubuntu servers from the safety of your local machine.
What tools do Homestread Offer?
Your can always upgrad the individual components of your Homestread virtual machine, but here are a few inmportant tools Homestgead comes with by default:
- To run the server and serve the site, Ubuntu, PHP, and Nginx (a web server similar to Apache).
- For database/storage and queues, MySQL, Postgres, Redis, Memcached, and beanstalkd.
- For build steps and other tools, Node.
Installing Homesterad''s dependencies
First, you'll need to deonload and install either VirtualBox or VMWare, VirturalBox is most common because it's free.
Next, download and install Vagrant.
vagrant is convenient because it makes it easy for your to rectre a new local virtual machine from a precreated "box", which is essentially a tmeplate for a virtual machine. So, the next step is to run vagrant box andd laravel/homestread from your terminal to download the box.
Installing Homestead
Next, let's actually install Homeestead. You can install multiple instances of Homestead(perhaps hosting a different Homestread box per project), but I perfer a single Homestread virtual machine for all of my projects. It you wnat on per project, you'll want to installl Homestead in your project directory; check the Homestread documentation online for instructions. If you want a single virtual machine for all of your projects, instlal Homesterad in your user's home directory useing the following command:
git clone https://github.com/laravel/homestead.git ~/Homestead
Now, run the initialization script from wherevent you put the Homestead directory:
bash ~/Homestead/init/sh
This will place Homestead's primary configuration file, Homestead.yaml, in a new ~/.homestead directory.
Configuring Homestead
Open up Homestead.yaml and configure it how yhou'd like. Here's what it looks like out of the box:
ip : "192.168.10.10"
memory: 2048
cpus: 1
oorivuder: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
- ~/.ssh/id_rsa
folders:
- map: hoestead.app
to: /home/vagrant/Code
sites:
- map: homestead.app
to:/home/vagrant/Code/Laravel/public
databases:
- homestead
# blackfire:
# - id: foo
# token: bar
# client-id: foo
# client-token: bar
# ports:
# - send: 5000
# to : 5000
# - send: 7777
# to : 7777
# protocol: udp
You'll need to tell it your provider( likely virtualbox), point it to yhour public SSH key(by default ~/.ssh/id_rsa.pub; if you don't have one, GitHub has a gread tutorial on creating SSH keys), map folders and sites to their local machine equivalents, and provison a database.
Mapping folers in Homestead allows you to edit files on your local machine and have those files show up in your Vagrant box so they cna be serverd. For example, it you rhave a ~/Sites directory whrere your put all of your code, your'd map the folders in Homeestead by replacing the folders section in Homestead.yaml with the floowing:
folders:
- map: ~/Sites
to: /home/vagrant/Sites
You've now just created a directory in your Homestead virtual machine at /home/vagrant/Sites that will mirror your computer's directory at ~/Sites.
Top-level domains for development sites
You cna chooese nay converntion for local development sites' URLs, but .app and .dev are the most common. Homesteread suggest. .app, so if I'm working on a local copy of symposiumapp.com, I'll develop at symposiumapp.app.
Technically, .app and .dev are valid TLDs, so by choosing them for your won internal use, you could be confliciting with real domains.
This doesn't really bother me, but if you're concerned, there are four TLDs reserved for development purposes: .example, .test, .invlid, and .localhost.
Now, let's setup our first example website. Let's say our live site is going to be projectName.com. In Homestead,yaml, we'll map our local development folder to projectName.app, so we have a separate URL to visit for local development:
sites:
-map: projectName.app
to: /home/vagrant/Sites/projectName/public
As you can see, we're mapping the URL projectName.app to the virtual machine directory /home/vagrant/Sites/projectName/public, which is the public folder within our Laravel install. We'll learn more about that later.
Finlly, you're going to need to teach your local machine that, when you try to visit proejctName.app, it should look at your computer's local IP address to resolve it Mac and Linux users should edit /etc/hosts, and Windows users C:\Windows\System32\direvers\etc]host. Add a line to this file that looks lick this:
192. 186.10.10 projectName.app
Once you've provisioned Homeestead, your site will be available to browse (on your machine) at http:.//projectName.app/.
Creating databases in Homestead
Just like you can define a site in Homestead.yaml, you can slso define a database. Databases are a lot simpler, because you're only telling the provisioner to create a database with that name, nothing else. We dothis a follows:
databases:
-projectname
Provisioning Homestead
The first time your acually turn on a Homestead box, you need to tell Vagrant to initialize it. Navigate to your Homestead directory and run vagrant up:
cd ~/Homestead
bagrant up
Your Homestead box is now up and running: it's mirroring a local folder, and it's serving it to a URL you can visit in any browser on your computer. It also has created a MySQL database. Now that your have that environment running, you're ready to test up your first Laravel project - but first, a quick note about using Homestead day-to-day.
Using Homestead day-to-day
It's common to leave your Homestead virtual machine up and running at all times, but if you don't, or if you have recently restarted your computer, you'll need to know how to spin the box up and down.
Since Homestead is based on Vagrant commands, you'll ust use basic Vagrant commands for most Homestead actions. Change to the directory where you installed Homestead (using cd) and then run the following commands as needed:
- vagrant up spins up the Homestead box.
- vagrant suspend takes a snapshot of where the box is and tehn shuts it down;
like "hibernating" a desktop machine.
- vagrant halt shuts the entire box down; like turning off a desktop machine.
- vagrant destory deletes the entire box; like formatting a desktop machine.
- vagrant provision re-runs the provisioners on the preexisting box.
Connecting to Homestead databses from desktop applications
If yhou use a dsktop application like Sequel Pro, you'll likely want to connect to your Homestead MySQL databases from your host machine. These settings will get you going:
- Connection type: Standard(non-SSH)
- Host: 127.0.0.1
- Username:homestead
- Password:secret
- Post:33060
Creating a New Laravel Proejct
There are two ways to create a new Laravel proejct, but both are run from the command line. The first option is to globallyinstlal the Laravel installer tool( using Composer); the second is to use Composer's create-project feature.
You can learn about both options in more detail on the Installation documentation page, but I'd recommend the Laravel installer tool.
Installing Laravel with the Laravel Installer Tool
If you have Composer installed globally, installing the Laravel installer tool is as simple as running the following command:
composer global require "laravel/installer=~1.1"
Once you have the Laravel installer tool installed, spinning up a new Laravel proejct is simple. Just run this command from yhour command line:
laravel new proejctName
This will create a new subdirectory of your current directory named projectName and install a bare Laravel project in it.
Installing Laravel with Composer's create-proejct feature
Composer also offers a feature called create-proejct for creating new projects with a particular skeleton.to use this tool to create a new Laravel project, issue the following command:
composer create-proejct laravel/laravel projectName --prefer -dist
Just liek the installer tool, this will crfeate a subdirectory of your current directory named proejctName that contains a skeleton Laravel install. ready for you to develop.
Laravel's Directory Structure
When you openup a direcotry that contains a skeleton Laravel application, you'll see the following files and direcories:
app/
bootstrap/
config/
database/
public/
resources/
routes/
storage/
tests/
vendor/
.env
.ev.example.
.gitattributs/
.gitignore
artisan
composer.json
compoer.lock
gulpfile.js
package.sjon
phpunit.xml
readme.md
server.php
Let's walk through them one by one to get familiar.
The Folders
The root directory contains the follwoing folders by default:
- app is where the bulk of your actual application will go. Models, controllers, route definitions, commands, and yhour PHP domain code all go in here.
- bootstrap contains the files that the Laravel framework uses to boot every time it runs.
- config is whrere all the configuration files live.
- database is where database migrations and seeds live.
- public is the directory the server points to when it's serving the website. This contains index.php, whichis the front controller that kicks off the bootstrapping process and routes all requests appropriately. It's also where any public-facing files like images, stylesheets, scripts, or downloads go.
- reousrce is when non-PHP files that are needed for other scripts live. Views, language files, and (opotionally)Sass/LESS and source JavaScript files live here.
- routes is where all of the route definitions live, both for HTTP routes and "console routes," or Artisan commands.
- storage is where cashes, logs, and compiled system files live.
- tests is where unit and integration tests live.
- vendor is where Composer installs its dependencies. It's Git-ignored(marked to be excluded from your version control system), as Composer is expected to run as a part of your deploy process on any remote servers.
The Loose Files
The root directory also contains the following files:
- .env and .env.example are the files that dictate the environment variables (variables that are expected to be different in each environmnet and are therefore not committed to version control). .env.example is a template that each environment should duplicate to create its own .env file, which is Git-ignored.
-artisan is the file that allows you to run Artisan commands (see Chapter 7) from the command line.
-.gitignore and .gitattributes are Git configuration files.
- composer.json and composer.lock are the configuration files for Composer; composer.json is user-editable and composer.lock is not. These files share some basic information about this proejct and aslo define its PHP dependencies.
-gulpfile.js is the (optional) configuration file for Elixir and Gulp. This is for compiling and processing your frontend assets.
-package.json is like composer.json but for frontend asserts.
-phpuniut.xml is a configuration file for PHPUnit, the tool Laravel users for testing out of the box.
- readme.md is a Markdown file giving a basic introduction to Laravel.
-server.php is a backup server that tries to allow less-capable servers to still perview the Laravel application.
Configuration
The core settings of your Laravel application-database connection, queue and mail settings, etc. - live in files in the config folder. Each of these files returns an array, and each value in the array will be accessible by a config key that is comprised of the filename and all descendant keys, separated by dots(.)
So, if you create a file at config/service.php that looks like this:
// config/services.php
return [
'sparkost' => [
'secret' => 'abcdefg'
]
];
you will now have access to that config variable using config('services.spark post.secret').
Any configuration variables that should b distinct for each environment(and therefore not committed to source control) will instead live in your .env files. Let's say your want to use a different Bugsnag API key for each environment. You'd set the config file to pull it from .env:
// config/services.php
return [
'bugsnag' => [
'api_key' => env('BUGSANG_API_KEY')
]
];
This env() helper function pulls a value from your .env file with tat same key. So now, add that key to your .env (settings for this environment)and .env.example(template for all environmnets) files:
BUGSNAG_API_KEY=oinfp9813410942
your .env file already contains quite a few environment-specific variables needed by the framework, like which mail driver you'll be suing and what your basic database settings are.
Up and Running
You're now up and running with a bare Laravel install, Run git init, commit the bare files with git add . and git commit, and you're ready to start coding. That's it!
And if you're using Valet, you can run the follwing commands and instantly see your site live in your browser:
laravel new myProejct && cd myProejct && valet open
Every time I start a new project, these are the steops I take:
laravel new myProejct
cd myProejct
git init
git add .
git commit -m "Inital commit"
I keep all of my sites in a ~/Sites folder, which I hava set up as my primary Valet directory, so in this case I'd instantly have myProejct.dev accessible in mybrowser with no added work. I can edit .evn and point it to particular database, add that database in my MySQL app, and I'm ready to start coding.
Lambo
I perform this set of steps so often that I created a simple global Composer package to do it for me. It's called Lambo, and you can learn more about it on GitHub.
Testing
In every chapter after this, the "Testing" section at tne end of the chapter will show you how to wirte test for the feature of reatures that were coverd. Since this chater doesn't cover a testable feature, let's talk test quickly.(To lean more about wirting and running tests in Laravel, head over to Chapter 12.)
Out of the box, Laravel bring in PHPUnit as dependency and is configured to ren the tests in any file in the tests directory whose name ends with Test.php(for example, tests/UserTest.php).
So, the simplest way to write tests is to create a file in the tests directory with a anme that ends with Test.php. And the easiest way to run them is to run ./vendor/bin/phpunit from the command line (in the proejct root).
If nay tests require database access, be user to run your tests form the machine where your database is hosted- so if you're hosting your databases in Vagrant, make sure to ssh into your Vagrant box to run your test from there. Again, your can learn about this and much more in Chapter 12.
TL;DR
Since Laravel is a PHP framework, it's very simple to serve it locally. Laravel also provides two tools for maanging your local developoment: a simpler tool called Valet that uyses your local machine to provide your dependencies, and a preconfigured Vagrant setup named Homested. Laravel relies on, and can be installed by, Composer, and comes out of the box with a series of folders and files that rreflect both its conventiions and its relationship with other open source tools.
Composer is a dependency manager for PHP, much like NPM for Node or RubyGems for Ruby. You'll need Composer to install Laravel, update Laravel, and bring in external dependencies.
- Local Development Environments
However, Laravel offers two tools for local development, Valet and Homestead, and we'll cover both briefly. If you're unsure of which to use, I'd recommend useing Valet and just skimming the Homested section; however, both tools are valuable and worth understanding.
- Laravel Valet
If you want to use PHP's build-in web server, your simplest option in to serve every site from a localhost URL. If your urn php -S localhost:8000 -t kpublic from yhour Laravel site's root folder, PHP's built-in web server your site a http://localhost:8000/. You can also run php artisan serve once you have your application setup to easily spin up an equivalent server
But if yhou're interrested in tying each of your sites to a specific development domain, you'll need to get comfortabel with your operationg system's host file and use a tool like dnsmasq. Let's instead tyr something simpler.
If your're a Mac user (there are also unofficial forks for Windows and Linux), Laravel Valet takes away the need to connnect yhour domains to your applicaiton folders. Valet install dnsmasq and a series of PHP scripts that make it possible to tyhpe laravel new myapp && open myapp.dev and for it to just work. You'll need to install a few tools using Homebrew, which thedocumentaion will walk you through, but the steps from initial installation to serving your apps are few and simple.
Imstall Valet (see the docs for the latest installation instruction- it's under very active developoment at this time of writing), and point it at one or more directories whrere your sites will live. I ran valet park from my ~/Sites directory, which is where I put all of my under-development apps. Now, you can just add .dev to the end of the directory name and visit it in your browser.
Valet makes it easy to serve all folders in a given folder a "FOLDERNAME.dev" using valet park, to server just a single folder using valet link, to open the Valetserved domain for qa folder using valet open, to serve the Valet site with HTTPS using valet secure, and to open an ngrok tunnel so you can share your site with others with valet share.
- Laravel Homestead
Homestead is another tool you might want to use to set up your local developement environment. It't configuration tool that site on top of Vagrant and providers a preconfigured virtual machine image that i perfectly set up for Laravel developemnt, and mirrors the most common production environment that many Laravel sites run on.
Setting up Homestead
If your choose to use Homestead, it's going to take a bit more work to set up than something like MAMP or Valet. The benefits are myriad, however: configured correctly, your local environment can be incredibly close to your ermote working environmnent; you won't have to worry about updating yuour dependencies on your local machine; and you can learn all about the structure of Ubuntu servers from the safety of your local machine.
What tools do Homestread Offer?
Your can always upgrad the individual components of your Homestread virtual machine, but here are a few inmportant tools Homestgead comes with by default:
- To run the server and serve the site, Ubuntu, PHP, and Nginx (a web server similar to Apache).
- For database/storage and queues, MySQL, Postgres, Redis, Memcached, and beanstalkd.
- For build steps and other tools, Node.
Installing Homesterad''s dependencies
First, you'll need to deonload and install either VirtualBox or VMWare, VirturalBox is most common because it's free.
Next, download and install Vagrant.
vagrant is convenient because it makes it easy for your to rectre a new local virtual machine from a precreated "box", which is essentially a tmeplate for a virtual machine. So, the next step is to run vagrant box andd laravel/homestread from your terminal to download the box.
Installing Homestead
Next, let's actually install Homeestead. You can install multiple instances of Homestead(perhaps hosting a different Homestread box per project), but I perfer a single Homestread virtual machine for all of my projects. It you wnat on per project, you'll want to installl Homestead in your project directory; check the Homestread documentation online for instructions. If you want a single virtual machine for all of your projects, instlal Homesterad in your user's home directory useing the following command:
git clone https://github.com/laravel/homestead.git ~/Homestead
Now, run the initialization script from wherevent you put the Homestead directory:
bash ~/Homestead/init/sh
This will place Homestead's primary configuration file, Homestead.yaml, in a new ~/.homestead directory.
Configuring Homestead
Open up Homestead.yaml and configure it how yhou'd like. Here's what it looks like out of the box:
ip : "192.168.10.10"
memory: 2048
cpus: 1
oorivuder: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
- ~/.ssh/id_rsa
folders:
- map: hoestead.app
to: /home/vagrant/Code
sites:
- map: homestead.app
to:/home/vagrant/Code/Laravel/public
databases:
- homestead
# blackfire:
# - id: foo
# token: bar
# client-id: foo
# client-token: bar
# ports:
# - send: 5000
# to : 5000
# - send: 7777
# to : 7777
# protocol: udp
You'll need to tell it your provider( likely virtualbox), point it to yhour public SSH key(by default ~/.ssh/id_rsa.pub; if you don't have one, GitHub has a gread tutorial on creating SSH keys), map folders and sites to their local machine equivalents, and provison a database.
Mapping folers in Homestead allows you to edit files on your local machine and have those files show up in your Vagrant box so they cna be serverd. For example, it you rhave a ~/Sites directory whrere your put all of your code, your'd map the folders in Homeestead by replacing the folders section in Homestead.yaml with the floowing:
folders:
- map: ~/Sites
to: /home/vagrant/Sites
You've now just created a directory in your Homestead virtual machine at /home/vagrant/Sites that will mirror your computer's directory at ~/Sites.
Top-level domains for development sites
You cna chooese nay converntion for local development sites' URLs, but .app and .dev are the most common. Homesteread suggest. .app, so if I'm working on a local copy of symposiumapp.com, I'll develop at symposiumapp.app.
Technically, .app and .dev are valid TLDs, so by choosing them for your won internal use, you could be confliciting with real domains.
This doesn't really bother me, but if you're concerned, there are four TLDs reserved for development purposes: .example, .test, .invlid, and .localhost.
Now, let's setup our first example website. Let's say our live site is going to be projectName.com. In Homestead,yaml, we'll map our local development folder to projectName.app, so we have a separate URL to visit for local development:
sites:
-map: projectName.app
to: /home/vagrant/Sites/projectName/public
As you can see, we're mapping the URL projectName.app to the virtual machine directory /home/vagrant/Sites/projectName/public, which is the public folder within our Laravel install. We'll learn more about that later.
Finlly, you're going to need to teach your local machine that, when you try to visit proejctName.app, it should look at your computer's local IP address to resolve it Mac and Linux users should edit /etc/hosts, and Windows users C:\Windows\System32\direvers\etc]host. Add a line to this file that looks lick this:
192. 186.10.10 projectName.app
Once you've provisioned Homeestead, your site will be available to browse (on your machine) at http:.//projectName.app/.
Creating databases in Homestead
Just like you can define a site in Homestead.yaml, you can slso define a database. Databases are a lot simpler, because you're only telling the provisioner to create a database with that name, nothing else. We dothis a follows:
databases:
-projectname
Provisioning Homestead
The first time your acually turn on a Homestead box, you need to tell Vagrant to initialize it. Navigate to your Homestead directory and run vagrant up:
cd ~/Homestead
bagrant up
Your Homestead box is now up and running: it's mirroring a local folder, and it's serving it to a URL you can visit in any browser on your computer. It also has created a MySQL database. Now that your have that environment running, you're ready to test up your first Laravel project - but first, a quick note about using Homestead day-to-day.
Using Homestead day-to-day
It's common to leave your Homestead virtual machine up and running at all times, but if you don't, or if you have recently restarted your computer, you'll need to know how to spin the box up and down.
Since Homestead is based on Vagrant commands, you'll ust use basic Vagrant commands for most Homestead actions. Change to the directory where you installed Homestead (using cd) and then run the following commands as needed:
- vagrant up spins up the Homestead box.
- vagrant suspend takes a snapshot of where the box is and tehn shuts it down;
like "hibernating" a desktop machine.
- vagrant halt shuts the entire box down; like turning off a desktop machine.
- vagrant destory deletes the entire box; like formatting a desktop machine.
- vagrant provision re-runs the provisioners on the preexisting box.
Connecting to Homestead databses from desktop applications
If yhou use a dsktop application like Sequel Pro, you'll likely want to connect to your Homestead MySQL databases from your host machine. These settings will get you going:
- Connection type: Standard(non-SSH)
- Host: 127.0.0.1
- Username:homestead
- Password:secret
- Post:33060
Creating a New Laravel Proejct
There are two ways to create a new Laravel proejct, but both are run from the command line. The first option is to globallyinstlal the Laravel installer tool( using Composer); the second is to use Composer's create-project feature.
You can learn about both options in more detail on the Installation documentation page, but I'd recommend the Laravel installer tool.
Installing Laravel with the Laravel Installer Tool
If you have Composer installed globally, installing the Laravel installer tool is as simple as running the following command:
composer global require "laravel/installer=~1.1"
Once you have the Laravel installer tool installed, spinning up a new Laravel proejct is simple. Just run this command from yhour command line:
laravel new proejctName
This will create a new subdirectory of your current directory named projectName and install a bare Laravel project in it.
Installing Laravel with Composer's create-proejct feature
Composer also offers a feature called create-proejct for creating new projects with a particular skeleton.to use this tool to create a new Laravel project, issue the following command:
composer create-proejct laravel/laravel projectName --prefer -dist
Just liek the installer tool, this will crfeate a subdirectory of your current directory named proejctName that contains a skeleton Laravel install. ready for you to develop.
Laravel's Directory Structure
When you openup a direcotry that contains a skeleton Laravel application, you'll see the following files and direcories:
app/
bootstrap/
config/
database/
public/
resources/
routes/
storage/
tests/
vendor/
.env
.ev.example.
.gitattributs/
.gitignore
artisan
composer.json
compoer.lock
gulpfile.js
package.sjon
phpunit.xml
readme.md
server.php
Let's walk through them one by one to get familiar.
The Folders
The root directory contains the follwoing folders by default:
- app is where the bulk of your actual application will go. Models, controllers, route definitions, commands, and yhour PHP domain code all go in here.
- bootstrap contains the files that the Laravel framework uses to boot every time it runs.
- config is whrere all the configuration files live.
- database is where database migrations and seeds live.
- public is the directory the server points to when it's serving the website. This contains index.php, whichis the front controller that kicks off the bootstrapping process and routes all requests appropriately. It's also where any public-facing files like images, stylesheets, scripts, or downloads go.
- reousrce is when non-PHP files that are needed for other scripts live. Views, language files, and (opotionally)Sass/LESS and source JavaScript files live here.
- routes is where all of the route definitions live, both for HTTP routes and "console routes," or Artisan commands.
- storage is where cashes, logs, and compiled system files live.
- tests is where unit and integration tests live.
- vendor is where Composer installs its dependencies. It's Git-ignored(marked to be excluded from your version control system), as Composer is expected to run as a part of your deploy process on any remote servers.
The Loose Files
The root directory also contains the following files:
- .env and .env.example are the files that dictate the environment variables (variables that are expected to be different in each environmnet and are therefore not committed to version control). .env.example is a template that each environment should duplicate to create its own .env file, which is Git-ignored.
-artisan is the file that allows you to run Artisan commands (see Chapter 7) from the command line.
-.gitignore and .gitattributes are Git configuration files.
- composer.json and composer.lock are the configuration files for Composer; composer.json is user-editable and composer.lock is not. These files share some basic information about this proejct and aslo define its PHP dependencies.
-gulpfile.js is the (optional) configuration file for Elixir and Gulp. This is for compiling and processing your frontend assets.
-package.json is like composer.json but for frontend asserts.
-phpuniut.xml is a configuration file for PHPUnit, the tool Laravel users for testing out of the box.
- readme.md is a Markdown file giving a basic introduction to Laravel.
-server.php is a backup server that tries to allow less-capable servers to still perview the Laravel application.
Configuration
The core settings of your Laravel application-database connection, queue and mail settings, etc. - live in files in the config folder. Each of these files returns an array, and each value in the array will be accessible by a config key that is comprised of the filename and all descendant keys, separated by dots(.)
So, if you create a file at config/service.php that looks like this:
// config/services.php
return [
'sparkost' => [
'secret' => 'abcdefg'
]
];
you will now have access to that config variable using config('services.spark post.secret').
Any configuration variables that should b distinct for each environment(and therefore not committed to source control) will instead live in your .env files. Let's say your want to use a different Bugsnag API key for each environment. You'd set the config file to pull it from .env:
// config/services.php
return [
'bugsnag' => [
'api_key' => env('BUGSANG_API_KEY')
]
];
This env() helper function pulls a value from your .env file with tat same key. So now, add that key to your .env (settings for this environment)and .env.example(template for all environmnets) files:
BUGSNAG_API_KEY=oinfp9813410942
your .env file already contains quite a few environment-specific variables needed by the framework, like which mail driver you'll be suing and what your basic database settings are.
Up and Running
You're now up and running with a bare Laravel install, Run git init, commit the bare files with git add . and git commit, and you're ready to start coding. That's it!
And if you're using Valet, you can run the follwing commands and instantly see your site live in your browser:
laravel new myProejct && cd myProejct && valet open
Every time I start a new project, these are the steops I take:
laravel new myProejct
cd myProejct
git init
git add .
git commit -m "Inital commit"
I keep all of my sites in a ~/Sites folder, which I hava set up as my primary Valet directory, so in this case I'd instantly have myProejct.dev accessible in mybrowser with no added work. I can edit .evn and point it to particular database, add that database in my MySQL app, and I'm ready to start coding.
Lambo
I perform this set of steps so often that I created a simple global Composer package to do it for me. It's called Lambo, and you can learn more about it on GitHub.
Testing
In every chapter after this, the "Testing" section at tne end of the chapter will show you how to wirte test for the feature of reatures that were coverd. Since this chater doesn't cover a testable feature, let's talk test quickly.(To lean more about wirting and running tests in Laravel, head over to Chapter 12.)
Out of the box, Laravel bring in PHPUnit as dependency and is configured to ren the tests in any file in the tests directory whose name ends with Test.php(for example, tests/UserTest.php).
So, the simplest way to write tests is to create a file in the tests directory with a anme that ends with Test.php. And the easiest way to run them is to run ./vendor/bin/phpunit from the command line (in the proejct root).
If nay tests require database access, be user to run your tests form the machine where your database is hosted- so if you're hosting your databases in Vagrant, make sure to ssh into your Vagrant box to run your test from there. Again, your can learn about this and much more in Chapter 12.
TL;DR
Since Laravel is a PHP framework, it's very simple to serve it locally. Laravel also provides two tools for maanging your local developoment: a simpler tool called Valet that uyses your local machine to provide your dependencies, and a preconfigured Vagrant setup named Homested. Laravel relies on, and can be installed by, Composer, and comes out of the box with a series of folders and files that rreflect both its conventiions and its relationship with other open source tools.
2018년 2월 10일 토요일
CHAPTER1 The Neural Network.
- Building Intelligent Machines
The brain is the most incredible organ in the human body. It dictates the way we perceive every sight, sound, smell, taste, and touch. It enables us to store memories, experience emotions, and even dream. Without it, we would be primitive organisms, incapable of anything other than the simplest of reflexes. The brain is, inherently, what makes us intelligent.
The infant brain only weighs a single pound, but somehow it solves problems that even out biggest, most powerful supercomputers find impossible. Within a matter of months after birth, infants can recognize the faces of their parents, discern discrete objects from their backgrounds, and even tell apart voices. Within a year, they've already developed an intuition for natural physics, can track objects even when they become partially or completely blocked, and can associate sounds with specific meanings. And by early childhood, they have s sophisticated understanding of grammar and thousands of words in their vocabularies.
For decades, we've dreamed of building intelligent machines with brains like ours-robotic assistants to clean our homes, cars that drive themselves, microscopes that automatically detect diseases. But building these artificially intelligent machines requires us to solve some of the most complex computational problems we have ever grappled with; problems that our brains can already solve in a manner of microseconds. To tackle these problems, we'll have to develop a radically different way of programming a computer using techniques largely developed over the past decade. This is an extremely active field of artificial computer intelligence often referred to as deep learning.
- The Limits of Traditional Computer Programs
Why exactly are certain problems so difficult for computers to solve? Well, it turns out that traditional computer programs are designed to be very good at two things: 1) performing arithmetic really fast and 2) explicitly following a list of instructions. So if you want to do some heavy financial number crunching, you're in luck. Traditional computer programs can do the trick. But let's say we want to do something slightly more interesting, like write a program to automatically read someone's handwriting.
Figure 1-1 will serve as a starting point.
Although every digit in Figure 1-1 is written in a slightly different way, we can easily recognize every digit in the first row as a zero, every digit in the second row as a one, etc. Let's try to write a computer program to crack this task. What rules could we use to tell one digit from another?
You could potentially establish some sort of cutoff for the distance between the starting point of the loop and the ending point, but it's not exactly clear where we should be drawing the line. But this dilemma is only the beginning of our worries. How do we distinguish between threes and fives? Or between fours and nines? We can add more and more rules, or features, through careful observation and months of trial and error, but it's quite clear that this isn't going to be an easy process.
The input 𝞠 is a vector of the parameters that our model uses. Our machine learning program tires to perfect the values of these parameters as it is exposed to more and more examples. We'll see this in action and in more detail in Chapter 2.
Then it turns out, by selecting 𝞠 = [-24 3 4]τ, our machine learning model makes the correct prediction on every data point:
But these situations are only the tip of the iceberg. As we move on to much more complex problems, such as object recognition and text analysis, our data becomes extremely high dimensional, and the relationships we want to capture become highly nonlinear. To accommodate this complexity, recent research in machine learning has attempted to vuild models that resemble the structures utilized by our brains. It's essentially this body of research, commonly referred to as deep learning, that has had spectacular success in tackling problems not only for surpass other kinds of machine learning algorithms, but also rival(or even exceed!) the accuracies achieved by humans.
The brain is the most incredible organ in the human body. It dictates the way we perceive every sight, sound, smell, taste, and touch. It enables us to store memories, experience emotions, and even dream. Without it, we would be primitive organisms, incapable of anything other than the simplest of reflexes. The brain is, inherently, what makes us intelligent.
The infant brain only weighs a single pound, but somehow it solves problems that even out biggest, most powerful supercomputers find impossible. Within a matter of months after birth, infants can recognize the faces of their parents, discern discrete objects from their backgrounds, and even tell apart voices. Within a year, they've already developed an intuition for natural physics, can track objects even when they become partially or completely blocked, and can associate sounds with specific meanings. And by early childhood, they have s sophisticated understanding of grammar and thousands of words in their vocabularies.
For decades, we've dreamed of building intelligent machines with brains like ours-robotic assistants to clean our homes, cars that drive themselves, microscopes that automatically detect diseases. But building these artificially intelligent machines requires us to solve some of the most complex computational problems we have ever grappled with; problems that our brains can already solve in a manner of microseconds. To tackle these problems, we'll have to develop a radically different way of programming a computer using techniques largely developed over the past decade. This is an extremely active field of artificial computer intelligence often referred to as deep learning.
- The Limits of Traditional Computer Programs
Why exactly are certain problems so difficult for computers to solve? Well, it turns out that traditional computer programs are designed to be very good at two things: 1) performing arithmetic really fast and 2) explicitly following a list of instructions. So if you want to do some heavy financial number crunching, you're in luck. Traditional computer programs can do the trick. But let's say we want to do something slightly more interesting, like write a program to automatically read someone's handwriting.
Figure 1-1 will serve as a starting point.
Figure 1-1. Image from MNIST handwritten digit dataset |
Although every digit in Figure 1-1 is written in a slightly different way, we can easily recognize every digit in the first row as a zero, every digit in the second row as a one, etc. Let's try to write a computer program to crack this task. What rules could we use to tell one digit from another?
Well, we can start simple! For example, we might state that we have a zero if our image only has a single, closed loop. All the examples in Figure 1-1 seem to fit this bill, but this isn't really a sufficient condition. What if someone doesn't perfectly close the loop on their zero? And, as in Figure 1-2, how do you distinguish a messy zero from a six?
Figure 1-2. A zero that's algorithmically difficult to distinguish from a six |
Many other classes of problems fall into this same category: object recognition, speech comprehension, automated translation, etc. We don't know what program to write because we don't know it's done by our brains. And even if we did know how to do it, the program might be horrendously complicated.
- The Mechanics of Machine Learning
To tackle these classes of problems, we'll have to use a very different kind of approach. A lot of the things we learn in school growing up have a lot in common with traditional computer programs. We learn how to multiple numbers, solve equations, and take derivatives by internalizing a set of instructions. But the things we learn at an extremely early age, the things we find most natural, are learned by example, not by formula.
For instance, when we were two years old, our parents didn't teach us how to recognize a dog by measuring the shape of its nose or the contours of its body. We learned to recognize a dog by being shown multiple examples and being corrected when we made the wrong guess. In other words, when we were born, our brains provided us with a model that described how we would be able to see the world. As we grew up, that model would take in our sensory inputs and make a guess about what we were experiencing. If that guess was confirmed by our parents, our model would be reinforced. If our parents said we were wrong, we'd modify our model to incorporate this new information. Over our lifetime, our model becomes more and more accurate as we assimilate more and more examples. Obviously all of this happens subconsciously, without us even realizing it, but we can use this to our advantage nonetheless.
Deep learning is a subset of a more general field of artificial intelligence called machine learning, which is predicated on this idea of learning from example. In machine learning, instead of teaching a computer a massive list of rules to solve the problem, we give it a model with which it can evaluate examples, and a small set of instructions to modify the model when it makes a mistake. We expect that, over time, a well-suited model would be able to solve the problem extremely accurately.
Let's be a little bit more rigorous about what this means so we can formulate this idea mathematically. Let's define our model to be a function ℎ(x,𝞠). The input x is an example expressed in vector form. For example, if x were a grayscale image, the vector's components would be pixel intensities at each position, as shown in Figure 1-3.
Figure 1-3. The process of vectorizing an image for a machine learning algorithm |
To develop a more intuitive understanding for machine learning models, let's walk through a quick example. Let's say we wanted to determine how to predict exam performance based on the number of hours of sleep we get and the number of hours we study the previous day. We collect a lot of data, and for each data point x = [x₁ x₂]T, we record the number of sleep we get (x₂), and whether we performed above or below the class average, Our goal, then, might be to learn a model ℎ(x,𝞠) with parameter vector 𝞠 = [𝞠₀ 𝞠₁ 𝞠₂]T such that:
In other words, we guess that the blueprint for our model ℎ(x,𝞠) is as described above (geometrically, this particular blueprint describes a linear classifier that divides the coordinate plane into two halves). Then, we want to learn a parameter vector 𝞠 such that our model make the right predictions (-1 if we perform below average, and 1 otherwise) given an input example x. This model is called a linear perceptron, and it's a model that's been used since the 1950s. Let's assume our data is as shown in Figure 1-4.
Figure 1-4. Sample data for our exam predictor algorithm and a potential classifier |
An optimal parameter vector 𝞠 positions the classifier so that we make as many correct predictions as possible. In most cases, there are many ( or even infinitely many) possible choices for 𝞠 that are optimal. Fortunately for us, most of the timethese alternatives are so close to one another that the difference is negligible. If this is not the case, we may want to collect more data to narrow our choice of 𝞠.
While the setup seems reasonable, where are still some pretty significant questions that remain. First off, how do we even come up with an optimal value for the parameter vector 𝞠 in the first place? Solving this problem requires a technique commonly known as optimization. An optimizer aims to maximize the performance of a machine learning model by iteratively tweaking its parameters until the error is minimized. We'll begin to tackle this question of learning parameter vectors in more detail in Chapter2, when we describe the process of gradient descent. In later chapters, we'll fry to find ways to make this process even more efficient.
Seound, it's quite clear that this particular model (the linear perceptron model) is quite limited in the relationships it can learn. For example, the distributions of data shown in Figure 1-5 cannot be described well by a linear perceptron.
Figure 1-5. As our data takes on more complex forms, we need more complex models to describe them |
The Neuron
The foundational unit of the human brain is the neuron. A tiny piece of the brain, about the size of grain of rice, contains over 10.000 neurons, each of which forms and average of 6,000 connections with other neurons. It's this massive biological network that enalbes us to experience the world around us. Our goal in this section will be to use this natural structure to build machine learning models that sol ve problems in an analogous way.
At its core, the neuron is optimized to receive information from other neurons, process this information in a unique way, and send its result to other cells. This process is summarized in Figure 1-6. The neuron receives its inmputs along antennae-like structures called dendrites. Each of these incoming connections is dynamically strengthened or weakened based on how oftern it is used(this is how we learn new concepts!), and it's the strength of each connection that determines the contribution of the input to the neuron's output. After being weighted by the strength of their respective connections, the inputs are summed together in the cell body. This sum is then transformed into a new signal that's propagated along the cell's axon and sent off to other neurons.
Figure 1-6. A functional description of a biological neuron's structure |
We can translate this functional understanding of the neurons in our brain into an artificial model that we can represent on our computer. Such a model is described in Figure 1-7, leveraging the approach first pioneered in 1943 by Warren S. McCulloch and Walter H. Pitts. Just as in biological neurons, our artificial neuron takes in some number of inputs, x₁, x₂,...,xₙ, each of which is multiplied by a specific weight, w₁, w₂,...,wₙ These weighted inputs are, as before, summed together to produce the logit of the neuron,
In many cases, the logit also includes a bias, which is constant ( not shown in the figure). The logit is then passed through a function f to produce the output y = f(z). This out put can be transmitted to other neurons.
In many cases, the logit also includes a bias, which is constant ( not shown in the figure). The logit is then passed through a function f to produce the output y = f(z). This out put can be transmitted to other neurons.
Figure 1-7. Schematic for a neuron in an artificial neural net |
We'll concolude our mathematical discussion of the artificial neuron by re-expressiong its functionality in vector form. Let's reformulate the inputs as a vector x = [x₁ x₂ ... xₙ] and the weights of the neuron s w = [w₁ w₂ ... wₙ] . Then we can re-express the output of the neuron as y = f(x.w + b), where b is the bias term. In other words, we can compute the output by performing the dot product of the input and weight vectors, adding in the bias term to produce the logit, and then applying the transformation function. While this seems like a trivial reformulation, thinking about neurons as a series of vector manipulations will be crucial to how we implement them in software later in this book.
- Expressiong Linear Perceptrons as Neurons
In "The mechanics of Machine Learning" on page 3, we talked about using machine learning models to capture the relationship between success on exams and time spent studying and sleeping. To tackle this problem, we constructed a linear perceptron classifier that divided the Cartesian coordinate plane into two halves:
As shown in Figure 1-4, this is an optimal choice for 𝞠 because it correctly classifies every sample in our dataset. Here, we show that our model h is easily using a neuron.
Consider the neuron depicted in Figure 1-8. The neuron has two inputs, a bias, and uses the function:
It's very easy to show that our linear perceptron and the neuronal model are perfectly equivalent. And in general, it's quite simple to show that singular neurons are strictly more expressive than linear perceptrons. In other words, every linear perceptron can be expressed as a single neuron, but single neurons can also express models that cannot be expressed by any linear perceptron.
- Feed-Forward Neural Networks
Although single neurons are more powerful than linear perceptrons, they're not nearly expressive enough to solve complicated learning problems. There's a reason our brain is made of more than one neuron, For example, it is impossible for a single neuron to differentiate handwritten digits. So to tackle much more complicated tasks, we'll have to take our machine learning model even further.
The neurons is the human brain are organized in layers. In fact, the human cerebral cortex (The structure responsible for most of human intelligence) is made up of six layers. Information flows from one layer to another until sensory input is converted into conceptual understanding. For example, the bottommost layer of the visual cortex receives raw visual data from the eyes. This information is processed by each layer and passed on to the next until, in the sixth layer, we conclude whether we are looking at a cat, or a soda can, or an airplane. Figure 1-9 shows a more simplified version of these layers.
Borrowing from these concepts, we can construct an artificial neural network. A neural network comes about when we start hooking up neurons to each other, the input data, and to the output nodes, which correspond to the network's answer to a learning problem. Figure 1-9 demonstrates a simple example of a artificial neural network, similar to the architecture described in McCulloch and Pitt's work in 1943. The bottom layer of the network pulls in the input data. The top layer of neurons (output nodes) computes our final answer. The middle layer(s) of neurons are called the hidden layers, and we let
- Expressiong Linear Perceptrons as Neurons
In "The mechanics of Machine Learning" on page 3, we talked about using machine learning models to capture the relationship between success on exams and time spent studying and sleeping. To tackle this problem, we constructed a linear perceptron classifier that divided the Cartesian coordinate plane into two halves:
As shown in Figure 1-4, this is an optimal choice for 𝞠 because it correctly classifies every sample in our dataset. Here, we show that our model h is easily using a neuron.
Consider the neuron depicted in Figure 1-8. The neuron has two inputs, a bias, and uses the function:
It's very easy to show that our linear perceptron and the neuronal model are perfectly equivalent. And in general, it's quite simple to show that singular neurons are strictly more expressive than linear perceptrons. In other words, every linear perceptron can be expressed as a single neuron, but single neurons can also express models that cannot be expressed by any linear perceptron.
Figure 1-8. Expressing our exam performance perceptron as a neuron |
Although single neurons are more powerful than linear perceptrons, they're not nearly expressive enough to solve complicated learning problems. There's a reason our brain is made of more than one neuron, For example, it is impossible for a single neuron to differentiate handwritten digits. So to tackle much more complicated tasks, we'll have to take our machine learning model even further.
The neurons is the human brain are organized in layers. In fact, the human cerebral cortex (The structure responsible for most of human intelligence) is made up of six layers. Information flows from one layer to another until sensory input is converted into conceptual understanding. For example, the bottommost layer of the visual cortex receives raw visual data from the eyes. This information is processed by each layer and passed on to the next until, in the sixth layer, we conclude whether we are looking at a cat, or a soda can, or an airplane. Figure 1-9 shows a more simplified version of these layers.
Figure 1-9. A simple example of a feed-forward neural network with three layers(input, one hidden, and output) and three neurons per layer |
Borrowing from these concepts, we can construct an artificial neural network. A neural network comes about when we start hooking up neurons to each other, the input data, and to the output nodes, which correspond to the network's answer to a learning problem. Figure 1-9 demonstrates a simple example of a artificial neural network, similar to the architecture described in McCulloch and Pitt's work in 1943. The bottom layer of the network pulls in the input data. The top layer of neurons (output nodes) computes our final answer. The middle layer(s) of neurons are called the hidden layers, and we let
be the weight of the connection between the neuron in the layer with theneuraon in the layer. These weights constitute our parameter vector, 𝞠, and just as before, our ability to solve problems with neural networks depends on finding the optimal values to plug into 𝞠.
We not that in this example, connections only traverse from a lower layer to a higher layer. There are no connections between neurons in the same layer, and there are no connections that transmit data from a higher layer to a lower layer. These neural networks are called feed-forward networks, and we start by discussing these networks because they are the simplest to analyze. We present this analysis (specifically, the process of selecting the optimal values for the weights) in Chapter 2. More complicated connectivities will be addressed in later chapters.
In the final sections, we'll discuss the major types of layers that are utilized in feedforward neural networks. But before we proceed, here's a couple of important notes to keep in mind:
1. As we mentioned, the layers of neurons that lie sandwiched between the first layer of neurons (input layer) and the last layer of neurons (output layer) are called the hidden layers. This is where most of the masic is happening when the neural net tries to solve problems. Whereas (as in the handwritten digit example) we would previously have to spend a lot of time identifying useful features, the hidden layers automate this process for us. Oftentimes, taking a look at the activities of hidden layers can tell you a lot about the features the network has automatically learned to extract from the data.
2. Although in this example every layer has the same number of neurons, this is neither necessary nor recommended. More often than not, hidden layers have fewer neurons than the input layer to force the network to learn compressed representations of the original input. For example, while our eyes obtain raw pixel vlaues from our surroundings, our brain thinks in terms of edges and contours. This is because the hidden layers of biological neurons in our brain force us to come up with better representations for everything we perceive.
3.It is not required that every neuron has its output conneted to the inputs of all neurons in the next layer. In fact, selecting which neurons to connect to which other neurons in the next layer is an art that comes from experience. We'll discuss this issue in more depth as we work though various examples of neural networks.
4. The inputs and outputs are vectorized representations. For example, you might imagine a neural network where the inputs are the individual pixel RGB values in an image represented as a vector (refer to Figure 1-3). The last layer might have two neurons that correspond to the answer to our problem: [1, 0] if the image contains a dog, [0,1] if the image contains a cat, [1, 1] if it contains both and [0, 0] if it contains neither.
We'll also observe that, similarly to our reformulation for the neuron, we can also mathematically express a neural network as a series of vector and matrix operations.
We'd like to find the vector y = [y₁ y₂ ... yₘ] produced by propagating the input through the neurons. We can express this as a simple matrix multiply if we construct a weight matrix W of size n * m and a bias vector of size m. In this matrix, each column corresponds to a neuron, where the element of the column corresponds to the weight of the connection pulling in the element of the input. In other words, y = ƒ(WTx + b), where the transformation function is applied to the vector elementwise. This reformulation will become all the more critical as we begin to implement these networks in software.
- Linear Neurons and Their Limitations
Most neuron types are defined by the function f they apply to their logit z. Let's first consider layers of neurons that use a linear function in the form of f(z) = az +b. For example, a neuron that attempts to estimate a cost of a meal in a fast-food restaurant would use a linear neruon where a = 1 and b = 0, In other words, using f(z) = z and weight equal to the price of each item, the linear neuron in Figure 1-10 would take in some orderd triple of servings of burgurs, fries, and sodas and output the price of the combination.
Figure 1-10. An example of a linear neuron |
Linear neurons are easy to compute with, but they run into serious limitations. In fact, it can be shown that any feed-forward neural network consisting of only linear neurons can be expressed as a network with no hidden layers. This is problematic because, as we discussed before, hidden layers are what enable us to learn important features from the input data. In other words, In order to learn complex relationships, we need to use neurons that employ some sort of nonlinearity.
- Sigmoid, Tanh, and ReLu Neurons
There are three major types of neurons that are used in practice that introduce nonlinearities in their computations. The First of these is the sigmoid neuron, which uses the function:
2018년 2월 7일 수요일
피드 구독하기:
글 (Atom)