This has been moved to my blog at asklagbox blog
We are going to make a quick laravel application, including the setup and install.
We will setup the project using the following:
- Nginx
- sqlite3
- and we are on a *nix system (Linux, Mac, Unix, Freebsd, etc ...)
We will end up using 1 extra composer package:
- Laravel Collective HTML & Form helper (laravelcollective/html)
⚡ composer create-project --prefer-dist laravel/laravel letsdothis
...
Writing lock file
Generating autoload files
> Illuminate\Foundation\ComposerScripts::postInstall
> php artisan optimize
Generating optimized class loader
> php artisan key:generate
Application key [base64:...this will be a generated key...] set successfully.
sudo vim /etc/hosts
...
127.0.0.1 letsdothis.local
Lets create a Nginx config for our site. It is important to note that the way Laravel wants to be setup, the document root or webroot for your site should point to the public folder of the project. Laravel uses a front loader where all requests come through index.php
which is in the public
folder.
Side Note: The way the webserver is handling these requests, as in the case for how apache would be setup as well, is that any requests that match any files or folders that are accessible in
public
will get served by the webserver. Requests that don't match will be passed toindex.php
. Be aware of this as you name routes and files and folders you place inpublic
.
⚡ cd /etc/nginx/sites-available
⚡ sudo vim letsdothis.local
server {
listen 127.0.0.1:80;
root /var/www/sites/letsdothis/public;
index index.php index.html index.htm;
server_name letsdothis.local;
# we will put the logs in laravel's storage folder
access_log /var/www/sites/letsdothis/storage/logs/access.log;
error_log /var/www/sites/letsdothis/storage/logs/error.log;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
error_page 404 /index.php;
include fastcgi.conf;
location ~ /\.ht {
deny all;
}
}
Enable this site by creating a symlink in sites-enabled to the config we just created.
⚡ cd ../sites-enabled/
⚡ sudo ln -s ../sites-available/letsdothis.local .
Lets reload nginx.
⚡ sudo service nginx reload
This is just one quick way of doing this. You can do permissions on the way you prefer and should look into how to do permissions correctly. Im just going to use group write permissions for www-data
.
⚡ cd /var/www/sites/letsdothis
⚡ chgrp www-data -R bootstrap/cache storage
⚡ chmod g+w -R bootstrap/cache storage
At this point you can hit your site from your browser at http://letsdothis.local
. You will see the Laravel landing page, at the time of writing it would have said "Laravel 5" centered on the page.
We are going to keep this simple and quick and use a sqlite database. We will create it in storage
.
⚡ sqlite3 database.sqlite
SQLite version 3.8.11.1 2015-07-29 20:00:57
Enter ".help" for usage hints.
sqlite> .databases
seq name file
--- --------------- -----------------------------------------------------
0 main /var/www/sites/letsdothis/storage/database.sqlite
sqlite> .q
Now that we have a sqlite database lets set the write permissions needed on it. (As before you should look into how permissions work on the system you are on and decide the best method needed.)
⚡ chgrp www-data database.sqlite
⚡ chmod g+w database.sqlite
We will make two adjustment in the .env
file that has been created for us, to set the default database connection to use our sqlite database.
...
DB_CONNECTION=sqlite
...
#DB_DATABASE=homestead
...
These env values will get read by the configuration files in the config
directory. The env variables, DB_CONNECTION
and DB_DATABASE
, are used by database.php
as shown below.
'default' => env('DB_CONNECTION', 'mysql')
...
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', storage_path('database.sqlite')),
'prefix' => '',
],
We adjusted the database_path('database.sqlite')
to storage_path('database.sqlite')
; this will resolve to the path where we placed our sqlite database.
Now that We have setup and configured our application we can move onto the fun stuff. There are numerous generators that are provided by Laravel via the artisan
helper that you can use on the command line. (You should get to know artisan
and its many commands)
In the spirit of keeping this simple lets just create a table that can store attributes and values. This will be a simple CRUD interface to create.
⚡ php artisan make:migration create_data_table_migration
Created Migration: 2016_04_09_053441_create_data_table_migration
Lets edit that file, database/migrations/2016_04_09_053441_create_data_table_migration.php
to create a table with the fields that we will need using the Schema Builder and Blueprint.
public function up()
{
Schema::create('data', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('value');
$table->timestamps();
});
}
public function down()
{
Schema::drop('data');
}
We use the down()
method that would be called when we rollback, refresh, or reset the migrations, to make sure any changes this migration makes can be reversed, in the context of the schema.
To follow the naming convention that Eloquent will use by default you would name your tables in the plural form. In our case this table name is a word that is the same singular and plural.
We can run our migrations to setup our database tables.
⚡ artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrated: 2016_04_09_053441_create_data_table_migration
Note: Laravel comes with two migrations, one for creating the
users
table and the other for creating thepassword_resets
table.
Another lovely artisan
command is tinker
, an interactive shell for your Laravel application. We are going to create our user real quick using this cli tool.
⚡ php artisan tinker
Psy Shell v0.7.2 (PHP 7.0.5-2+deb.sury.org~wily+1 — cli) by Justin Hileman
>>> $credentials = [
... 'name' => 'admin',
... 'email' => 'admin@admin',
... 'password' => bcrypt('test')
... ];
=> [
"name" => "admin",
"email" => "admin@admin",
"password" => "$2y$10$uw1GOP/OwmxPxZGP.E4KOOfvXZGHld/s.V7Cr5N1IAw7j6Fpu.zNu",
]
>>> $user = App\User::create($credentials);
=> App\User {#639
name: "admin",
email: "admin@admin",
updated_at: "2016-04-09 05:47:35",
created_at: "2016-04-09 05:47:35",
id: 1,
}
As simple as that, we have a user in our database.
At this point we really haven't done any coding and we have come a long way. Lets add the authentication scaffolding to our application. Once again the artisan
cli can be used again.
⚡ artisan make:auth
Created View: /var/www/html/sites/letsdothis/resources/views/auth/login.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/auth/register.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/auth/passwords/email.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/auth/passwords/reset.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/auth/emails/password.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/layouts/app.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/home.blade.php
Created View: /var/www/html/sites/letsdothis/resources/views/welcome.blade.php
Installed HomeController.
Updated Routes File.
Authentication scaffolding generated successfully!
This helpful little command has given us a head start on a simple frame for our application. It has provided us with view templates, a HomeController and updated our routes file for us.
If you refresh your site you will see that you have a new layout and some links. Click on the Login
link in the header and enter the credentials we used to create our user and click the login button.
Still without much code written at all, we have a basic site with authentication up and running.
To use our data
table we will create an Eloquent Model for our table. Guess what we will use to do this? Thats right, artisan
cli.
⚡ php artisan make:model Data
Model created successfully.
We will set the fillable
attributes for this model. (app\Data.php
)
namespace App;
use Illuminate\Database\Eloquent\Model;
class Data extends Model
{
protected $fillable = ['name', 'value'];
}
Now some code, but first ... artisan
cli :).
⚡ php artisan make:controller --resource DataController
Controller created successfully.
This will create a RESTful Resource Controller for us in app/Http/Controllers
. Lets open this up make some adjustments and add some functionality.
namespace App\Http\Controllers;
use App\Data;
use App\Http\Requests;
use Illuminate\Http\Request;
class DataController extends Controller
{
protected $rules = [
'name' => 'required',
'value' => 'required'
];
public function __construct()
{
$this->middleware('auth', ['except' => ['index', 'show']]);
}
public function index()
{
$data = Data::paginate(20);
return view('data.index', compact('data'));
}
public function create()
{
$data = new Data;
$action = 'Create';
return view('data.edit', compact('action', 'data'));
}
public function store(Request $request)
{
$this->validate($request, $this->rules);
Data::create($request->only(['name', 'value']));
return redirect()->route('data.index')->with('msg', 'Data was created.');
}
public function show(Data $data)
{
return view('data.show', compact('data'));
}
public function edit(Data $data)
{
$action = 'Update';
return view('data.edit', compact('data', 'action'));
}
public function update(Request $request, Data $data)
{
$this->validate($request, $this->rules);
$data->update($request->only(['name', 'value']));
return redirect()->route('data.index')->with('msg', 'Data was updated.');
}
public function destroy(Data $data)
{
$data->delete();
return redirect()->route('data.index')->with('msg', 'Data was deleted.');
}
}
These are the CRUD methods and the functionality involved with these operations. This is a super simplified example that includes validation, dependency injection, model bindings and flash data.
... MORE INFORMATION ...
Adding the routes for this controller is very simple with Laravel. We will open the routes.php
file in app\Http
and add the following:
Route::resource('data', 'DataController');
Thats it. We now have 7 routes for us that correspond to the 7 methods of our DataController
.
Note: At any time you can check to see how your routes are registered with the application via the
artisan
cli commandroute:list
.
Several of these routes take parameters which will be passed to our controller methods. These parameter names correspond to the name of the parameter we used in those method signatures. Because we type-hinted the $data
variables as Data
the router will actually try to find a Data
model by id
that corresponds to the parameter that is passed via the URL, and pass that to our Controller method instead of the actual passed parameter from the URL.
... MORE INFORMATION ...
Almost done, believe it or not.
We have the model, we have the controller, we just dont have any views for our CRUD for data. We are going to need a index, show and edit/new view.
Create a folder in resources/views
named data
and create 3 files, index.blade.php
, show.blade.php
, edit.blade.php
.
We are going to quickly install the Laravel Collective's HTML & Form package to help with our forms.
⚡ composer require laravelcollective/html
When this finishes downloading we will add the Service Provider and alias the Facades.
Open up config/app.php
and add the following to the $providers
array:
Collective\Html\HtmlServiceProvider::class,
and add the following to the $aliases
array:
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class,
That package is now installed and ready to use.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">
Data
</div>
<div class="panel-body">
@if (Session::has('msg'))
<div class="alert alert-info">
<p>
{{ Session::get('msg') }}
</p>
</div>
@endif
@if (Auth::check())
<span class="pull-right">
<a href="{{ route('data.create') }}" class="btn btn-success">Add New Data</a>
</span>
@endif
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Value</th>
<th>Created At</th>
@if (Auth::check())
<th>Actions</th>
@endif
</tr>
</thead>
<tbody>
@forelse($data as $item)
<tr>
<th scope="row"><a href="{{ route('data.show', [$item]) }}">{{ $item->id }}</a></th>
<td><a href="{{ route('data.show', [$item]) }}">{{ $item->name }}</a></td>
<td>{{ $item->value }}</td>
<td>{{ $item->created_at->diffForHumans() }}</td>
@if (Auth::check())
<td>
<a href="{{ route('data.edit', [$item->id]) }}" class="btn btn-primary">Edit</a>
<form method="POST" action="{{ route('data.destroy', [$item->id]) }}" style="display:inline">
<input type="hidden" name="_method" value="DELETE">
{{ csrf_field() }}
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</td>
@endif
<td></td>
</tr>
@empty
<tr>
<td colspan="{{ 4 + Auth::check() }}" align="center">No Data to display.</td>
</tr>
@endforelse
</tbody>
</table>
{{ $data->render() }}
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">{{ $action }} Data</div>
<div class="panel-body">
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
{{ Form::model($data, [
'route' => $data->exists ? ['data.update', $data] : 'data.store',
'class' => 'form',
'role' => 'form',
'method' => $data->exists ? 'PUT' : 'POST'
]) }}
<div class="form-group {{ $errors->has('name') ? 'has-error' : '' }}">
<label for="name">Name</label>
{{ Form::text('name', null, [
'class' => 'form-control',
'placeholder' => 'Name'
]) }}
</div>
<div class="form-group {{ $errors->has('value') ? 'has-error' : '' }}">
<label for="value">Value</label>
{{ Form::textarea('value', null, [
'class' => 'form-control',
'placeholder' => 'Value'
]) }}
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
{{ Form::close() }}
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">
Data
</div>
<div class="panel-body">
<div>
<strong>Name:</strong>
<p>
{{ $data->name }}
</p>
</div>
<div>
<strong>Value:</strong>
<p>
{{ $data->value }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
Open up resources/views/layouts/app.blade.php
and find the left side of the navbar section and replace it as so:
<!-- Left Side Of Navbar -->
<ul class="nav navbar-nav">
<li><a href="{{ url('/home') }}">Home</a></li>
<li><a href="{{ route('data.index') }}">Data</a></li>
</ul>
You have now finished your basic run through of simple CRUD with authentication on Laravel 5.2.
I have moved this to my blog to continue this series.
asklagbox - blog