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