Created Friday 08 March 2019
Ait, the new job requires it. Let's get started with this, apparently, awesome framework.
Cheatsheet: https://cheats.jesse-obrien.ca/
Installation
# You will be requiring laravel via composer, so make sure that is installed.
# Also make sure that composer is in your $PATH (.bashrc i.e.)
# Then install laravel
$ composer global require "laravel/installer"
Usage
# There's quite a lot to do with laravel and its components
Create project
# Now that laravel is installed, you can use the laravel command
# Navigate to the folder, where you want the new project to be (www)
$ laravel new ProjectName
Artisan
# If you navigate to the newly create project ProjectName you can use a lil' extra "php" commands
# To get an overview - don't worry, you should learn with time.
$ php artisan
Server
# While in the project folder, start a deployment server
$ php artisan serve
# Now you can navigate to http://127.0.0.1:8000/ and see the default laravel page (new project)
Project files
# route > web.php
# Shows the URL paths/locations (sub pages) and what view they return
# Copy the already existing function, to create more sub pages (remember to change the / )
# resources > views
# The views that can be returned via route
# It seems like the names of the files (views) needs a .blade.php suffix (i.e. contact.blade.php )
Create a layout file
# Like in my own TinyMVC, where root folders index.php has all the "static" data for all pages
# The "layout"-ish page, which then loads all the content via that page.
# In the views folder, create a layout.blade.php file.
# Create the HTML typical document and place a @yield('') which in return will be called from the
# other documents. It'll indicate that this is where we want the content, from other views, to
# be displayed. Below is simplified.
<html>
<head></head>
<body>
// Maybe you have a menu here
@yield('content')
// Maybe a footer here
</body>
</html>
# In our next view, about i.e, (empty doc, the HTML is already defined in the layout)
@extends('layout')
@section('content')
<h3>Some fancy text</h3>
@endsection
# Everything in the section part will now be piped into the layout, at the @yield place.
Database migration
# Remember to define the .env file in the root directory for your database credencials
# The DB also needs to be created it would seem.
# Say we would like to create a table in our DB that holds links
$ php artisan make:migration create_links_table --create=links
# The create_links_table is the file that gets created in database/migrations and
# links, after the --create, will be the name of the table.
# Then open the database/migration/_create_links_table document,
# In the up method we will be defining the columns.
# It should already hold the id and timestamp columns.
public function up()
{
Schema::create('links', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->string('url')->unique();
$table->text('description');
$table->timestamps();
});
}
# Then run the migration
$ php artisan migrate
Lipsum (fake/test) data to the DB
# Quite good for testing I guess.
# These parts I don't fully understand yet, but fancy it was.
# So out above table, with a title, url and a description, let's fill that with test data
$ php artisan make:model --factory Link
# This will create a factory file in the database/factories folder, called LinkFactory.php
# Then plug in the the columns we've created, title, url and description
$factory->define(App\Link::class, function (Faker $faker) {
return [
'title' => $faker->sentence(3),
'url' => $faker->url,
'description' => $faker->paragraph
];
});
# Apparently the $faker model holds quite a few methods, properties and the like,
# to generate our test data - Awesome mayn.
# Alright, next up is to create a seeder.
$ php artisan make:seeder LinksTableSeeder
# This will create a file in database/seeds
# I don't understand this, but add this in the run() method
public function run()
{
factory(App\Link::class, 5)->create();
}
# Guess it's something like, the factory class Link, and the numeric value is the number of rows.
# should be created (from a create() method I can't really find in the factory file.. Oh well)
# Anyway, to activate that seeder, you have to run it from the MAIN seeder file - DatabaseSeeder
# which is also found in the seeder folder. So add this to the run() method:
public function run()
{
$this->call(LinksTableSeeder::class);
}
# Now that it's all set up, let's populate the table with some data!
$ php artisan migrate:fresh --seed
# Voila, you now have 5 rows of test data in the database table.
Routing w/ additional data (variables, arrays etc)
# Alright, so if we want to pass our newly created database data to the view
# Edit the route/web.php file (the MAIN routing doc)
Route::get('/', function () {
// Collect the links
$links = \App\Link::all();
// Return them with the view
return view('welcome', ['links' => $links] );
});
# The second argument can be an array of data, and the key-value ends up
# being the variable name in the template file.
# Other ways of doing this, instead of passing a second parameter
// with()
return view('welcome')->with('links', $links);
// dynamic method to name the variable
return view('welcome')->withLinks($links);
# Now edit the welcome.blade.php doc (view)
# For new projects you will of course have some HTML already, for the default page
# Just append this for the proof of concept
@foreach ($links as $link)
<a href="{{ $link->url }}">{{ $link->title }}</a>
@endforeach
Create a submit form
# Continued with database we've already have, links
# First, create a new route in the you-know-what file (you should by now at least..)
Route::get('/submit', function () {
return view('submit');
});
# We're calling a /submit sub-page, so create a submit.blade.php in the view as well
# It actually seems this blade is a template engine
# Create a quick layout file in views/layouts/app.blade.php (create the folder if needed)
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
<!--This is the master sidebar.-->
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
# I'll break it down step by step, creating a blade template/ submit view
# There is quite a few goodies along the way.
@extends('layout.app')
@section('content')
<div class="container">
<div class="row">
<h1>Submit a link</h1>
<form method="post" action="/submit">
</form>
</div>
</div>
@endsection
# Pretty self-explained. Bootstrap seems available from the beginning.
Checking for User Input errors
# Here's a nice little goodie. If any errors is caught, then nicely display them.
<form method="post" action="/submit">
@if ( $errors->any() )
<div class="alert alert-danger" role="alert">
Fix the following errors
</div>
@endif
</form>
# So, as you see, we are asking to fix the FOLLOWING errors.
# That is because, that each of the the form groups we are gonna create will have validation
# Alright, so let's have a look at one of our form groups - This one for the title
<div class="form-group{{ $errors->has('title') ? ' has-error' : '' }}">
<label for="title">Title</label>
<input type="text"
class="form-control"
id="title"
name="title"
placeholder="Title"
value="{{ old('title') }}">
@if( $errors->has('title') )
<span class="help-block">{{ $errors->first('title') }}</span>
@endif
</div>
# Each field/group will do a validation and display an error if has-error class is set for that group
# The (the value) will be the input that the user typed (stored in a session)
# If a field has an error, the $errors->first() will return the first error for that field
Continue with the submit form/page
# Now, because we aren't securing this form against cross-site request forgery,
# we'll exclude laravel from performing that security check, which apparently is default.
# Include this right after defining the form: {!! csrf_field() !!}
# So, all in all, the whole submit view document should look like this:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<h1>Submit a link</h1>
<form method="post" action="/submit">
{!! csrf_field() !!}
@if( $errors->any() )
<div class="alert alert-danger" role="alert">
Fix the following errors
</div>
@endif
<!-- Title -->
<div class="form-group{{ $errors->has('title') ? ' has-error' : '' }}">
<label for="title">Title</label>
<input type="text"
class="form-control"
id="title"
name="title"
placeholder="Title"
value="{{ old('title') }}">
@if( $errors->has('title') )
<span class="help-block">{{ $errors->first('title') }}</span>
@endif
</div>
<!-- URL -->
<div class="form-group{{ $errors->has('url') ? ' has-error' : '' }}">
<label for="title">URL</label>
<input type="text"
class="form-control"
id="url"
name="url"
placeholder="URL"
value="{{ old('url') }}">
@if( $errors->has('url') )
<span class="help-block">{{ $errors->first('url') }}</span>
@endif
</div>
<!-- Description -->
<div class="form-group{{ $errors->has('description') ? ' has-error' : '' }}">
<label for="title">Description</label>
<input type="text"
class="form-control"
id="description"
name="description"
placeholder="Description"
value="{{ old('description') }}">
@if( $errors->has('description') )
<span class="help-block">{{ $errors->first('description') }}</span>
@endif
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
@endsection
Route (and input validation continued)
# Now that our submit view page is created, our route document needs an additional method
# for the POST request. This new route method will also be the backbone for input validation
Route::post('/submit', function(Request $request) {
$data = $request->validate([
'title' => 'required|max:255',
'url' => 'required|url|max:255',
'description' => 'required|max:255'
]);
$link = new App\Link($data);
$link->save();
// Alternative you could do like this:
// $link = tap(new App\Link($data))->save();
//
// The tab() allows to quickly create an instance of the model
return redirect('/');
});
# So the $request model has a validate method.
# We are saying each is required, that each can be max 255 characters, and URL need to be
# validated as an URL. Voila. Peace of pie.
# As you can see, we are sending the $data forward to the Link model.
# If you were to open that document, app/Link.php, it's just an empty model - Let's fix.
# So we need to tell it which data we can populate it with:
class Link extends Model
{
protected $fillable = ['title', 'url', 'description'];
}
# Now everything should be a-okay! The landing page should have the links, probably the
# 5 test rows from we've created earlier (database seeding) and if you navigate to
# /submit and fill out he form, it will create it to the database and send you back to the landing