Laravel -> Table of Contents:
A) Composer
1) Do I Even Have Composer?
2) Composer Installation
B) Laravel Installation
1) Laravel Version
2) Installation
C) PHP Storm / Laravel Plugins
A) Set Up Directory / Install Laravel Infrastructure
B) Virtual Host
1) Apache
2) host file
A) app
1) Console
2) http
a) Controllers
b) Middleware
B) bootstrap
C) config
D) database
E) public
F) resources
1) assets
2) lang
3) views
G) routes
H) storage
I) tests
J) vendor
K) env
A) web.php (route to view)
B) PublicController (route to controller)
C) Groups
D) Passing Parameters in Your Routes
1) Single Parameter Using a Route
2) Single Parameter Using Controller
3) Multiple Parameters Using Controller
E) Namespaces (organizing your Controllers)
1) Create Controller
2) Create Route
3) Document Namespace and "use"
F) Route Names
1) Passing a Variable
2) Passing Multiple Variables
i) Route
G) Redirect
A) Create Middleware (Terminal Command)
B) Register Middleware
C) Use Your Middleware
1) Kernel.php
2) web.php (routes)
D) Assign Middleware
A) Connection
B) Migration
C) Migration Functions
1) Change Column Name
2) Change Default Value
C) Models
D) Seeders, Factories and Faker
1) Factories
2) Seeder
A) Master View
B) Passing Variables
C) Passing Variables Globally
1) AppServiceProvider.php
2) .env file
D) Loops
E) Includes
F) Helpers / Active Links
A) contact.blade.php
B) Route
C) Controller
1) Single Field
D) File Upload
1) File Upload Field
2) Controller
E) How to Handle an Array of Inputs
A) Basic Setup
B) Import Front End Assets
C) Create Other Pages
1) Create Route
2) Create PublicController
3) Create View
4) Create master.blade.php
D) Asset Helper
E) Authentication
1) mailtrap.io
F) Navigation
1) navigation.blade.php
G) Admin Panel Assets
1) AdminController
2) Admin Route
3) Dashboard Blade
H) Protecting Admin Panel
1) Create and Register CheckRole Middleware
2) Edit CheckRole Middleware
a) Create CheckRole
b) Register CheckRole
c) Run CheckRole
I) Login Page
1) auth.blade.php
2) login.blade.php
J) Dashboard
K) Dashboard Navigation
1) Login Name
2) Sidebar Links
3) Logout
L) Creating, Migrating, Seeding...Posts and Comments Table
M) Displaying Posts & Comments
1) Dynamic Title
2) welcome.blade.php / Post.php Model / Public Controller
N) Displaying Single Post & Comments
A) Setting Up the Database and Database Content
1) composer create-project (import from Github)
2) database / .env file
3) migration
i) create migration file / adust AppServiceProvider.php
ii) create seeder file
iii) Adjust DatabaseSeeder.php File
iv) Make Article Factory
v) Make Model
vi) Create Tables
vii) Add Dummy Data
B) Setting Up Controllers, Routes & Resources
1) List Articles
i) ArticlesController.php
ii) api.php (routes)
iii) Resource
iv) Postman / API in Action
2) Display Article
3) Add / Edit Article
4) Delete Article
C) Vue.js
1) Install Dependencies and "npm run watch"
i) Bringing Files from One Project to Another
ii) package.json
iii) composer.json
2) Basic Files
i) npm run watch
ii) welcome.blade.php
iii) app.js
iv) Articles.vue
3) Cadillac Display
4) Delete Article
5) Add Article Form
A) Incorporating Security
1) Setup Database
B) Positioning of Login | Register Links
1) welcome.blade.php
2) style.css
C) User Login and Administrator
D) Pages
1) Pages Table
2) Insert Pages
$ composer
______
/ ____/___ ____ ___ ____ ____ ________ _____
/ / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
/_/
Composer version 1.8.4 2019-02-11 10:52:10
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
--profile Display timing and memory usage information
--no-plugins Whether to disable plugins.
-d, --working-dir=WORKING-DIR If specified, use the given directory as working directory.
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
about Shows the short information about Composer.
archive Creates an archive of this composer package.
browse Opens the package's repository URL or homepage in your browser.
check-platform-reqs Check that platform requirements are satisfied.
clear-cache Clears composer's internal package cache.
clearcache Clears composer's internal package cache.
config Sets config options.
create-project Creates new project from a package into given directory.
depends Shows which packages cause the given package to be installed.
diagnose Diagnoses the system to identify common errors.
dump-autoload Dumps the autoloader.
dumpautoload Dumps the autoloader.
exec Executes a vendored binary/script.
global Allows running commands in the global composer dir ($COMPOSER_HOME).
help Displays help for a command
home Opens the package's repository URL or homepage in your browser.
i Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
info Shows information about packages.
init Creates a basic composer.json file in current directory.
install Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
licenses Shows information about licenses of dependencies.
list Lists commands
outdated Shows a list of installed packages that have updates available, including their latest version.
prohibits Shows which packages prevent the given package from being installed.
remove Removes a package from the require or require-dev.
require Adds required packages to your composer.json and installs them.
run-script Runs the scripts defined in composer.json.
search Searches for packages.
self-update Updates composer.phar to the latest version.
selfupdate Updates composer.phar to the latest version.
show Shows information about packages.
status Shows a list of locally modified packages, for packages installed from source.
suggests Shows package suggestions.
u Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
update Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
upgrade Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
validate Validates a composer.json and composer.lock.
why Shows which packages cause the given package to be installed.
why-not Shows which packages prevent the given package from being installed.
Otherwise, you'll just get $composer
bash: composer: command not found
2) Composer Installation (back to top...)
You'll use the Composer installer which will pretty much take care of everything. Don't worry about the "developer" option. Just install it and you'll be gold.
That will create all the files and dependencies you need to start you new Laravel project. The only thing that you need to ensure is that when the prompt comes up that declares the PATH to your php.exe file - that path needs to be accurate. Provided that's in place, you'll be able to successfully call Composer from anywhere. And don't worry about a "proxy server." Just blow past that for now.
Ran into a little problem with Composer when I first set it up. Wound up deleting it, reinstalling it and making a point of closing down the Command Prompt before attempting to set up a Laravel project. After that everything worked great.
B) Laravel Installation (back to top...)
1) Laravel Version (back to top...)
To determine what version of Laravel you're running, navigate to the directory where you've got your Laravel app and type this into your Command Line:
php artisan --version
Make sure you're in the directory where your Laravel application is located. Otherwise, you'll get a response that suggests you don't even have Laravel installed.
2) Installation (back to top...)
To install Laravel, type this in your Command Line (again, shut down your Command Line app and open it up again to ensure that the Composer dynamic you just installed is recognized by Command Line as being present).
composer global require laravel/installer
That will install Laravel. Quit your Command Line interface and restart it. Type in laravel -h to see if you're running Laravel and if you get a screen that lists a number of Laravel commands, you're all set!
Now you're ready to begin your project!
You can also go out to https://laravel.com/docs/5.8 and copy and paste this line of code that you can retrieve from that site
C) PHP Storm / Laravel Plugins (back to top...)
You can install some "Laravel Helpers" that allow PHP Storm to fill in some gaps and make your coding a little easier. Do this by going to "File -> Settings" and navigate to "Plugins." Do a search for "Larvel" and install it.
After that, you'll want to navigate to "File -> Settings -> Languages & Frameworks -> Laravel" and activate that plugin for your project (see image to the right).
A) Set Up Directory / Install Laravel Infrastructure (back to top...)
Use this command to set up your directory and the necessary files to kick off your project.
C:\wamp64\www>composer create-project laravel/laravel new blog
B) Virtual Host (back to top...)
What you're doing here is setting up your "virtual host" (localhost) in a way that resembles the manner in which your actual user is going to access your site. You've got to adjust two files to make that happen.
The goal is to bring up the "blog" site in your "localhost" without having to type http://localhost/blog/public. We're going to change that so all we need to do is type blog.test.
1) Apache (back to top...)
Right now, provided your WAMP was running, you could go to http://localhost/blog/public/ and everything would be running just fine. For the sake of this tutorial, however, we're going to adjust our Apache httpd-vhost.conf file to accommodate a more streamlined URL.
Go to C:\wamp64\bin\apache\apache2.4.23\conf\extra and navigate to your "httpd-vhost.conf" file and add this line:
<VirtualHost *:80>
ServerName blog.test
DocumentRoot c:/wamp/www/blog/public
</VirtualHost>
2) host file (back to top...)
Now, open up a Notepad application and choose "Run as Administrator." Navigate to your C:\Windows\System32\drivers\etc and open up your host file. You'll most likely have to choose the "Show All Files" option in order to see it.
Add this line: 127.0.0.1 blog.test.
Restart Apache and you should be gold! All you need to do is head out to "blog.test."
The first page you're looking at is based off of the routes/web.php file which has this:
Route::get('/', function () {
return view('welcome');
});
That's opening up the welcome.blade.php page that sitting in resources/views. "blade," by the way, is the template engine that Larvavel uses.
A) app (back to top...)
1) Console (back to top...)
This is where you'll store your Console commands will live. You won't be using this directory that often.
2) http (back to top...)
a) Controllers (back to top...)
This is where your logic lives as per your typical MVC architecture.
b) Middleware (back to top...)
Middleware is the home for that code you may want to execute before the looks in the Controller directory. A good example would be any kind of authentication you want in place.
B) bootstrap (back to top...)
This is where you're going to keep your "cache" file.
C) config (back to top...)
This is what you would expect, as far as you "config" settings. An example would be your "database.php" file which has all the settings you would want access to in order to connect with any one of a number of database types.
D) database (back to top...)
"migrations" let you manage your database structures. "factories" and "seeds" allow you to do "en masse" operations. We'll get into that more later.
E) public (back to top...)
This is your root directory and the only place that's accessible to the client browser.
F) resources (back to top...)
1) assets (back to top...)
The "assets" directory is where you'll keep all of your JavaScript code that needs to be compiled.
2) lang (back to top...)
"lang" is where you'll put your translated words if you're building a multi-language site.
3) views (back to top...)
Here's your "home" for all of your "views" - what your user is going to "see."
G) routes (back to top...)
The only file you need to worry about right now is "web.php." This is where you're going to put your main "routing" for your site.
H) storage (back to top...)
The only directory you need to concern yourself with for right now is the "logs" directory. That's where you're storing your system error logs.
I) tests (back to top...)
This is where you'll keep your unit and functional tests. We'll get into that more later...
J) vendor (back to top...)
Here's where you're keeping all of your supplementary tech. You'll never edit anything in here.
K) env (back to top...)
"env" is a file you want to remember in that it's here where you define all of your database constants. "database.php" is the code, but "env" is where you store your values.
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:UWnrNlE2Ut5/SevmLpcwp4xx1H9fLt5Hx5DmFLhJBXM=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 200;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 13px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@auth
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ route('login') }}">Login</a>
@if (Route::has('register'))
<a href="{{ route('register') }}">Register</a>
@endif
@endauth
</div>
@endif
<div class="content">
<div class="title m-b-md">
Laravel
</div>
<div class="links">
<a href="https://laravel.com/docs">Docs</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://blog.laravel.com">Blog</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:controller PublicController
Here's your route that references the Controller:
Route::get('/', "PublicController@index");
...and now, here's our "PublicController" with the "index" function that returns the "welcome" view:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PublicController extends Controller
{
public function index() {
return view('welcome');
}
}
C) Groups (back to top...)
This is a great way to organize your routes according a particular URL. For example, all of your "blog/admin" routes could be grouped like this:
Route::get('/', "PublicController@index");
Route::prefix('admin')->group(function(){
Route::get('users', function(){
return "admin users";
});
Route::get('posts', function(){
return "admin posts";
});
});
user id: 1
2) Single Parameter Using Controller (back to top...)
You can also do the same thing using your Controller. Here's your Route:
Route::get('user/{userId}', 'PublicController@userInfo');
...and here's your Controller:
public function userInfo($userId) {
return "User ID: ".$userId;
}
Same result as before.
Finally, if you wanted to pass multiple variables in through your URL, you would do this:
3) Multiple Parameters Using Controller (back to top...)
Here's your Controller:
public function userInfo($userId, $name) {
return "User ID: ".$userId. '-' . $name;
}
...and here's your Router:
Route::get('user/{userId}/{name}', 'PublicController@userInfo');
E) Namespaces (organizing your Controllers) (back to top...)
Right now you only have one Controller. That can get pretty cumbersome pretty quick. To break things up a bit so you can keep your code from getting out of control, you use "namespaces."
1) Create Controller (back to top...)
Start by creating another Controller. Call it "UsersController.php."
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:controller UsersController
Now, create another directory in your "Controllers" folder and name it "Admin" and move your new Controller to that directory (see image to the right).
2) Create Route (back to top...)
Here's your Route:
Route::prefix('admin')->group(function(){
Route::get('users', 'Admin\UsersController@listUsers');
Route::get('posts', function(){
return "admin posts";
});
Notice the fact that it has an "address" and the fact that the "\" is a backward slash. You can't use a forward slash.
a) Namespace Route Shortcut (back to top...)
You can also do this:
Route::namespace('Admin')->prefix('admin')->group(function(){
Route::get('users', 'UsersController@listUsers');
Route::get('posts', function(){
return "admin posts";
});
Notice the addition of the namespace dynamic. Plus, you don't have the "Admin" entity like you did before...
Here's what it was: Route::get('users', 'Admin\UsersController@listUsers');
Here's what you've got now:
Route::get('users', 'UsersController@listUsers');
A neat little way to keep things organized without having to document the namespace over and over again...
3) Document Namespace and "use" (back to top...)
...and here's your Controller:
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UsersController extends Controller
{
public function listUsers() {
return "list users = admin/users controller";
}
}
Notice the way the "namespace" is documented and the way "use" is referenced as well.
And that will do it!
F) Route Names (back to top...)
Hardcoding a specific URL isn't necessarily a good idea, especially if you wind up changing your domain.
You can "name" your routes so you don't have to worry about specifying a particular domain.
Here's how you do it:
Route::get('/', "PublicController@index")->name('welcome'); //here I'm naming my route
Route::get('posts', function(){
return route('welcome');
});
Now, when I go out to "http://blog.test/admin/posts," I get this:
http://blog.test
...and that makes sense because the whole route is based on "/"...
1) Passing a Variable (back to top...)
If you had to pass a variable through your route name, you would do it this way:
Here's your "web.php" page:
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/{name}', "PublicController@index")->name('welcome');
Route::namespace('Admin')->prefix('admin')->group(function(){
Route::get('users', 'UsersController@listUsers');
Route::get('posts', function(){
return route(name: 'welcome', parameters: "Bruce");
});
});
http://blog.test/Bruce
2) Passing Multiple Variables (back to top...)
i) Route (back to top...)
To pass mulitple variables, you use an array configuration. Here's your Route:
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/{name}/{$age}',"PublicController@index")->name('welcome');
Route::namespace('Admin')->prefix('admin')->group(function(){
Route::get('users', 'UsersController@listUsers');
Route::get('posts', function(){
return route('welcome', ['name'=>'Bruce', 'age' => '56']);
});
});
http://blog.test/Bruce/56
Notice that you don't have to worry about your Controller, as far as populating the Route with content.
G) Redirect (back to top...)
Easy - peasy...
Route::redirect('/old', '/new', 301);
A) Create Middleware (Terminal Command) (back to top...)
To create your Middleware functionality, type this into your Terminal:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:middleware CheckAge
Middleware created successfully.
B) Register Middleware (back to top...)
1) Kernel.php (back to top...)
In your "Http" directory, you've got a file called, "Kernel.php." Here's where you're going to register your Middleware.
You've got more than one option. The one we're going with in this case is the one that allows you to assign it to a group or an individual route:
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'checkAge' => \App\Http\Middleware\CheckAge::class
];
list users = admin/users controller
D) Assign Middleware (back to top...)
Previously, you assigned some Middleware to a specific route. You can also assign it to a Controller which will affect multiple routes. You just put it in the corresponding Controller. In this case, we're altering the "UsersController.php."
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UsersController extends Controller
{
public function __construct() {
$this->middleware('checkAge');
}
public function listUsers() {
return "list users = admin/users controller";
}
}
Migrations are like version control for your database, allowing your team to easily modify and share the application's database schema. Migrations are typically paired with Laravel's schema builder to easily build your application's database schema. If you have ever had to tell a teammate to manually add a column to their local database schema, you've faced the problem that database migrations solve.
Here's the way it looks in real life. The command is create_posts_table "posts" is the name of your table. That's the first part of the command. The second part is what you see, as far as the --create posts. With this command, you're not just creating a table, you're doing it in a way that's documented so other people working on the same app are alterted to what you've done.
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:migration create_posts_table --create=posts
After you do that, you'll see a record of that in your database->migrations file. It looks like this:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string( 'title')❶ ->default('my title');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan migrate
...and just like that, you're table is created along with another table that documents your migrations.
Pretty cool!
And, if you want to roll all that back, all you need to do is:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan migrate:rollback
...and that will kill your "posts" table.
C) Migration Functions (back to top...)
1) Change Column Name (back to top...)
You can use your terminal to rename columns in your database, although you need a new package to do that.
Using "composer," you'll type this into your terminal:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ composer require doctrine/dbal
\Once that's installed, you'll do this:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:migration rename_content_to_body --table=posts
Understand, this is just manufacturing a "migration" doc. This doesn't actually change the name of the column. To do that, you've got to go to the newly formed migration file named, "rename_content_to_body."
Once you're there, you'll add this syntax:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RenameContentToBody extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('content', 'body');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('body', 'content');
});
}
}
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan migrate
That will change the name of the column, "content" to "body."
2) Change Default Value (back to top...)
You can change the default value of your column by first creating your migration file...
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:migration change_default_value_of_title --table=posts
...and then entering the highlighted syntax to that new migration file:
<p?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class ChangeDefaultValueOfTitle extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->string( 'title')->default('Nice title')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function (Blueprint $table) {
//
});
}
}
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:model Post
The name "Post," will automatically assume you're going to be interacting with the "post" table.
D) Seeders, Factories and Faker (back to top...)
1) Factories (back to top...)
Factories are a feature that Laravel provides to help you test your data.
You start by using your Terminal to create a "factory" file:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:factory PostFactory
Once it's made, you'll document the code like this in your new file:
<?php
/* @var $factory \Illuminate\Database\Eloquent\Factory */
use App\Model;
use Faker\Generator as Faker;
/* @var $factory \Illuminate\Database\Eloquent\Factory */
$factory->define(App\Post::class, function(Faker $faker) {
return [
'title' => \Faker\Provider\Lorem::sentence($nbWords = 6, $variableNbWords = true),
'body' => \Faker\Provider\Lorem::paragraph($nbSentences = 3, $variableNbSentences = true)
];
});
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan make:seeder PostSeeder
Now, once that file has been created, here's the code:
<?php
use Illuminate\Database\Seeder;
class PostSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
❶ factory(App\Post::class, 10)->create()->each(function($u) {
❷ $u->issues()->save(factory(App\Post)::class)-> make());
});
}
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ composer dump-autoload
At this point, you're going to use the "DatabaseSeeder.php" page to "seed" your database. You can document things on the actual php page, or you can do it via the Terminal like this:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/blog
$ php artisan db:seed --class=PostSeeder
And that will populate your database with 10 rows of dummy data!
A) Master View (back to top...)
First, you've got your "web.php" which is your "route" configuration:
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('posts', "PublicController@displayPosts")->name('displayPosts');
Route::namespace('Admin')->prefix('admin')->group(function(){
Route::get('users', 'UsersController@listUsers');
Route::get('posts', function(){
return route('welcome', ['name' => 'Bruce', 'age' => '56']);
});
});
Route::view('/', 'welcome');
Route::view('/about', 'about');
❶ @extends('Layouts.master')
❷ @section('content')
<div class="title m-b-md">
Laravel
</div>
<div class="links">
<a href="https://laravel.com/docs">Docs</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://blog.laravel.com">Blog</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
@endsection
class PublicController extends Controller
{
public function index() {
❶ $title = "Muscular Christianity";
return view('welcome', ❷ compact( 'title'));
}
}
@extends('Layouts.master')
@section('content')
<div class="title m-b-md">
{{ $title }}
</div>
<div class="links">
<a href="https://laravel.com/docs">Docs</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://blog.laravel.com">Blog</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
@endsection
class PublicController extends Controller
{
public function index() {
$title = "Muscular Christianity";
$title]);
}
}
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
❶ use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
❷ View::share('title', 'Muscular Christianity');
}
}
class PublicController extends Controller
{
public function index() {
$posts = Post::all();
return view('welcome', compact('posts'));
}
}
@extends('layouts.master')
@section('content')
❶ <form method="Post" action="{{ route('contactPost') }}">
❷ @csrf
<div class="form-group">
<input class="form-control" type="text" placeholder="Name" name="name">
</div>
<div class="form-group">
<input class="form-control" type="email" placeholder="Email" name="email">
</div>
<div class="form-group">
<textarea class="form-control" id="" cols="30" rows="10" name="message" placeholder="Message..."></textarea>
</div>
<div class="form-group">
<button type="submit" class="form-control">Send message</button>
</div>
</form>
@endsection
public function contactPost(Request $request) {
❶ if($request->hasFile('attachment')) {
❷ $file = $request->file('attachment');
❸ $filename = $file->getClientOriginalName();
❹ $file->move('images', $filename);
}
else
{
return "no";
}
public function contactPost(Request $request) {
if($request->hasFile('attachment')) {
$file = $request->file('attachment');
$filename = $file->getClientOriginalName();
$file->move('images', $filename);
}
$name=$request['email'];
var_dump($name);
}
C:\wamp64\www\ laravel new personal-blog
After that, you're going to want to configure your browser so it automatically goes to the correct home page.
B) Import Front End Assets (back to top...)
You can download an entire look and feel for free without having to start from scratch.
BOOM!
Head out to https://startbootstrap.com/themes/creative/ and download the zip file.
Copy and paste all of the files into your "assets" directory. Then delete everything except the css, img, js and vendor folders.
Grab the HTML code that is rendered when you go to "personal.blog/assest/index.html." Copy that into your "welcome.blade.php" page and then add "assets" to the appropriate URLs so your page renders correctly.
Like this:
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template -->
<link href="assets/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template -->
<link href="assets/css/clean-blog.min.css" rel="stylesheet">
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:controller PublicController
After you make that Controller, add this code to accommodate your page...
class PublicController extends Controller
{
public function index() {
return view('welcome');
}
}
3) Create View (back to top...)
You've already got the "welcome.blade.php" view page, so you're set.
To add new pages, you'll repeat the above process sans the creation of the PublicController...
You can get those pages by heading out to the following links:
This is great, but if you were to look at the pages, you'll notice that the C SS is all squirreled up. To remedy that, we're going to create a "master.blade.php" page that will provide all of the CSS / layout dynamics that we need that we can then easily apply to all of the pages.
4) Create master.blade.php (back to top...)
This is your "master.blade.php" page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Clean Blog - Start Bootstrap Theme</title>
<!-- Bootstrap core CSS -->
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template -->
<link href="assets/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template -->
<link href="assets/css/clean-blog.min.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about.html">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="post.html">Sample Post</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contact.html">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
@yield('content');
<!-- Footer -->
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">Copyright © Your Website 2019</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap core JavaScript -->
<script src="assets/vendor/jquery/jquery.min.js"></script>
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for this template -->
<script src="assets/js/clean-blog.min.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Clean Blog - Start Bootstrap Theme</title>
<!-- Bootstrap core CSS -->
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template -->
<link href="assets/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template -->
<link href="assets/css/clean-blog.min.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about.html">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="post.html">Sample Post</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contact.html">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Page Header -->
<header class="masthead" style="background-image: url('img/home-bg.jpg')">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Man must explore, and this is exploration at its greatest
</h2>
<h3 class="post-subtitle">
Problems look mighty small from 150 miles up
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on September 24, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
I believe every human has a finite number of heartbeats. I don't intend to waste any of mine.
</h2>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on September 18, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Science has not yet mastered prophecy
</h2>
<h3 class="post-subtitle">
We predict too much for the next year and yet far too little for the next ten.
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on August 24, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Failure is not an option
</h2>
<h3 class="post-subtitle">
Many say exploration is part of our destiny, but it’s actually our duty to future generations.
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on July 8, 2019</p>
</div>
<hr>
<!-- Pager -->
<div class="clearfix">
<a class="btn btn-primary float-right" href="#">Older Posts →</a>
</div>
</div>
</div>
</div>
<hr>
<!-- Footer -->
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">Copyright © Your Website 2019</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap core JavaScript -->
<script src="assets/vendor/jquery/jquery.min.js"></script>
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for this template -->
<script src="assets/js/clean-blog.min.js"></script>
</body>
</html>
❶ @extends('layouts.master')
❷ @section('content')
this is your dynamic content - the stuff that's unique to that particular page
<!-- Page Header -->
<header class="masthead" style="background-image: url('img/home-bg.jpg')">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Man must explore, and this is exploration at its greatest
</h2>
<h3 class="post-subtitle">
Problems look mighty small from 150 miles up
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on September 24, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
I believe every human has a finite number of heartbeats. I don't intend to waste any of mine.
</h2>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on September 18, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Science has not yet mastered prophecy
</h2>
<h3 class="post-subtitle">
We predict too much for the next year and yet far too little for the next ten.
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on August 24, 2019</p>
</div>
<hr>
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">
Failure is not an option
</h2>
<h3 class="post-subtitle">
Many say exploration is part of our destiny, but it’s actually our duty to future generations.
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">Start Bootstrap</a>
on July 8, 2019</p>
</div>
<hr>
<!-- Pager -->
<div class="clearfix">
<a class="btn btn-primary float-right" href="#">Older Posts →</a>
</div>
</div>
</div>
</div>
❸ @endsection
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Clean Blog - Start Bootstrap Theme</title>
<!-- Bootstrap core CSS -->
<link href="/assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template -->
<link href="/assets/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template -->
<link href="/ssets/css/clean-blog.min.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about.html">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="post.html">Sample Post</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contact.html">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
@yield('content');
<!-- Footer -->
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">Copyright © Your Website 2019</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap core JavaScript -->
<script src="assets/vendor/jquery/jquery.min.js"></script>
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for this template -->
<script src="assets/js/clean-blog.min.js"></script>
</body>
</html>
As an aside, depending on the language you're using, extends, inheriting and implementing are all words that apply to the same kind of thing in that you're allowing a class (or aspects of that class) to be replicated in different ways throughout your application.
You can read more about extends in that way it's used in PHP by clicking here. Bottom line: The class you're extending is like a parent and the code you're extending it to becomes like a child. You're "extending" the functionality of parent to the child.
Look at the highlighted "@yield('content');" element. That's the way you're telling your "master.blade.php" page to be looking for a section called "content" in any page that constitutes and extension of the "master.blade.php"
D) Asset Helper (back to top...)
All your assets now are currently referenced as relative URLs. You can change them into Absolute URLs by using the Laravel "asset helper."
To start with, you'll do this in your "master.blade.php" page:
<script src="{{asset ('assets/vendor/jquery/jquery.min.js')}}"></script><
...and then for all of your images, you'll do this:
<header class="masthead" style="background-image: url('{{asset ('assets/img/post-bg.jpg')}}">
Notice that you still have to include the "assets" directory in the URL that pertains to both your JS, CSS and image files.
E) Authentication (back to top...)
Start by setting up a database using PhpMyAdmin and then adjusting the login criteria in your ".env" file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=personal-blog
DB_USERNAME=root
DB_PASSWORD=
Next, head out to your "AppServiceProvider.php" page and make the following changes:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
}
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:auth
This will create your migration. To run it, do this:
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan migrate
That will create your tables! In addition, it will set up your Authentication Controllers, Middleware and Views! It's beautiful!
E) Authentication (back to top...)
1) mailtrap.io (back to top...)
We're using mailtrap for the sake of establishing an email paradigm that we can use to test the whole resetting of one's password.
F) Navigation (back to top...)
1) navigation.blade.php (back to top...)
Grab the navigation content from "master.blade.php" and paste it into a new file called "navigation.blade.php" and put that in a new directory called "includes" within your "views" folder.
After that, put this code in your "master.blade.php" page:
@include('includes.navigation')
2) web.php (back to top...)
Give each of your links a name in your "web.php" page:
Route::get('/', 'PublicController@index')->name('index');
Route::get('post/{id}', 'PublicController@singlePost')->name('singlePost');
Route::get('about', 'PublicController@about')->name('about');
Route::get('contact', 'PublicController@contact')->name('contact');
Route::post('contact', 'PublicController@contactPost')->name('contactPost');
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
@if(Auth::check())
<li class="nav-item">
<a class="nav-link" href="{{ route('dashboard') }}">Dashboard</a>
</li>
<li class="nav-item">
<form method="Post" id="logout-form" action="{{ route('logout') }}">@csrf</form>
<a href="#" class="nav-link" onclick="document.getElementById('logout-form').submit();">Logout</a>
</li>
@else
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">Register</a>
</li>
@endif
I had to use a different template. I went out to athemes.com
Under "public" create a new folder called "admin" and in that folder, place the "assets" folder you copied a moment ago.
You're poised on the threshold of great things!
1) AdminController (back to top...)
Create a new Controller that will facilitate all of the admin views that we're going to need.
php artisan make:controller AdminController
Now create a "dashboard" method that will direct the user to the "dashboard" blade.
class AdminController extends Controller
{
public function dashboard()
{
return view('admin.dashboard');
}
}
2) Admin Route (back to top...)
In your "web.php" page, do this:
Route::prefix('admin')->group(function() {
Route::get('/dashboard', 'AdminController@dashboard')->name('adminDashboard');
});
That gets your "dashboard" concept into place. Now let's create that view...
3) Dashboard Blade (back to top...)
Under your "views" directory, create another folder called "admin." This is where you're going to store all of your admin views.
Once you've done that, create a new file called, "dashboard.blade.php." For now now just write the word, "Hi."
Now, when you go out to http://personal.blog/admin/dashboard, you'll see your page.
H) Protecting Admin Panel (back to top...)
1) Create, Register and Run CheckRole Middleware (back to top...)
a) Create CheckRole (back to top...)
We're going to start by creating a new Middleware called "CheckRole."
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:middleware CheckRole
b) Register CheckRole (back to top...)
After you've done that, you have to register it in the "Kernel.php" file which is located in the "http" directory. That's going to look like this:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'checkRole' => \App\Http\Middleware\CheckRole::class,
];
<?php
namespace App\Http\Middleware;
use Closure;
❶ use Illuminate\Support\Facades\Auth;
class CheckRole
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if(❷ Auth::check() == false || Auth::user()->❸ admin != true)
{
return redirect('/');
}
else
{
return $next($request);
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Star Admin Premium Bootstrap Admin Dashboard Template</title>
<!-- plugins:css -->
<link rel="stylesheet" href="../../../assets/vendors/iconfonts/mdi/css/materialdesignicons.min.css">
<link rel="stylesheet" href="../../../assets/vendors/iconfonts/ionicons/css/ionicons.css">
<link rel="stylesheet" href="../../../assets/vendors/iconfonts/typicons/src/font/typicons.css">
<link rel="stylesheet" href="../../../assets/vendors/iconfonts/flag-icon-css/css/flag-icon.min.css">
<link rel="stylesheet" href="../../../assets/vendors/css/vendor.bundle.base.css">
<link rel="stylesheet" href="../../../assets/vendors/css/vendor.bundle.addons.css">
<!-- endinject -->
<!-- plugin css for this page -->
<!-- End plugin css for this page -->
<!-- inject:css -->
<link rel="stylesheet" href="../../../assets/css/shared/style.css">
<!-- endinject -->
<link rel="shortcut icon" href="../../../assets/images/favicon.png" />
</head>
<body>
<div class="container-scroller">
<div class="container-fluid page-body-wrapper full-page-wrapper">
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
<div class="row w-100">
<div class="col-lg-4 mx-auto">
<div class="auto-form-wrapper">
<form action="#">
<div class="form-group">
<label class="label">Username</label>
<div class="input-group">
<input type="text" class="form-control" placeholder="Username">
<div class="input-group-append">
<span class="input-group-text">
<i class="mdi mdi-check-circle-outline"></i>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="label">Password</label>
<div class="input-group">
<input type="password" class="form-control" placeholder="*********">
<div class="input-group-append">
<span class="input-group-text">
<i class="mdi mdi-check-circle-outline"></i>
</span>
</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-primary submit-btn btn-block">Login</button>
</div>
<div class="form-group d-flex justify-content-between">
<div class="form-check form-check-flat mt-0">
<label class="form-check-label">
<input type="checkbox" class="form-check-input" checked> Keep me signed in </label>
</div>
<a href="#" class="text-small forgot-password text-black">Forgot Password</a>
</div>
<div class="form-group">
<button class="btn btn-block g-login">
<img class="mr-3" src="../../../assets/images/file-icons/icon-google.svg" alt="">Log in with Google</button>
</div>
<div class="text-block text-center my-3">
<span class="text-small font-weight-semibold">Not a member ?</span>
<a href="register.html" class="text-black text-small">Create new account</a>
</div>
</form>
</div>
<ul class="auth-footer">
<li>
<a href="#">Conditions</a>
</li>
<li>
<a href="#">Help</a>
</li>
<li>
<a href="#">Terms</a>
</li>
</ul>
<p class="footer-text text-center">copyright © 2018 Bootstrapdash. All rights reserved.</p>
</div>
</div>
</div>
<!-- content-wrapper ends -->
</div>
<!-- page-body-wrapper ends -->
</div>
<!-- container-scroller -->
<!-- plugins:js -->
<script src="../../../assets/vendors/js/vendor.bundle.base.js"></script>
<script src="../../../assets/vendors/js/vendor.bundle.addons.js"></script>
<!-- endinject -->
<!-- inject:js -->
<script src="../../../assets/js/shared/off-canvas.js"></script>
<script src="../../../assets/js/shared/misc.js"></script>
<!-- endinject -->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>@yield('title')</title>
<!-- plugins:css -->
<link rel="stylesheet" href="{{asset ('admin/assets/vendors/iconfonts/mdi/css/materialdesignicons.min.css')}}">
<link rel="stylesheet" href="{{ asset('admin/assets/vendors/iconfonts/ionicons/css/ionicons.css') }}">
<link rel="stylesheet" href="{{ asset('admin/assets/vendors/iconfonts/typicons/src/font/typicons.css') }}">
<link rel="stylesheet" href="{{ asset('admin/assets/vendors/iconfonts/flag-icon-css/css/flag-icon.min.css') }}">
<link rel="stylesheet" href="{{ asset('admin/assets/vendors/css/vendor.bundle.base.css') }}">
<link rel="stylesheet" href="{{ asset('admin/assets/vendors/css/vendor.bundle.addons.css') }}">
<!-- endinject -->
<!-- plugin css for this page -->
<!-- End plugin css for this page -->
<!-- inject:css -->
<link rel="stylesheet" href="{{ asset ('admin/assets/css/shared/style.css') }}">
<!-- endinject -->
<link rel="shortcut icon" href="{{ asset('admin/assets/images/favicon.png') }}" />
</head>
<body>
<div class="container-scroller">
<div class="container-fluid page-body-wrapper full-page-wrapper">
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
@yield('content')
<!-- content-wrapper ends -->
</div>
<!-- page-body-wrapper ends -->
</div>
<!-- container-scroller -->
<!-- plugins:js -->
<script src="{{ asset ('admin/assets/vendors/js/vendor.bundle.base.js') }}"></script>
<script src="{{ asset ('admin/assets/vendors/js/vendor.bundle.addons.js') }}"></script>
<!-- endinject -->
<!-- inject:js -->
<script src="{{ asset ('admin/assets/js/shared/off-canvas.js') }}"></script>
<!--<script src="{{ asset('admin/assets/js/shared/misc.js') }}"></script>-->
<!-- endinject -->
</body>
</html>
@extends('layouts.auth')
@section('title') Login @endsection
@section('content')
<div class="row w-100">
<div class="col-lg-4 mx-auto">
<div class="auto-form-wrapper">
<form method="POST" action="{{ route('login') }}">
@csrf
<div class="form-group">
<label class="label">Email</label>
<div class="input-group">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus style="width:95%;">
@error('email')
<span class="invalid-feedback" role="alert"
<strong>{{ $message }}</strong><br><br>
</span>
@enderror
</div><br>
</div>
<div class="form-group">
<label class="label">Password</label>
<div class="input-group">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password" placeholder="*********">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div><br>
</div>
<div class="form-group">
<button class="btn btn-primary submit-btn btn-block">Login</button>
</div>
</form>
<div class="form-group d-flex justify-content-between">
<div class="form-check form-check-flat mt-0">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
<a href="{{ route('password.request') }}" class="text-small forgot-password text-black">Forgot Password</a>
</div>
<div class="text-block text-center my-3">
<span class="text-small font-weight-semibold">Not a member ?</span>
<a href="{{ route('register') }}" class="text-black text-small">Create new account</a>
</div>
</div>
</div>
</div>
@endsection
You will have to make some CSS changes in order to get everything looking like your downloaded Bootstrap template. One thing you'll want to remember is how to get your input fields looking good. For that, I had to go into style.css in public/admin/assets/css/shared to adjust right hand border of fields. Another thing I had to do was add the highlighted <br> tag in order to create enough roo
J) Dashboard (back to top...)
Grab the "index.html" from your Bootstrap template and put that in a new file in your "layouts" folder. Call it "admin.blade.php."
After you do that, you'll want to find where the main content is going to be located and put, " @yield('content')" at that point.
Now, go to your "views" directory and grab your "home.blade.php" file and rename it to "dashboard.blade.php." Once you do that, you'll want to adjust your "HomeController.php" file so it's referring to "/dashboard" rather than "/home." Also, change the layout you're referring to at the top of the page to "@extends('layouts.admin')."
And that will do it!
K) Dashboard Navigation (back to top...)
First thing is get rid of the two <li> elements that form the email and notification icons / pulldown menu.
1) Login Name (back to top...)
Next, you're going to replace the static "name" with the name of the hardcharger that's logged in with this:
<p class="mb-1 mt-3 font-weight-semibold">{{ Auth::user()->name }}</p>
2) Sidebar Links (back to top...)
You're going to change up the sidebar somewhat with a different class for you links as well as some additional icons.
The class you're going to use is this:
a.new_menu_link {
color:#ffffff;
align-items:center;
padding:15px 30px 15px 25px;
whitespace: nowrap;
height:52px;
font-size: 15px;
font-weight:bold;
font-weight:500;
display:inline-block;
display:flex;
}
This is on your "sidebar.css" page.
Your links are going to look like this (with your icon):
<li class="nav-item">
<a href="index.html" class="new_menu_link">
<ion-icon name="md-document" lazy="" role="img" class="hydrated" aria-label="person" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Courses</span>
</a>
</li>
Notice the new class! And, for your icons, you're going to need a new JS code. You'll put that on your "admin.blade.php" page...
<script src="{{ asset('admin/assets/vendors/iconfonts/ionicons/ionicons.js') }}"></script>
And for the actual icons, you can click here for a reference.
Your finished sidebar menu looks like this:
<ul class="nav">
<li class="nav-item nav-profile">
<a href="#" class="nav-link">
<div class="profile-image">
<img class="img-xs rounded-circle" src="../admin/assets/images/faces/face8.jpg" alt="profile image">
<div class="dot-indicator bg-success"></div>
</div>
<div class="text-wrapper">
<p class="profile-name">{{ Auth::user()->name }}</p>
<p class="designation">Premium user</p>
</div>
</a>
</li>
<li class="nav-item nav-category">Main Menu</li>
<li class="nav-item">
<a href="index.html" class="new_menu_link">
<ion-icon name="md-speedometer" lazy="" role="img" class="hydrated" aria-label="speedometer" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Dashboard</span>
</a>
</li>
<li class="nav-item">
<a href="index.html" class="new_menu_link">
<ion-icon name="md-person" lazy="" role="img" class="hydrated" aria-label="person" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Customers</span>
</a>
</li>
<li class="nav-item">
<a href="index.html" class="new_menu_link">
<ion-icon name="md-document" lazy="" role="img" class="hydrated" aria-label="person" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Courses</span>
</a>
</li>
<li class="nav-item">
<a href="index.html" class="new_menu_link">
<ion-icon name="md-trophy" lazy="" role="img" class="hydrated" aria-label="person" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Quizzes</span>
</a>
</li>
<li class="nav-item">
<a class="new_menu_link" data-toggle="collapse" href="#auth" aria-expanded="false" aria-controls="auth">
<ion-icon name="ios-videocam" lazy="" role="img" class="hydrated" aria-label="person" style=font-size:18pt;"></ion-icon>
<span class="menu-title">Videos</span>
<i class="menu-arrow"></i>
</a>
<div class="collapse" id="auth">
<ul class="nav flex-column sub-menu">
<li class="nav-item">
<a class="nav-link" href="pages/samples/blank-page.html"> Blank Page </a>
</li>
<li class="nav-item">
<a class="nav-link" href="pages/samples/login.html"> Login </a>
</li>
<li class="nav-item">
<a class="nav-link" href="pages/samples/register.html"> Register </a>
</li>
<li class="nav-item">
<a class="nav-link" href="pages/samples/error-404.html"> 404 </a>
</li>
<li class="nav-item">
<a class="nav-link" href="pages/samples/error-500.html"> 500 </a>
</li>
</ul>
</div>
</li>
</ul>
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:migration create_posts_table --create=posts
Created Migration: 2019_08_13_013432_create_posts_table
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan migrate
Migrating: 2019_08_13_013432_create_posts_table
Migrated: 2019_08_13_013432_create_posts_table
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php make:model Post
Could not open input file: make:model
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:model Post
Model created successfully.
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan make:seeder PostSeeder
Seeder created successfully.
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ composer dump-autoload
Generating optimized autoload files> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
Generated optimized autoload files containing 3630 classes
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
$ php artisan db:seed --class=PostSeeder
Database seeding completed successfully.
brucegust@BRUCEGUST59AC MINGW64 /c/wamp/www/personal-blog
M) Displaying Posts & Comments (back to top...)
1) Dynamic Title (back to top...)
In your "header," you'll want to change it to this:
<title>@yield('title', 'Laravel Blog')</title>
That tells Laravel to "yield" to whatever the "title" variable may be and print that. If there's no "title" variable, then write "Laravel Blog."
2) welcome.blade.php / Post.php / Public Controller (back to top...)
Here's what your "welcome.blade.php" page will look like:
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
❶ @foreach($posts as $post)
<div class="post-preview">
<a href="#">
<h2 class="post-title">
❷ {{$post->title }}
</h2>
<h3 class="post-subtitle">
Problems look mighty small from 150 miles up
</h3>
</a>
<p class="post-meta">Posted by
<a href="#">❸ {{$post->user->name}}</a>
❹ on {{ date_format($post->created_at, 'F d, Y') }} | <i class="fa fa-comment" aria-hidden="true"></i>
❺ {{ $post->comments->count() }}
</p>
</div>
<hr>
❺ @endforeach
<!-- Pager -->
<div class="clearfix">
<a class="btn btn-primary float-right" href="#">Older Posts →</a>
</div>
</div>
</div>
</div>
@endsection
class Post extends Model
{
public function user() {
return $this->belongsTo('App\user');
}
public function comments() {
return $this->hasMany('App\Comment');
}
}
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
class PublicController extends Controller
{
public function index() {
$posts = Post::all();
return view('welcome', compact ('posts'));
}
public function singlePost($id) {
return view('singlePost');
}
public function about() {
return view('about');
}
public function contact() {
return view('contact');
}
public function contactPost() {
}
}
<header class="masthead" style="background-image: url('{{asset ('assets/img/post-bg.jpg')}}">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="post-heading">
<h1>{{ $post->title }}</h1>
<span class="meta">Posted by
<a href="#">{{ $post->user->name }}</a>
on {{ date_format($post->created_at, 'F d, Y') }} </span>
</div>
</div>
</div>
</div>
</header>
composer create-project --prefer-dist laravel/laravel pages.site
BTW: --prefer -dist is, "...--prefer-dist: Reverse of --prefer-source, composer will install from dist if possible. This can speed up installs substantially on build servers and other use cases where you typically do not run updates of the vendors. It is also a way to circumvent problems with git if you do not have a proper setup."
Basically, it's going to let you speed up installation. This sets up all your packages, libraries and dependencies.
After that, set up your shortcuts based on the "clunky" URL of "localhost/pages/public/index," You can review those steps by clicking here.
BTW: If you're cloning a project from Github, remember that "composer install" is to Laravel what "npm install" is to Node. You've got to run that command to set up your "vendor" directory. Otherwise, you'll get an error that refers to your "autoload" script in your index file which means nothing if you don't know what it's referring to!
2) database / .env file (back to top...)
Setup your database in phpMyAdmin. In this case, we're going to call "pages_database" and set things up accordingly in the ".env" file.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=pages_database
DB_USERNAME=root
DB_PASSWORD=
3) migration (back to top...)
You'll be using "migrations" and "seeds" to create and populate your tables so that's all you have to do at this step.
i) create migration file / adjust AppServiceProvider (back to top...)
php artisan make:migration create_articles_table --create-pages_database
When you create that file, you've created, not only the syntax that will create your table, but you'll also create what another developer will need in order to mimic your set up if that becomes an issue.
After you've done that, you'll see the file you just created in app -> database -> migrations.
It's just "scaffolding," though. You've got to add the fields that are specific to your app. In this case, it looks like this:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
//use Illuminate\Http\Resources\Json\Resource;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
//Resource::withoutWrapping();
}
}
php artisan make:seeder ArticlesTableSeeder
After running that, you get the "ArticlesTableSeeder.php" file in the "app -> seeds" directory:
<?php
use Illuminate\Database\Seeder;
class ArticlesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Article::class, 30)->create();
}
}
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(ArticlesTableSeeder::class);
}
}
- made your migration file
- created your Model
- created your seeder...
php artisan make:factory ArticleFactory
Go to app -> database -> factories to see the file you just created. You'll see something like this (the code's been altered according to what you see in bold below);
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Model;
use Faker\Generator as Faker;
$factory->define(App\Article::class, function (Faker $faker) {
return [
'title' => $faker->text(50),
'body' => $faker->text(200)
];
});
php artisan make:model Article
That gives you this file:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
//
}
php artisan migrate
That makes all of our tables. The next step is to populate them with some data...
vii) Add Dummy Data (back to top...)
Now, we're going to create some dummy data in our "articles" table.
php artisan db:seed
What this is going to do is run any "seeder" file you've got in your "seeds" directory.
Notice the convention when it comes to naming tables. In this case, you're populating a table called, "articles." In our "migration" file, you're going to refer to that table as "article..."
factory(App\Article::class, 30)->create();
That gives us 30 rows of dummy data that we can now use as a way to test the functionality we're going to create to administer our site's content.
B) Setting Up Controllers and Routes (back to top...)
1) List Articles (back to top...)
i) ArticlesController.php (back to top...)
Start by making your Controller that's going to "control" your "articles" table:
php artisan make:controller ArticleController --resource
By adding "resource," it will automatically generate placeholders for your main blocks of functionality.
Here's your finished Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
❶ use App\Http\Requests;
use App\Article;
❸ use App\Http\Resources\Article as ArticleResource;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//get articles
❷ $articles = Article::paginate(15); // "Article" is your model. "paginate" tells the system to display the rows 15 at a time
//return collection of articles as a resource
❸ return ArticleResource::collection($articles);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
$article = $request->isMethod('put') ? Article::findOrFail
($request->article_id) : new Article;
$article->id = $request->input('article_id');
$article->title = $request->input('title');
$article->body = $request->input('body');
if($article->save()) {
return new ArticleResource($article);
}
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//get article
$article = Article::findOrFail($id);
//return single article as resource
return new ArticleResource($article);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$article = Article::findOrFail($id);
if($article->delete()) {
return new ArticleResource($article);
}
}
}
When building an API, you may need a transformation layer that sits between your Eloquent models and the JSON responses that are actually returned to your application's users. Laravel's resource classes allow you to expressively and easily transform your models and model collections into JSON.
In this case, you're working with the "Article" model. You define your "dependency" at the top of the page and name it "ArticlesResource" and then invoke it in your code and pass the "article" variable into it via the paranthesis.
ii) api.php (routes) (back to top...)
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
//list articles
Route::get('/articles', 'ArticleController@index');
//list single article
Route::get('/article/{id}', 'ArticleController@show');
//create new article
Route::post('/article', 'ArticleController@store');
//update article
Route::put('/article', 'ArticleController@store');
//delete an article
Route::delete('/article/{id}', 'ArticleController@destroy');
php artisan make: resource Article
That's the file that you see in the, "http->Resources" directory which looks like this:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Article extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
❶ //return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'body' => $this->body
];
}
public function with($request) {
return [
'version' => '1.0.0',
'author_url' => url('http://brucegust.com')
];
}
}
{
"data": [
{
"id": 1,
"title": "Ad magnam rerum eaque. Laborum est ipsa labore.",
"body": "Facilis illum vel qui odio laudantium et doloremque alias. Nisi eum ipsum quibusdam ut. Sed pariatur accusamus facilis similique quis iusto."
},
{
"id": 31,
"title": "Test Title",
"body": "test body"
},
{
"id": 32,
"title": "Test Title",
"body": "test body"
},
{
"id": 33,
"title": "Test Title",
"body": "test body"
},
{
"id": 3,
"title": "Dolores ut ut animi quia.",
"body": "Aliquid autem eum quidem perferendis deleniti corporis et magnam. Laborum et beatae aut doloremque nulla consequatur qui. Tempore sit ut culpa ut voluptatem quod repudiandae nam."
},
{
"id": 4,
"title": "Updated Tite",
"body": "updated body"
},
{
"id": 5,
"title": "Odio architecto cum quae illum fuga odio quis.",
"body": "Vero nulla ullam quisquam odio neque consequatur. Ut sed sint eum ea recusandae unde aliquid. Sit sed occaecati et id ea."
},
{
"id": 6,
"title": "Vel ut ut nobis cum consequatur voluptatibus.",
"body": "Et ea assumenda ipsa voluptatum ab quia qui. Alias accusamus eos ratione quidem ab rerum quis. Quis maxime qui fuga sapiente facilis architecto impedit. Architecto amet magni quia voluptate qui."
},
{
"id": 7,
"title": "Officia ipsum enim et.",
"body": "Voluptates ut enim voluptatem qui omnis repellat qui. Tempore beatae qui dolorem et totam sed autem sunt. Excepturi cumque possimus est eum autem."
},
{
"id": 8,
"title": "Illum incidunt qui voluptates natus et.",
"body": "Ad provident velit debitis esse. Quas voluptatem optio molestiae placeat a dolorem. Dolorem fuga quas natus aut voluptatem qui dolor."
},
{
"id": 9,
"title": "Quasi aliquid voluptas qui repudiandae.",
"body": "Cumque doloribus impedit sed aut omnis. Molestiae et et vel officia neque itaque. In ducimus illo laborum aut hic ut incidunt."
},
{
"id": 10,
"title": "Odio fugiat et asperiores autem.",
"body": "Vitae odit numquam facilis ipsam illum eum. Eum quo tempora excepturi. Voluptates facere quidem aliquam pariatur asperiores."
},
{
"id": 11,
"title": "Enim sapiente ea et.",
"body": "Modi dolor excepturi voluptate est omnis. Eum explicabo dolorum officiis adipisci. At cumque aspernatur distinctio dolorum modi est. Et tempora illum voluptatibus autem dolores."
},
{
"id": 12,
"title": "Vel deserunt sint non sit consequatur.",
"body": "Dolor accusamus architecto omnis. Earum dolor temporibus expedita odio eos porro. Ratione modi rerum maxime."
},
{
"id": 13,
"title": "Amet et recusandae expedita.",
"body": "Dolor odit accusamus omnis dignissimos pariatur alias qui. Omnis rem quia necessitatibus atque. Dolorum natus et atque magni consectetur asperiores veritatis. Molestiae aut id aut."
}
],
"links": {
"first": "http://pages.site/api/articles?page=1",
"last": "http://pages.site/api/articles?page=3",
"prev": null,
"next": "http://pages.site/api/articles?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "http://pages.site/api/articles",
"per_page": 15,
"to": 15,
"total": 32
}
}
❶ public function show($id)
{
//get article
❷ $article = Article::findOrFail($id);
//return single article as resource
❸ return new ArticleResource($article);
}
Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The findOrFail and firstOrFail methods will retrieve the first result of the query; however, if no result is found, a Illuminate\Database\Eloquent\ModelNotFoundException will be thrown. (Laravel Docs)
③ this is yet another use of your "resource" that Eloquent uses for API dynamics
When you go to Postman and do a "POST" using http://pages.site/api/article/4, you get this:
{
"data": {
"id": 4,
"title": "Updated Tite",
"body": "updated body"
},
"version": "1.0.0",
"author_url": "http://brucegust.com"
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
use Illuminate\Http\Resources\Json\Resource;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
Resource::withoutWrapping();
}
}
{
"id": 4,
"title": "Updated Tite",
"body": "updated body"
}
public function with($request) {
return [
'version' => '1.0.0',
'author_url' => url('http://brucegust.com')
];
}
public function store(Request $request)
{
//
❶ $article = $request->isMethod('put') ? Article::findOrFail($request->article_id) : new Article;
$article->id = $request->input('article_id');
$article->title = $request->input('title');
$article->body = $request->input('body');
❷ if($article->save()) {
return new ArticleResource($article);
}
}
Boolean Expression ? First Statement : Second Statement
As you can see in the above syntax, ternary operator includes three parts. First part (before ?) includes conditional expression that returns boolean value true or false. Second part (after ? and before :) contains a statement which will be returned if the conditional expression in the first part evalutes to true. The third part includes another statement which will be returned if the conditional expression returns false.
Also, as a quick aside, Article is your "Article" model which you imported into your Controller with this line of code: use App\Article;
The difference between an object and an instance one more time:
"A blueprint for a house design is like a class description. All the houses built from that blueprint are objects of that class. A given house is an instance."
So, in this one ternary IF statement you're saying that if the app is using a "PUT" dynamic, you're going to use the "findOrFail" method and passing the value of the article_id into the method. Otherwise, you're setting up an entirely new "Article" object.
② Having defined whether or not this is an entirely new entry or you're merely updating an existing record, once the user hits "save," you grab the incoming data and process it by passing your object into your new "resource" object.
To update an article then, your Postman interface is going to look like this:
You're going to use the PUT method and your URL is "http://pages.site/api/article."
The system recognizes PUT and then looks for the id of the already existing record. In our Postman interface, we put "content type" of "appplication/json" in our header and then put row JSON code into our body that looked like this:
{
"article_id": 4,
"title": "Updated Tite",
"body": "updated body"
}
And that updated our article.
To put a new article into the database, we used the same "application/json" content type and then this will be the raw JSON in your body:
{
"title": "Test Title",
"body": "test body"
}
You'll use the URL, only this time you're using "POST" instead of "PUT" and that's all there is to it!
4) Delete Article (back to top...)
To delete an article, you're going to start by coping the code you had in "show" and making a couple of modifications.
public function destroy($id)
{
❶ $article = Article::findOrFail($id);
❷ if($article->delete()) {
return new ArticleResource($article);
}
}

Laravel is currently shipping version 6. If you want to run Vue, then you've got to install it by hand and specifiy it's usage. Otherwise, you won't have the infrastructure or the functionality. Here's what you do: composer require laravel/ui --dev php artisan ui vue At that point, you'll get a prompt that will ask you to run npm install and npm run devThen...and only then... you are good to go!
$ npm run watch
> @ watch C:\wamp\www\larticles
> cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
'cross-env' is not recognized as an internal or external command,
operable program or batch file.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ watch: `cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ watch script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\brucegust\AppData\Roaming\npm-cache\_logs\2019-12-01T12_05_13_664Z-debug.log
In the end, it was a wild goose chase that was finally solved by running the above commands (composer require laravel/ui --dev | php artisan ui vue). Short of that, and it was a mess that never stopped.
1) Install Dependencies and "npm run watch" (back to top...)
i) Bringing Files from One Project to Another (back to top...)
When you're bringing files from one project to another, you'll copy and paste your Controllers and your Routes. One thing that might be a little illusive, however, is your Models. Those are sitting in your "app" directory and are absolutely essential in order for your Controller to work in the context of your database.
ii) package.json (back to top...)
You'll run npm install to get your localized app up to speed with all of the Node related dependencies in place.
In your "package.json" file, you have this:
"devDependencies": {
"axios": "^0.19",
❶ "bootstrap-sass": "^3.3.7",
"cross-env": "^5.1",
"jquery": "^3.2",
❷ "laravel-mix": "^4.0.7",
"lodash": "^4.17.13",
"resolve-url-loader": "^2.3.1",
"sass": "^1.15.2",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.6.10",
"vue": "^2.5.7"
}
A couple of things you'll want to be aware of...
This has been stated before but it's worth repeating: When you import a project from Github, not only will you have to run npm install, but you'll also have to run composer install. That's how you get your "vendor" directory and all of your dependencies beyond what's related specifically to JavaScript / Node etc. Click here for more info.
① SASS stands for "syntactically awesome style sheets." It adds a layer of functionality on to your CSS script that makes it a far more verbose and functional approach to stylesheets. Click here for even more information.
② In this app, you've got a bunch of packages and dependencies that make for a great looking / functioning application. While Composer orchestrates and organizes PHP dependencies, Laravel Mix is organizing your Node tech.
It's a layer of functionality positioned over the JS Webpack technology. You'll use npm run watch to keep track of any updates or changes to those technologies to ensure your app doesn't get hung up on an upgrade that it isn't prepared for.
Here's what the Laravel docs say...
The npm run watch command will continue running in your terminal and watch all relevant files for changes. Webpack will then automatically recompile your assets when it detects a change...
Here's the syntax you need to remove all of your node packages and start fresh just in case you feel like you need to start at the beginning.
rm -rf node_modules
rm package-lock.json yarn.lock
npm cache clear --force
npm install
iii) composer.json (back to top...)
This is similar to Node in that you've got several "packages" that are needed in order for this puppy to run. While npm install uploads all of your Node dynamics, composer install uploads all of your PHP tech.
2) Basic Files (back to top...)
i) npm run watch (back to top...)
"npm run watch" is a needed piece of tech in order to update your vue.js files. Reason being is that "vue" is a framework.
There's a difference between a library and a framework...
The "^" character is a piece of syntax that tells your system to go ahead and update older versions of your various libraries. Click here for more information.
"yarn" is simliar to "npm," but in some ways is a little more secure and effective. Click here for more info.
A library can be defined as bunch of code which can be used for a specific purpose. Typical example of a library is jQuery which is a JavaScript library consisting of API ’s through which one can easily manipulate HTML and CSS and also provide a better, dynamic outlook to your website.
On the other hand, framework can be defined as the skeleton of a project which helps you eradicate the need of hard coding……. by this i mean to say that nothing needs to be done from scratch and it provides initial support to start the project. Bootstrap can be considered as a typical example of a web framework which provides you all the pre defined classes and fonts and many other features your which makes your development faster and easier (from quora.com).
That being the case, when you make changes to your vue.js files within Laravel, you're affecting more than just that one line of code. Rather, you're potentially affecting several files, hence the need for npm run watch
ii) welcome.blade.php (back to top...)
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
❶ <meta name="csrf-token" content="{{ csrf_token() }}">
<script>window.Laravel = { csrfToken: '{{ csrf_token() }}' }</script>
❷ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<title>The Starting Line</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<!-- Styles -->
</head>
<body>
❸ <div id="app">
<navbar></navbar>
<div class="container">
<articles></articles>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
❹ <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Cross-Site Request Forgery (CSRF) in simple words:The transfer request is extended with a third argument: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
That token is a huge, impossible-to-guess random number that mybank.com will include on their own web page when they serve it to you. It is different each time they serve any page to anybody.
The attacker is not able to guess the token, is not able to convince your web browser to surrender it (if the browser works correctly...), and so the attacker will not be able to create a valid request, because requests with the wrong token (or no token) will be refused by www.mybank.com. Result: You keep your 10000 monetary units. I suggest you donate some of that to Wikipedia.
- Assume you are currently logged into your online banking at www.mybank.com
- Assume a money transfer from mybank.com will result in a request of (conceptually) the form http://www.mybank.com/transfer?to=&l;SomeAccountnumber>;amount=<SomeAmount>. (Your account number is not needed, because it is implied by your login.)
- You visit www.cute-cat-pictures.org, not knowing that it is a malicious site.
- If the owner of that site knows the form of the above request (easy!) and correctly guesses you are logged into mybank.com (requires some luck!), they could include on their page a request like http://www.mybank.com/transfer?to=123456;amount=10000 (where 123456 is the number of their Cayman Islands account and 10000 is an amount that you previously thought you were glad to possess).
- You retrieved that www.cute-cat-pictures.org page, so your browser will make that request.
- Your bank cannot recognize this origin of the request: Your web browser will send the request along with your www.mybank.com cookie and it will look perfectly legitimate. There goes your money!
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
❶ window.Vue = require('vue');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
❷ Vue.component('navbar', require('./components/Navbar.vue').default);
Vue.component('articles', require('./components/Articles.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
❸ const app = new Vue({
❹ el: '#app',
});
① Vue provides an ES module that is used by webpack.
"Webpack" is a module bundler which is a tool that takes pieces of JavaScript and their dependencies and bundles them into a single file, usually for use in the browser.
Refer to the graphic to the right to get an idea of how it works and what it does.
Bottom line: In JavaScript, if you're still manually including each JavaScript file you depend on with a script tag... there's a better way! ES6 introduced the concept of modules: the ability (finally!) to isolate our JavaScript into small components that live in different files (like we do with classes in JavaScript).
But, to get this to work on the web, we need some help. We need something that's able to read our imports and aggregate everything we need into a single JavaScript file. We need webpack! (taken from symfonycasts.com).
② this is a Vue Component. You're associating it with the "navbar" element in the DOM (Data Object Model).
③ this is coming from the Vue documentation...
Provide the Vue instance an existing DOM element to mount on. It can be a CSS selector string or an actual HTMLElement.
After the instance is mounted, the resolved element will be accessible as vm.$el.
In other words, you have a new Vue instance (const app...) and with the "el" syntax you're saying you defining the element (el) that you want to mount your Vue instance on.
BOOM!
iv) Articles.vue (back to top...)
Here's the first round of code that we built...
❶ <template>
<div>
<h2>Articles</h2>
</div>
</template>
<script>
❷ export default {
❸ data() {
return {
articles: [],
article: {
id: '',
title: '',
body: ''
},
article_id: '',
pagination: {},
edit: false
}
},
❹ created() {
this.fetchArticles();
},
methods: {
❺ fetchArticles() {
fetch('api/articles')
.then(res => res.json())
.then(res=> {
console.log(res.data);
})
}
}
}
</script>
The <template> tag holds its content hidden from the client.
Content inside a <template> tag will not be rendered.
The content can be made visible and rendered later by using JavaScript.
Taken from w3schools.com
① These tags make complete sense when you consider what it looks like when you're writing straight Vue.js code. Here's a portion of the tutorial on Vue.js in 60 Minutes:
import Vue from 'vue' // import Vue
import App from './App' // import your main "App" component from Vue
new Vue({ // new Vue instance
el: '#app', // this is the element that we're attaching the Vue instance to.
In this case, the name of the element is "app."
template: '<App/>', // the <template> tag is actually an HTML element.
See callout to the right...
components: { App } // a list of all the components you're going to foward to your
<template> tag. Technically, this is where you're "registering
your components
})
② export default is part of the ES6 version of JavaScript. It's basically saying that you want to export everything you're getting ready to program.
③ data() is a property of a Vue instance that sets the properties of that Vue instance, and those properties can be accessed by and bound to the component.
Here's an example that's coming from EE:
<div id="myApp">
<h1>Hello {{ name }}</h1>
</div>
new Vue({
el : '#myApp',
data : {
name: 'Chris'
}
});
In the single instance example above, you'll see that the value of the data property is just an object (which has a single property called name). When you're building re-usable components, your data property needs to be a function that returns an object. This is so that each instance (copy) of your component has access to it's own copy of the data (otherwise changing a property value on one instance would change the value on all instances!)
The syntax you've used above is just shorthand for the following:
export default {
data : function() {
return {
prop1 : "Some Value",
prop2 : "Another Value",
}
},
As far as what you have after "return," here's a quick summary of objects and arrays as they're used in JavaScript:
In Javascript you have Arrays and you have Objects. Generally speaking an Array is a collections of 'things', and an Object is a single 'thing' that contains related properties (for example a Customer object might have a FirstName property, and a LastName Property).
An Array can contain a collection simple things (primitives), such as strings, numbers etc (the contents of an array don't have to be the same type!), but it can also contain a collection of Objects. An Object contains properties, which in turn can also be Arrays!
Arrays use the square brackets and you access the elements of that array using the zero-based index:
var myArray = ["Value1", "Value2", "Value3"];
console.log( myArray[0] ); // Value 1;
Objects use the curly brackets and you access the properties using the period:
var myObject = { FirstName : "Chris", LastName : "Stanyon" };
console.log( myObject.FirstName ); // Chris
As I said, Arrays can contain Objects, and Object Properties can be Arrays!
var customers = [
{ FirstName : "Chris", LastName : "Stanyon", PhoneNumbers : [ "123456", "098876" ] },
{ FirstName : "Bruce", LastName : "Gust", PhoneNumbers : [ "00000", "55555" ] },
];
What we have here is an Array of Customer Objects. Each Customer has 3 Properties - FirstName, LastName and PhoneNumbers. PhoneNumbers is an Array. You can access the data like so:
customers[0].FirstName; // FirstName property of the 1st customer
customers[1].LastName; // LastName property of the 2nd customer
customers[1].PhoneNumbers[0]; // 1st PhoneNumber of the 2nd customer
This is coming from a Fitbit project that we worked on a while ago and you can see some more context by clicking here
④ "created" is a "Lifecycle Hook. Basically, it's a label that indicates in what order is a particular piece of code going to fire. Click on the link for more information and / or refer to the diagram to the right to see what kind of role it plays in the overall scheme of things.
⑤ pretty straight forward. This is your list of methods. In this case, we're grabbing the results from an api and retrieving them as JSON.
The above code gives you what is coming from your api/artilces API which looks like this:
{"data":[{"id":33,"title":"Test Title","body":"test body","created_at":"2019-11-10 02:21:19","updated_at":"2019-11-10 02:21:19"},{"id":31,"title":"Test Title","body":"test body","created_at":"2019-11-10 02:20:57","updated_at":"2019-11-10 02:20:57"},{"id":1,"title":"Ad magnam rerum eaque. Laborum est ipsa labore.","body":"Facilis illum vel qui odio laudantium et doloremque alias. Nisi eum ipsum quibusdam ut. Sed pariatur accusamus facilis similique quis iusto.","created_at":"2019-11-09 04:02:01","updated_at":"2019-11-09 04:02:01"},{"id":3,"title":"Dolores ut ut animi quia.","body":"Aliquid autem eum quidem perferendis deleniti corporis et magnam. Laborum et beatae aut doloremque nulla consequatur qui. Tempore sit ut culpa ut voluptatem quod repudiandae nam.","created_at":"2019-11-09 04:02:01","updated_at":"2019-11-09 04:02:01"},{"id":4,"title":"Updated Tite","body":"updated body","created_at":"2019-11-09 04:02:01","updated_at":"2019-11-10 02:39:31"}],"links":{"first":"http:\/\/larticles.site\/api\/articles?page=1","last":"http:\/\/larticles.site\/api\/articles?page=7","prev":null,"next":"http:\/\/larticles.site\/api\/articles?page=2"},"meta":{"current_page":1,"from":1,"last_page":7,"path":"http:\/\/larticles.site\/api\/articles","per_page":5,"to":5,"total":31}}
3) Cadillac Display (back to top...)
Here's how we code this thing so it looks camera ready!
<template>
<div>
<h2>Articles</h2>
<nav aria-label="Page navigation example">
<ul class="pagination">
❺ <li v-bind:class="[{disabled: !pagination.prev_page_url}]" class="page-item">
<a class="page-link" href="#"
❻ @click="fetchArticles(pagination.prev_page_url)">Previous</a></li>
<li class="page-item disabled"><a class="page-link text-dark" href="#">
Page {{ pagination.current_page }} of {{ pagination.last_page }}</a></li>
❼ <li v-bind:class="[{disabled: !pagination.next_page_url}]" class="page-item">
<a class="page-link" href="#"
@click="fetchArticles(pagination.next_page_url)">Next</a></li>
</ul>
</nav>
❶ ❷ ❸ <div class="card card-body mb-2" v-for="article in articles" v-bind:key="article.id">
<h3>{{ article.title }}</h3>
<p>{{ article.body }}</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
articles: [],
article: {
id: '',
title: '',
body: ''
},
article_id: '',
pagination: {},
edit: false
}
},
created() {
this.fetchArticles();
},
methods: {
❹ fetchArticles(page_url) {
let vm = this;
❹ page_url = page_url || '/api/articles'
❹ fetch(page_url)
.then(res => res.json())
.then(res=> {
❶ this.articles = res.data;
❺ vm.makePagination(res.meta, res.links);
})
.catch(err => console.log(err));
},
❺ makePagination(meta, links) {
let pagination = {
current_page: meta.current_page,
last_page: meta.last_page,
next_page_url: links.next,
prev_page_url: links.prev
}
this.pagination = pagination;
}
}
}
</script>
Here are a couple of supplemental videos that further explain Vue.js principles:
Vue.us In 60 Seconds
Coder's Tape -> an entire library of quick and easy videos that elaborate on Vue.js and Laravel
① assigning the data that we're getting back from our method to the articles[] array we're returning
② this is Vue.js code. We're getting ready to loop through the associative array that we've got with . The one thing that's a little unique is the key that Vue.js expects which is what I've got highlighted here: v-for="article in articles" v-bind:key="article.id"
You see this explained in the Vue.js documentation:
<div v-for="item in items" v-bind:key="item.id">
<!-- content -->
</div>
③ card card-body mb-2 -> these are Bootstrap classes for "cards." mb-2 is another Bootstrap setting that stands for "margin body." This is what gives us a little extra space.
④ you're adjusting your fetchArticles a little bit by passing in a "page_url" variable. If that variable is present, you're going to be fetching those articles with the fetch functionality that coincide with that particular value. Otherwise, you're just grab what's coming from the "normal" api/articles dynamic.
⑤ vm stands for "view model." When you instantiate a "View" instance, you automatically have access to all the functionality contained within the "View" dynamic. "Pagination" is one of those things that is provided through that package.
⑥ this is the pagination code that you can get from Bootstrap
⑦ v-bind is what Vue.js uses to handle dynamically changed entities based on incoming data.
4) Delete Article (back to top...)
We're going to start by adding a "delete" button on the card:
<button @click="deleteArticle(article.id)" class="btn btn-danger">Delete Articles</button>
Next, we'll add this function:
deleteArticle(id) {
if(confirm('Are you sure?')) {
fetch(`api/article/${id}`, { notice the " ` " character. You may very well get another effort
method: 'delete'
})
.then(res => res.json())
.then(data => {
alert('Article Removed')
this.fetchArticles();
})
.catch(err => console.log(err));
}
}
5) Add Article Form (back to top...)
Here's your first piece:
<input type="text" class="form-control" placeholder="title" v-model="article.title">
Take a look at what "v-model" is all about:
v-model -> You can use the v-model directive to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, v-model is essentially syntax sugar for updating data on user input events, plus special care for some edge cases (from the Vue.js docs).
Here's your input for your body and your button:
<div class="form-group">
<textarea class="form-control" placeholder="body" v-model="article.bodyu"></textarea>
</div>
<button type="submit" class="btn btn-light btn-block">Save</button>
Now, here's your code. You're going to be using the same method for both the "add" and "update" functionality with some obvious differences depending on the "edit" value which is set to "false" by default.
Here's your "addArticle" code:
addArticle() {
if(this.edit === false) {
//add
fetch(`api/article`, {
method: 'post',
body: JSON.stringify(this.article),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then(data => {
this.article.title = '';
this.article.body = '';
alert('Article added');
this.fetchArticles();
})
.catch(err => console.log(err));
}
else {
//update
}
}
addArticle() {
❶ if(this.edit === false) {
//add
fetch(`api/article`, {
method: 'post',
body: JSON.stringify(this.article),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then(data => {
this.article.title = '';
this.article.body = '';
alert('Article updated');
this.fetchArticles();
})
.catch(err => console.log(err));
}
else {
//update
❷ fetch(`api/article`, {
❸ method: 'put',
❹ body: JSON.stringify(this.article),
headers: {
'content-type': 'application/json'
}
})
❺ .then(res => res.json())
.then(data => {
this.article.title='';
this.article.body='';
alert('Article Updated');
this.fetchArticles();
})
.catch(err => console.log(err));
}
},
editArticle(article) {
this.edit = true;
this.article.id = article.id;
this.article.article_id = article.id;
this.article.title = article.title;
this.article.body = article.body;
}
...this is from JavaScript and Oracle
async function put(req, res, next) {
try {
let employee = getEmployeeFromRec(req);
employee.employee_id = parseInt(req.params.id, 10);
employee = await employees.update(employee);
if (employee !== null) {
res.status(200).json(employee);
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
module.exports.put = put;- begin by setting up your database and adjusting your ".env" file
- alter your AppServiceProvider.php file in your "app/Providers" directory with this:
composer require laravel/ui
php artisan ui vue --auth
php artisan migrate
This works after you've set up your database.
Also, to determine the version of Laravel you're using, you'll run this command:
Bruce@WINDOWS-2SH5T3I MINGW64 /c/wamp64/www/new_nomas
$ php artisan --version
Laravel Framework 6.1.0
At that point, you've got everything you need to login, register, retrieve a forgotten password...it's awesome!
3) Understanding and Setting Up the Login Screen (back to top...)
When you run the above commands, you're doing more than what might appear to be the case on the surface. One example of that is the way in which the login process and routing is now firing automatically in ways that aren't necessarily obvious.
For example, those pages that can only be accessed by an authenticated user are protected by the incorporation of middleware that you reference in your Controller.
Take your AdminController.php page. You'll most likely have something like this:
public function __construct()
{
$this->middleware('checkRole:admin ');
}
That Middleware has to be registered. To do that, you'll add 'checkRole' => \App\Http\Middleware\CheckRole::class, to your "Kernel.php" page.
That is now firing with every request that's made to that page. Notice, it's checking the role of the person who's supposedly logged in and already authenticated. To trace the routing and the nuts and bolts of what's actually happening, you have to go to the Middleware itself.
With "checkRole," you'll go to the "CheckRole.php" page to see what's happening.
But here's something to be aware of:
When all of this is orginally set up, you automatically have routes set up for "login" and all of the other authentication pages you'll need. On the "web.php," you'll see this: Auth::routes();. That's referring to a collection of routes on the "Router.php" located in the "vendor\laravel\framework\src\Illuminate\Routing" directory.
Here are those routes:
public function auth(array $options = [])
{
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout');
// Registration Routes...
if ($options['register'] ?? true) {
$this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
$this->post('register', 'Auth\RegisterController@register');
}
// Password Reset Routes...
if ($options['reset'] ?? true) {
$this->resetPassword();
}
// Email Verification Routes...
if ($options['verify'] ?? false) {
$this->emailVerification();
}
}
<div class="top-area">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-xs-6 training_schedule">
<b>NOMAS<sup>®</sup> Training Schedule</b>
</div>
<div class="col-xs-6 training_register">
<!-- start login links-->
@if(Auth::check())
<a href="{{ route('dashboard') }}">Dashboard</a>
<form method="Post" id="logout-form" action="{{ route('logout') }}">@csrf</form>
<a href="#" style="font-weight:bold;" onclick="document.getElementById('logout-form').submit();">Logout</a>
@else
<a href="#" style="color:#fff; font-weight:bold;" href="{{ route('login') }}">Login</a> |
<a href="#" style="color:#fff; font-weight:bold;" href="{{ route('register') }}">Register</a>
@endif
<!-- end login links -->
</div>
</div>
</div>
</div>
</div>
</div>
Bruce@WINDOWS-2SH5T3I MINGW64 /c/wamp64/www/new_nomas
$ php artisan make:model Role -m
Model created successfully.
Created Migration: 2019_12_28_013531_create_roles_table
C) User Login and Administrator (back to top...)
A lot of the infrastructure you need to login is already in place by default thanks to the "auth" command. Still, there were some additional concepts and elements that had to be added in order to get this puppy to fire correctly.
Regular User vs Administrator
What's going to determine whether or not a user is a basic customer or an administrator is the value of "1" in the admin column in the user's table. That column had to be added.
The "Login | Register" links at the top were changed so they now displayed, "Admin Page | Dashboard | Logout" if a user was logged in AND had administrative privileges.
Here's the code that made all that happen:
<!-- start login links-->
❶ @if(Auth::check())
❷ @if(Auth::user()->admin==1)
<a href="{{ route('adminDashboard') }}" style="color:#fff; font-weight:bold;">Admin Page</a> |
<a href="{{ route('userDashboard') }}" style="color:#fff; font-weight:bold;">Dashboard</a> |
<form method="Post" id="logout-form" action="{{ route('logout') }}" style="display:inline;">@csrf</form>
<a href="#" style="font-weight:bold; color:#fff;" onclick="document.getElementById('logout-form').submit();">Logout</a>
@else
<a href="{{ route('userDashboard') }}" style="color:#fff; font-weight:bold;">Dashboard</a> |
<form method="Post" id="logout-form" action="{{ route('logout') }}" style="display:inline;">@csrf</form>
<a href="#" style="font-weight:bold; color:#fff;" onclick="document.getElementById('logout-form').submit();">Logout</a>
@endif
@endif
❸ @if(Auth::guest())
<a href="/login" style="color:#fff; font-weight:bold;" >Login</a> |
<a href="#" style="color:#fff; font-weight:bold;" href="{{ route('register') }}">Register</a>
@endif
<!-- end login links -->
Warning: Undefined variable $coede_frame in /home/cgob4051moa0/public_html/adm/laravel/index.php on line 4560
public function up() { Schema::create('pages', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('title'); $table->binary('body'); $table->timestamps(); }); }