My first project on Laravel with Cards and Notes

Setup MySQL connection in Laravel env

nano .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=DBNAME
DB_USERNAME=DBUSER
DB_PASSWORD=DBPASSWORD

 

Setup authentication

php artisan make:auth
php artisan migrate

This overwrites HomeController.php if already exist so execute at beginning stage of development

 

Create your database tables, Controller & Model

#Create database table example: cards & notes
php artisan make:migration create_cards_table --create=cards
php artisan make:migration create_notes_table --create=notes

#Refer to below link for database columns
https://laravel.com/docs/5.3/migrations#creating-columns

#migrate (lose data)
php artisan migrate
php artisan migrate:refresh
php artisan migrate:reset

#Make controller
php artisan make:controller CardsController
php artisan make:controller NotesController

#Make model
php artisan make:model Card
php artisan make:model Note

# listen to sql query
DB::listen(function($query) {var_dump($query->sql);});

Test your app on terminal first

php artisan tinker

#query table cards
DB::table('cards')->get();

#test model
App\Card::all();
App\Card::first();
App\Note::all();

#test model User (new, save, update, delete)
$user = new App\User;
$user->name = "My Name";
$user->email = "whatever";
$user->save();
$user->name = "My new Name";
$user->update();
$user->delete();

 

Setup your home routes at /routes/web.php

Route::auth();
Route::get('/', 'CardsController@home';);

 

CardsController class

use App\Card;

class CardsController extends Controller{

public function home(){

$cards = Card::all();
return view('card.cards', ['cards' => $cards]);
}
}... 

 

hasMany() Model relationship (example Card has many notes)

hasMany()

class Card extends Model
{
protected $table = 'cards';
protected $primaryKey = 'id';

public function getNotes(){

return $this->hasMany(Note::class, 'card_id', $this->primaryKey);
}
}

HasMany () format

return $this->hasMany('App\Note', 'foreign_key_on_another_table', 'local_key_PK');

 

 

Test Card hasMany() Note:class relationship

php artisan tinker

#query first Card
$card = App\Card::first();

#query all the Card's notes
$card->getNotes->all();
$card->getNotes()->get();
$card->getNotes

#query the Card's first note
$card->getNotes->first();

#Same as above but more efficient (doesn't query all notes on the database)
$card->getNotes()->first();

#Attempt saving a note to this card
$card = App\Card::first();
$note = new App\Note;
$card->notes()->save($note);

#refresh
$card = $card->fresh();

#test
$card->getForeignKey()
$card->getQuery()
$card->touch()

 

belongsTo() Model relationship (example Note belongs to Card)

belongsTo()

class Note extends Model
{
protected $table = 'notes';
protected $primaryKey = 'nid';

public function belongsToCard(){

return $this->belongsTo(Card::class, 'card_id', 'cid');
}
}

belongsTo format

return $this->belongsTo('App\Card', 'foreign_key_on_local', 'other_key_PK_of_another_table');

 

Test Note belongsTo() Card::class relationship

php artisan tinker

#query first Note
$note = App\Card::first();

#query this note belongsTo which card
$note->belongsToCard

#query using your methods
$note->belongsToCard->getNotes->first()->belongsToCard

 

Laravel API

https://laravel.com/api/5.3/

 

Layout using blade

<!doctype html>

<html>
<head>
@include('includes.head')
@yield('title')
</head>
<body>
<div class="container">
<div class="row">
@include('includes.header')
</div>
<div id="main" class="row">
@yield('content')
</div>
<footer class="row">
@include('includes.footer')
</footer>
</div>
</body>
</html>

 

Head

Bootstrap in your head section

<meta charset="UTF-8">

<!-- If IE use the latest rendering engine -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Set the page to the width of the device and set the zoon level -->
<meta name="viewport" content="width = device-width, initial-scale = 1">

<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

Get the latest CSS Bootstrap version at:http://getbootstrap.com/getting-started/ or https://www.bootstrapcdn.com/

Footer

Provide jQuery before loading bootstrap.min.js

<!-- jquery -->
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<!-- bootstrap.min.js-->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

Get the latest jquery version at:http://jquery.com/download/#other-cdns or https://cdnjs.com/libraries/jquery/
Get the latest bootstrap.min.js at: https://www.bootstrapcdn.com/

 

Form with csrf

<form method="POST" action="/card/addNote">

<textarea class="form-control" name="body"></textarea>
<input type="submit" value="Add note" class="btn btn-default">

{{ csrf_field() }}
</form>

MassAssignmentException

Declare $fillable to fix Mass Assignment Exception on your class

class Note extends Model
{
     protected $table = 'notes';
     protected $primaryKey = 'nid';

     protected $fillable = ['body', 'abc', 'zyx'];
...

 

Add validation to your form

Cleaner to put on contoller

public function addNote(Request $request, int $cid){

$this->validate($request, ['body' => 'required | min:10']);

...
}

 If you wish to use Input::all() you may need to use below on your controller

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
...
public function firstloginhtmlSubmit(Request $request){

$rules = [ 'name' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed' ];

$validator = Validator::make(Input::all(), $rules);
...
}
...

 

Display validation error on your view

@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

Give back old user input data that was cleared due to validation error on the form {{ old(‘body’) }}

Display all validation error

{{print_r($errors)}}

@if(Session::get('errors'))
<div class="alert alert-danger alert-dismissable">
@foreach($errors->all() as $msg)
<li> {{ $msg }} </li>
@endforeach
</div>
@endif

 

Display validation error with Bootstrap

Chose from has-error has-warning has-success

<form method="POST" class="form-group">

<div class="@if($errors->has('body')) has-error @endif">
<textarea class="form-control" name="body">{{$note->body}}</textarea>
</div>
...
</form>

 

Display custom validation error with Bootstrap

<form method="POST" class="form-group">

<div class="@if($errors->has('body')) has-error @endif">
@if ($errors->has('body'))
<p class="help-block">Please enter your message</p>
@endif
<textarea class="form-control" name="body">{{$note->body}}</textarea>
</div>
...
</form>

 Refer to bootstrap for more options: http://getbootstrap.com/css/?#forms-help-text

 

Pagination

class CardsController extends Controller
{
public function home(){

$cards = Card::paginate(25);

return view('card.cards', ['cards' => $cards]);
}

 

Display pagination on view

{{ $cards->links() }}

 

Configure mail

For gmail, port 465 (with SSL) and port 587 (with TLS)

.env

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=xyz@gmail.com
MAIL_PASSWORD=pass
MAIL_ENCRYPTION=ssl

/config/mail.php

'driver' => env('MAIL_DRIVER', 'smtp'),
'host' => env('MAIL_HOST', 'smtp.gmail.com'),
'port' => env('MAIL_PORT', 587),
'from' => ['address' => 'xyz@abc.com', 'name' => 'xyz'],
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'sendmail' => '/usr/sbin/sendmail -bs',

Clear cache

php artisan config:cache
php artisan config:clear

 

Disable gmail security (DisplayUnlockCaptcha)

https://accounts.google.com/b/0/DisplayUnlockCaptcha

Disable gmail security

https://www.google.com/settings/security/lesssecureapps

 

Enable 2 factor authentication if you do not wish to disable google security

http://www.google.com/landing/2step/

Generate apppasswords

https://security.google.com/settings/security/apppasswords

 

Admin.google.com

Step1. Go to admin.google.com
Step2. Select “Security” -> “Basic settings” -> “Less secure apps”
Step3. Go to settings for less secure apps -> Check the radio button “Allow users to manage their access to less secure apps”
Step4. Save the changes
Step5. Open this link being sign in as the super administrator https://www.google.com/settings/security/lesssecureapps
Step7. Check the radio button Turn On the access for less secure apps
Step8. Unlock Captcha using this link https://accounts.google.com/DisplayUnlockCaptcha

 

 

Make middleware

php artisan make:middleware AdminOnly

Assign Middleware To Routes

# app/Http/Kernel.php

...
protected $routeMiddleware = [

'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'AdminOnly' => \App\Http\Middleware\AdminOnly::class,

];

Leave a Comment

Your email address will not be published. Required fields are marked *