Thứ Ba, 22 tháng 11, 2016

Laravel 5 Blog System : CRUD on Admin Panel Backend Services


Laravel 5.3 Tutorial - Create a CRUD operations on Admin Panel / Backend services, this lesson will show you how to manage posts in dashbord admin, at the previews lessons, we have learn how to setup database, create migration and table, display post, create single page, adding comment systems, bootstrap templates.

This lessons, we will working on Backends services.

Create Admin Panel Using Bootstrap

We will using bootstrap for our dashbord, download admin dahsbord from gootstrap site http://getbootstrap.com/examples/dashboard/
here's video tutorial how to create panel admin in Laravel



Full source code :
make sure you have install bootstrap on our project, or just follow video tutorial above.

dashbord.blade.php (resources\views\layouts\dashbord.blade.php)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Admin Dashboard</title>
    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
      <!-- Bootstrap core CSS -->
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="{{ asset('css/ie10-viewport-bug-workaround.css') }}" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link href="{{ asset('dashboard.css') }}" rel="stylesheet">
    <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
    <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
    <script src="{{ asset('js/ie-emulation-modes-warning.js')}}"></script>

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/admin/index">
            <img alt="Brand" src="{{ asset('img/logo.png') }}" width="60%">
          </a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            @if (Auth::guest())
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                Members<span class="caret"></span>
              </a>
              <ul class="dropdown-menu" role="menu">
                <li><a href="{{ url('/login') }}">Login</a></li>
                <li><a href="{{ url('/register') }}">Register</a></li>
              </ul>
            </li>
            @else
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                {{ Auth::user()->name }} <span class="caret"></span>
              </a>
              <ul class="dropdown-menu" role="menu">
                <li>
                  <a href="{{ url('/logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
                    Logout
                  </a>
                  <form id="logout-form" action="{{ url('/logout') }}" method="POST" style="display: none;">
                      {{ csrf_field() }}
                  </form>
                </li>
              </ul>
            </li>
            @endif
          </ul>
        </div>
      </div>
    </nav>
    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="/admin/">Overview <span class="sr-only">(current)</span></a></li>
            <li><a href="/admin/posts/allposts">All Posts</a></li>
            <li><a href="/admin/posts/alldrafts">Drafts</a></li>
            <li><a href="/admin/posts/allcomments">Comments</a></li>
            <li><a href="#">Label</a></li>
            <li><a href="#">User</a></li>
            <li><a href="#">Profile</a></li>
          </ul>
        </div>
        <div class="col-sm-9 main">
          @yield('content')
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="{{ asset('vendor/jquery/jquery.min.js') }}"><\/script>')</script>
    <script src="{{ asset('js/bootstrap.min.js') }}"></script>
    <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
    <script src="{{ asset('js/vendor/holder.min.js') }}"></script>
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="{{ asset('js/ie10-viewport-bug-workaround.js') }}"></script>

    <!-- show images thumbnail in create/edit page -->
    <script type="text/javascript">
      function readURL(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function (e) {
            $('#showimages').attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }
      $("#inputimages").change(function () {
        readURL(this);
      });
    </script>
  </body>
</html>

Next, on the index.blade.php add this source code

index.blade.php (resources\views\admin\index.blade.php)

@extends('layouts.dashbord')
@section('content')
<div class="col-sm-9 main">
  <h2 class="sub-header">Dashbord</h2>
  <div class="table-responsive">
    <p>
      wellcome admin, you can add, update, delete any posts, comments, drafts, etc ..
    </p>
    <p>
      <a href="http://www.hc-kr.com/">www.hc-kr.com</a>
    </p>
  </div>
</div>
@endsection

CRUD Operations (on Posts Table)

Next, we will create crud operation for manage the posts,
this's video tutorial crud operation for manage the posts.


Full source code

PostsController (app\Http\Controllers\Auth\PostsController.php)

<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Posts;
use App\User;
use Redirect;
class PostsController extends Controller {
    // show all posts
    public function index(Request $request) {
        // i'll stored all posts and search function
        $search = $request->get('search');
        $posts = Posts::where('title','like','%'.$search.'%')->where('active',1)->orderBy('created_at')->paginate(3);
        return view('admin/posts/allposts')->withPosts($posts);
    }
    // show form create post
    public function create(Request $request) {
        // if user can post i.e. user is admin or author
        if ($request->user()->can_post()){
          return view('admin/posts/create');
        } else {
          return redirect('/')->withErrors('You have not sufficient permissions for writing post');
        }
    }
    // save posts data into database
    public function store(Request $request) {
        $post = new Posts();
        $post->title = $request->get('title');
        $post->description = $request->get('description');
        $post->body = $request->get('body');
        $post->slug = str_slug($post->title);
        $post->author_id = $request->user()->id;

        // thumbnail upload
        if ($request->file('images')) {
          $fileName = str_random(30);
          $request->file('images')->move("img/",$fileName);
        } else {
          $fileName = $post->images;
        }
        $post->images = $fileName;

        if ($request->has('save')){
          // for draft
          $post->active = 0;
          $message = 'Post saved successfully';
        } else {
          // for posts
          $post->active = 1;
          $message = 'Post published successfully';
        }
        $post->save();
        return redirect('admin/posts/editpost/'.$post->slug)->withMessage($message);
    }

    public function show($id)
    {
        // next lessons we will use this function
    }

    public function edit(Request $request, $slug) {
        $post = Posts::where('slug',$slug)->first();
        if($post && ($request->user()->id == $post->author_id || $request->user()->is_admin()))
        return view('admin/posts/edit')->with('post',$post);
        return redirect('/')->withErrors('you have not sufficient permissions');
    }
    // update data
    public function update(Request $request) {
        $post_id = $request->input('post_id');
        $post = Posts::find($post_id);
        if ($post && ($post->author_id == $request->user()->id || $request->user()->is_admin())){
          $title = $request->input('title');
          $slug = str_slug($title);
          $duplicate = Posts::where('slug',$slug)->first();
          if($duplicate){
            if($duplicate->id != $post_id){
              return redirect('admin/posts/editpost/'.$post->slug)->withErrors('Title already exists.')->withInput();
            } else {
              $post->slug = $slug;
            }
          }
          $post->title = $title;
          // thumbnail upload
          if ($request->file('images')) {
            $fileName = str_random(30);
            $request->file('images')->move("img/",$fileName);
          } else {
            $fileName = $post->images;
          }
          $post->images = $fileName;
          $post->body = $request->input('body');

          if($request->has('save')){
            $post->active = 0;
            $message = 'Post saved successfully';
            $goto = 'admin/posts/editpost/'.$post->slug;
          } else {
            $post->active = 1;
            $message = 'Post updated successfully';
            $goto = 'admin/posts/allposts';
          }
          $post->save();
          return redirect($goto)->withMessage($message);
        } else {
          return redirect('/')->withErrors('you have not sufficient permissions');
        }
    }

    public function destroy(Request $request, $id) {
        $post = Posts::find($id);
        if($post && ($post->author_id == $request->user()->id || $request->user()->is_admin())){
          $post->delete();
          $data['message'] = 'Post deleted Successfully';

        } else {
          $data['errors'] = 'Invalid Operation. You have not sufficient permissions';
        }
        return redirect('admin/posts/allposts')->with($data);
    }
}

User Model (app\User.php)

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function can_post() {
      $role = $this->role;
      if($role == 'author' || $role == 'admin') {
        return true;
      }
      return false;
    }

    public function is_admin() {
      $role = $this->role;
      if($role == 'admin') {
        return true;
      }
      return false;
    }

    public function posts() {
      return $this->hasMany('App\Posts','author_id');
    }

    public function comments() {
      return $this->hasMany('App\Comments','from_user');
    }
}

Routes

<?php
Auth::routes();
Route::get('/','PostsController@index');
Route::get('/home', 'PostsController@index');
Route::get('/{slug}', 'PostsController@show')->where('slug', '[A-Za-z0-9-_]+');
Route::group(['middleware' => ['auth']], function() {
  Route::post('comment/add','CommentsController@store');
  Route::get('admin/index', 'PostsController@indexDashbord');
  Route::resource('admin/posts/','Auth\PostsController');
  Route::get('admin/posts/allposts','Auth\PostsController@index');
  // show new post form
  Route::get('admin/posts/new-post','Auth\PostsController@create');
  // save new post
  Route::post('admin/posts/createpost','Auth\PostsController@store');
  // edit form
  Route::get('admin/posts/editpost/{slug}','Auth\PostsController@edit');
  // update data
  Route::post('admin/posts/updatepost','Auth\PostsController@update');
  // delete post
  Route::get('admin/posts/deletepost/{id}','Auth\PostsController@destroy');
});

allposts.blade.php (resources\views\admin\posts\allposts.blade.php)

@extends('layouts.dashbord')
@section('content')
  <h2 class="sub-header">All Posts</h2>
  <div class="row">
    <div class="col-md-9">
      <a href="{{ url('admin/posts/new-post')}}" class="btn btn-primary btn-sm">Add New Post</a>
    </div>
    <div class="col-md-3">
      {!! Form::open(['method'=>'GET','url'=>'admin/posts/','class'=>'navbar-form navbar-left','role'=>'search']) !!}
        <div class="input-group custom-search-form">
          <input type="text" name="search" class="form-control" placeholder="Search ....">
          <span class="input-group-btn">
            <button type="submit" class="btn btn-default-sm">
              <i class="fa fa-search"></i>
            </button>
          </span>
        </div>
      {!! Form::close() !!}
    </div>
  </div>

  <div class="table-responsive">
    <table class="table table-striped">
      <thead>
      <tr>
        <th>#</th>
        <th>Title</th>
        <th>Description</th>
        <th>Post</th>
        <th>Url's</th>
        <th>Image</th>
        <th>Created</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <?php $no=1; ?>
      @foreach($posts as $post)
        <tr>
          <td>{{$no++}}</td>
          <td>{{$post->title}}</td>
          <td>{{$post->description}}</td>
          <td>
            {{ str_limit($post->body, $limit = 120, $end = '.......') }}
          </td>
          <td>
            {!! ('<a href='.url("/".$post->slug).'>'.$post->slug.'</a>') !!}
          </td>
          <td>
            <img src="{{ url('img/'.$post->images)}}" id ="showimages" style="max-width:100px;max-height:50px;float:left;">
          </td>
          <td>{{$post->created_at}}</td>
          <td>
            <form class="" action="" method="post">
              <input type="hidden" name="_method" value="delete">
              <input type="hidden" name="_token" value="{{ csrf_token() }}">
              <a href="{{ url('admin/posts/editpost/'.$post->slug)}}" class="btn btn-primary btn-xs">
                <span class="glyphicon glyphicon-edit"></span>
              </a>

              <a href="{{ url('admin/posts/deletepost/'.$post->id.'?_token='.csrf_token()) }}" onclick="return confirm('Are you sure to delete this data');" class="btn btn-danger btn-xs">
                <span class="glyphicon glyphicon-trash"></span>
              </a>
            </form>
          </td>
        </tr>
      @endforeach
    </tbody>
    </table>
    <!-- pagination -->
    {!! $posts->links() !!}
  </div>
@endsection

create.blade.php (resources\views\admin\posts\create.blade.php)

@extends('layouts.dashbord')
@section('content')
<h2>Create New Post</h2>
<script type="text/javascript" src="//cdn.tinymce.com/4/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
  selector : "textarea",
  plugins : ["advlist autolink lists link image charmap print preview anchor", "searchreplace visualblocks code fullscreen", "insertdatetime media table contextmenu paste"],
  toolbar : "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});
</script>

<form action="{{ url('/admin/posts/createpost') }}" method="post" enctype="multipart/form-data">
  <input type="hidden" name="_token" value="{{ csrf_token() }}">
  <div class="form-group">
    <p>Title</p>
    <input type="text" name="title" value="{{ old('title') }}" required="required" placeholder="Enter title here" class="form-control">
    <br>
    <p>Description</p>
    <input type="text" name="description" value="{{ old('description') }}" required="required" placeholder="Enter description here" class="form-control">
    <br>
    <!-- thumbnail upload -->
    <p>Thumbnail</p>
    <img src="http://placehold.it/100x100" id ="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
  </div>

  <div class="form-group">
    <textarea name='body'class="form-control" rows="20"></textarea>
  </div>
  <input type="submit" name='publish' class="btn btn-success" value = "Publish"/>
  <input type="submit" name='save' class="btn btn-default" value = "Save Draft" />
</form>
@endsection

edit.blade.php (resources\views\admin\posts\edit.blade.php)

@extends('layouts.dashbord')
@section('content')
<h2>Update Post</h2>
<script type="text/javascript" src="//cdn.tinymce.com/4/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
  selector : "textarea",
  plugins : ["advlist autolink lists link image charmap print preview anchor", "searchreplace visualblocks code fullscreen", "insertdatetime media table contextmenu paste"],
  toolbar : "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});
</script>

<form action="{{ url('/admin/posts/updatepost') }}" method="post" enctype="multipart/form-data">
  <input type="hidden" name="_token" value="{{ csrf_token() }}">
  <input type="hidden" name="post_id" value="{{ $post->id }}{{ old('post_id') }}">
  <input type="hidden" name="post_descriptions" value="{{ $post->id }}{{ old('post_id') }}">
  <div class="form-group">
    <p>Title</p>
    <input type="text" name="title" value="@if(!old('title')){{$post->title}}@endif{{ old('title') }}" required="required" placeholder="Enter title here" class="form-control">
    <br>
    <p>Description</p>
    <input type="text" name="description" value="@if(!old('description')){{$post->description}}@endif{{ old('description') }}" required="required" placeholder="Enter description here" class="form-control">
    <br>
    <!-- thumbnail upload -->
    <p>Thumbnail</p>
    <img src="{{ url('img/'.$post->images) }}" id ="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
  </div>

  <div class="form-group">
    <textarea name='body'class="form-control" rows="20">
      @if(!old('body'))
        {!! $post->body !!}
      @endif
        {!! old('body') !!}
    </textarea>
  </div>
  @if($post->active == '1')
    <input type="submit" name='publish' class="btn btn-success" value = "Update"/>
  @else
    <input type="submit" name='publish' class="btn btn-success" value = "Publish"/>
  @endif
  <input type="submit" name='save' class="btn btn-default" value = "Save As Draft" />
  <a href="{{ url('admin/posts/deletepost/'.$post->id.'?_token='.csrf_token()) }}" onclick="return confirm('Are you sure to delete this data');" class="btn btn-danger">Delete</a>
</form>
@endsection

Note :
Please watch video tutorial before do anything,

for full tutorial is here

CRUD on Admin Panel Backend Services



See you next lessons

Laravel 5 Blog System : CRUD on Admin Panel Backend Services


Laravel 5.3 Tutorial - Create a CRUD operations on Admin Panel / Backend services, this lesson will show you how to manage posts in dashbord admin, at the previews lessons, we have learn how to setup database, create migration and table, display post, create single page, adding comment systems, bootstrap templates.

This lessons, we will working on Backends services.

Create Admin Panel Using Bootstrap

We will using bootstrap for our dashbord, download admin dahsbord from gootstrap site http://getbootstrap.com/examples/dashboard/
here's video tutorial how to create panel admin in Laravel



Full source code :
make sure you have install bootstrap on our project, or just follow video tutorial above.

dashbord.blade.php (resources\views\layouts\dashbord.blade.php)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Admin Dashboard</title>
    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
      <!-- Bootstrap core CSS -->
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="{{ asset('css/ie10-viewport-bug-workaround.css') }}" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link href="{{ asset('dashboard.css') }}" rel="stylesheet">
    <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
    <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
    <script src="{{ asset('js/ie-emulation-modes-warning.js')}}"></script>

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/admin/index">
            <img alt="Brand" src="{{ asset('img/logo.png') }}" width="60%">
          </a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            @if (Auth::guest())
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                Members<span class="caret"></span>
              </a>
              <ul class="dropdown-menu" role="menu">
                <li><a href="{{ url('/login') }}">Login</a></li>
                <li><a href="{{ url('/register') }}">Register</a></li>
              </ul>
            </li>
            @else
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                {{ Auth::user()->name }} <span class="caret"></span>
              </a>
              <ul class="dropdown-menu" role="menu">
                <li>
                  <a href="{{ url('/logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
                    Logout
                  </a>
                  <form id="logout-form" action="{{ url('/logout') }}" method="POST" style="display: none;">
                      {{ csrf_field() }}
                  </form>
                </li>
              </ul>
            </li>
            @endif
          </ul>
        </div>
      </div>
    </nav>
    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="/admin/">Overview <span class="sr-only">(current)</span></a></li>
            <li><a href="/admin/posts/allposts">All Posts</a></li>
            <li><a href="/admin/posts/alldrafts">Drafts</a></li>
            <li><a href="/admin/posts/allcomments">Comments</a></li>
            <li><a href="#">Label</a></li>
            <li><a href="#">User</a></li>
            <li><a href="#">Profile</a></li>
          </ul>
        </div>
        <div class="col-sm-9 main">
          @yield('content')
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="{{ asset('vendor/jquery/jquery.min.js') }}"><\/script>')</script>
    <script src="{{ asset('js/bootstrap.min.js') }}"></script>
    <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
    <script src="{{ asset('js/vendor/holder.min.js') }}"></script>
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="{{ asset('js/ie10-viewport-bug-workaround.js') }}"></script>

    <!-- show images thumbnail in create/edit page -->
    <script type="text/javascript">
      function readURL(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function (e) {
            $('#showimages').attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }
      $("#inputimages").change(function () {
        readURL(this);
      });
    </script>
  </body>
</html>

Next, on the index.blade.php add this source code

index.blade.php (resources\views\admin\index.blade.php)

@extends('layouts.dashbord')
@section('content')
<div class="col-sm-9 main">
  <h2 class="sub-header">Dashbord</h2>
  <div class="table-responsive">
    <p>
      wellcome admin, you can add, update, delete any posts, comments, drafts, etc ..
    </p>
    <p>
      <a href="http://www.hc-kr.com/">www.hc-kr.com</a>
    </p>
  </div>
</div>
@endsection

CRUD Operations (on Posts Table)

Next, we will create crud operation for manage the posts,
this's video tutorial crud operation for manage the posts.


Full source code

PostsController (app\Http\Controllers\Auth\PostsController.php)

<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Posts;
use App\User;
use Redirect;
class PostsController extends Controller {
    // show all posts
    public function index(Request $request) {
        // i'll stored all posts and search function
        $search = $request->get('search');
        $posts = Posts::where('title','like','%'.$search.'%')->where('active',1)->orderBy('created_at')->paginate(3);
        return view('admin/posts/allposts')->withPosts($posts);
    }
    // show form create post
    public function create(Request $request) {
        // if user can post i.e. user is admin or author
        if ($request->user()->can_post()){
          return view('admin/posts/create');
        } else {
          return redirect('/')->withErrors('You have not sufficient permissions for writing post');
        }
    }
    // save posts data into database
    public function store(Request $request) {
        $post = new Posts();
        $post->title = $request->get('title');
        $post->description = $request->get('description');
        $post->body = $request->get('body');
        $post->slug = str_slug($post->title);
        $post->author_id = $request->user()->id;

        // thumbnail upload
        if ($request->file('images')) {
          $fileName = str_random(30);
          $request->file('images')->move("img/",$fileName);
        } else {
          $fileName = $post->images;
        }
        $post->images = $fileName;

        if ($request->has('save')){
          // for draft
          $post->active = 0;
          $message = 'Post saved successfully';
        } else {
          // for posts
          $post->active = 1;
          $message = 'Post published successfully';
        }
        $post->save();
        return redirect('admin/posts/editpost/'.$post->slug)->withMessage($message);
    }

    public function show($id)
    {
        // next lessons we will use this function
    }

    public function edit(Request $request, $slug) {
        $post = Posts::where('slug',$slug)->first();
        if($post && ($request->user()->id == $post->author_id || $request->user()->is_admin()))
        return view('admin/posts/edit')->with('post',$post);
        return redirect('/')->withErrors('you have not sufficient permissions');
    }
    // update data
    public function update(Request $request) {
        $post_id = $request->input('post_id');
        $post = Posts::find($post_id);
        if ($post && ($post->author_id == $request->user()->id || $request->user()->is_admin())){
          $title = $request->input('title');
          $slug = str_slug($title);
          $duplicate = Posts::where('slug',$slug)->first();
          if($duplicate){
            if($duplicate->id != $post_id){
              return redirect('admin/posts/editpost/'.$post->slug)->withErrors('Title already exists.')->withInput();
            } else {
              $post->slug = $slug;
            }
          }
          $post->title = $title;
          // thumbnail upload
          if ($request->file('images')) {
            $fileName = str_random(30);
            $request->file('images')->move("img/",$fileName);
          } else {
            $fileName = $post->images;
          }
          $post->images = $fileName;
          $post->body = $request->input('body');

          if($request->has('save')){
            $post->active = 0;
            $message = 'Post saved successfully';
            $goto = 'admin/posts/editpost/'.$post->slug;
          } else {
            $post->active = 1;
            $message = 'Post updated successfully';
            $goto = 'admin/posts/allposts';
          }
          $post->save();
          return redirect($goto)->withMessage($message);
        } else {
          return redirect('/')->withErrors('you have not sufficient permissions');
        }
    }

    public function destroy(Request $request, $id) {
        $post = Posts::find($id);
        if($post && ($post->author_id == $request->user()->id || $request->user()->is_admin())){
          $post->delete();
          $data['message'] = 'Post deleted Successfully';

        } else {
          $data['errors'] = 'Invalid Operation. You have not sufficient permissions';
        }
        return redirect('admin/posts/allposts')->with($data);
    }
}

User Model (app\User.php)

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function can_post() {
      $role = $this->role;
      if($role == 'author' || $role == 'admin') {
        return true;
      }
      return false;
    }

    public function is_admin() {
      $role = $this->role;
      if($role == 'admin') {
        return true;
      }
      return false;
    }

    public function posts() {
      return $this->hasMany('App\Posts','author_id');
    }

    public function comments() {
      return $this->hasMany('App\Comments','from_user');
    }
}

Routes

<?php
Auth::routes();
Route::get('/','PostsController@index');
Route::get('/home', 'PostsController@index');
Route::get('/{slug}', 'PostsController@show')->where('slug', '[A-Za-z0-9-_]+');
Route::group(['middleware' => ['auth']], function() {
  Route::post('comment/add','CommentsController@store');
  Route::get('admin/index', 'PostsController@indexDashbord');
  Route::resource('admin/posts/','Auth\PostsController');
  Route::get('admin/posts/allposts','Auth\PostsController@index');
  // show new post form
  Route::get('admin/posts/new-post','Auth\PostsController@create');
  // save new post
  Route::post('admin/posts/createpost','Auth\PostsController@store');
  // edit form
  Route::get('admin/posts/editpost/{slug}','Auth\PostsController@edit');
  // update data
  Route::post('admin/posts/updatepost','Auth\PostsController@update');
  // delete post
  Route::get('admin/posts/deletepost/{id}','Auth\PostsController@destroy');
});

allposts.blade.php (resources\views\admin\posts\allposts.blade.php)

@extends('layouts.dashbord')
@section('content')
  <h2 class="sub-header">All Posts</h2>
  <div class="row">
    <div class="col-md-9">
      <a href="{{ url('admin/posts/new-post')}}" class="btn btn-primary btn-sm">Add New Post</a>
    </div>
    <div class="col-md-3">
      {!! Form::open(['method'=>'GET','url'=>'admin/posts/','class'=>'navbar-form navbar-left','role'=>'search']) !!}
        <div class="input-group custom-search-form">
          <input type="text" name="search" class="form-control" placeholder="Search ....">
          <span class="input-group-btn">
            <button type="submit" class="btn btn-default-sm">
              <i class="fa fa-search"></i>
            </button>
          </span>
        </div>
      {!! Form::close() !!}
    </div>
  </div>

  <div class="table-responsive">
    <table class="table table-striped">
      <thead>
      <tr>
        <th>#</th>
        <th>Title</th>
        <th>Description</th>
        <th>Post</th>
        <th>Url's</th>
        <th>Image</th>
        <th>Created</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <?php $no=1; ?>
      @foreach($posts as $post)
        <tr>
          <td>{{$no++}}</td>
          <td>{{$post->title}}</td>
          <td>{{$post->description}}</td>
          <td>
            {{ str_limit($post->body, $limit = 120, $end = '.......') }}
          </td>
          <td>
            {!! ('<a href='.url("/".$post->slug).'>'.$post->slug.'</a>') !!}
          </td>
          <td>
            <img src="{{ url('img/'.$post->images)}}" id ="showimages" style="max-width:100px;max-height:50px;float:left;">
          </td>
          <td>{{$post->created_at}}</td>
          <td>
            <form class="" action="" method="post">
              <input type="hidden" name="_method" value="delete">
              <input type="hidden" name="_token" value="{{ csrf_token() }}">
              <a href="{{ url('admin/posts/editpost/'.$post->slug)}}" class="btn btn-primary btn-xs">
                <span class="glyphicon glyphicon-edit"></span>
              </a>

              <a href="{{ url('admin/posts/deletepost/'.$post->id.'?_token='.csrf_token()) }}" onclick="return confirm('Are you sure to delete this data');" class="btn btn-danger btn-xs">
                <span class="glyphicon glyphicon-trash"></span>
              </a>
            </form>
          </td>
        </tr>
      @endforeach
    </tbody>
    </table>
    <!-- pagination -->
    {!! $posts->links() !!}
  </div>
@endsection

create.blade.php (resources\views\admin\posts\create.blade.php)

@extends('layouts.dashbord')
@section('content')
<h2>Create New Post</h2>
<script type="text/javascript" src="//cdn.tinymce.com/4/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
  selector : "textarea",
  plugins : ["advlist autolink lists link image charmap print preview anchor", "searchreplace visualblocks code fullscreen", "insertdatetime media table contextmenu paste"],
  toolbar : "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});
</script>

<form action="{{ url('/admin/posts/createpost') }}" method="post" enctype="multipart/form-data">
  <input type="hidden" name="_token" value="{{ csrf_token() }}">
  <div class="form-group">
    <p>Title</p>
    <input type="text" name="title" value="{{ old('title') }}" required="required" placeholder="Enter title here" class="form-control">
    <br>
    <p>Description</p>
    <input type="text" name="description" value="{{ old('description') }}" required="required" placeholder="Enter description here" class="form-control">
    <br>
    <!-- thumbnail upload -->
    <p>Thumbnail</p>
    <img src="http://placehold.it/100x100" id ="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
  </div>

  <div class="form-group">
    <textarea name='body'class="form-control" rows="20"></textarea>
  </div>
  <input type="submit" name='publish' class="btn btn-success" value = "Publish"/>
  <input type="submit" name='save' class="btn btn-default" value = "Save Draft" />
</form>
@endsection

edit.blade.php (resources\views\admin\posts\edit.blade.php)

@extends('layouts.dashbord')
@section('content')
<h2>Update Post</h2>
<script type="text/javascript" src="//cdn.tinymce.com/4/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
  selector : "textarea",
  plugins : ["advlist autolink lists link image charmap print preview anchor", "searchreplace visualblocks code fullscreen", "insertdatetime media table contextmenu paste"],
  toolbar : "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});
</script>

<form action="{{ url('/admin/posts/updatepost') }}" method="post" enctype="multipart/form-data">
  <input type="hidden" name="_token" value="{{ csrf_token() }}">
  <input type="hidden" name="post_id" value="{{ $post->id }}{{ old('post_id') }}">
  <input type="hidden" name="post_descriptions" value="{{ $post->id }}{{ old('post_id') }}">
  <div class="form-group">
    <p>Title</p>
    <input type="text" name="title" value="@if(!old('title')){{$post->title}}@endif{{ old('title') }}" required="required" placeholder="Enter title here" class="form-control">
    <br>
    <p>Description</p>
    <input type="text" name="description" value="@if(!old('description')){{$post->description}}@endif{{ old('description') }}" required="required" placeholder="Enter description here" class="form-control">
    <br>
    <!-- thumbnail upload -->
    <p>Thumbnail</p>
    <img src="{{ url('img/'.$post->images) }}" id ="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
  </div>

  <div class="form-group">
    <textarea name='body'class="form-control" rows="20">
      @if(!old('body'))
        {!! $post->body !!}
      @endif
        {!! old('body') !!}
    </textarea>
  </div>
  @if($post->active == '1')
    <input type="submit" name='publish' class="btn btn-success" value = "Update"/>
  @else
    <input type="submit" name='publish' class="btn btn-success" value = "Publish"/>
  @endif
  <input type="submit" name='save' class="btn btn-default" value = "Save As Draft" />
  <a href="{{ url('admin/posts/deletepost/'.$post->id.'?_token='.csrf_token()) }}" onclick="return confirm('Are you sure to delete this data');" class="btn btn-danger">Delete</a>
</form>
@endsection

Note :
Please watch video tutorial before do anything,

for full tutorial is here

CRUD on Admin Panel Backend Services



See you next lessons

Thứ Năm, 10 tháng 11, 2016

Build a Blog System with Laravel 5.3 - Setup Database, Display Post, Single Page, Comments System, Bootstrap Templates


Laravel 5.3 tutorial - How to Build a blog application using laravel 5.3? at the previews tutorial, we have learn how to make simple blog system using laravel 5.3, please read here Laravel 5.3 Make Simple Blog.

In this lessons, we will build a blog application with new versions, so just following this tutorial for step by step.

Build a Blog System with Laravel 5.3

INTRODUCTIONS

What is this application?
This is a simple blogging application with the following features:
Build a Blog System with Laravel 5.3

  1. Anyone can login or register
  2. Users can be 'admin', 'author' or 'subscriber'.
  3. Authors can write/update/delete their own posts.
  4. Admin has full access on the website and can read/ write/ update/ delete any of the posts.
  5. Anyone can read these posts
  6. Users can comment on the posts (only after login)
  7. Use tinymce library to create posts
  8. Adding images in the post
  9. Costumize slug
  10. etc..

Here's Intruction Video tutorials


BUILD BLOG APPLICATION PROJECT

First step, we need to create new database using MySQL database, make sure you have database and named with "myblog2016".

Create Project

next step, create new laravel project, install laravel 5.3 using composer

composer create-project --prefer-dist laravel/laravel myblog

Next, open the project using text editor and create conection

Create Connection

setup connection to database, your database configuration is stored on .ENV file

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myblog2016
DB_USERNAME=root
DB_PASSWORD=yourpassword

Create Table & Migrations

php artisan make:migration create_posts_table

php artisan make:migration create_comments_table

Posts migration file

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // posts table
        Schema::create('posts', function(Blueprint $table){
          $table->increments('id'); // table Id's
          $table -> integer('author_id') -> unsigned() -> default(0);
          $table->foreign('author_id')
                ->references('id')->on('users')
                ->onDelete('cascade');
          $table->string('title')->unique();
          $table->string('description'); // for meta description
          $table->text('body'); // our posts
          $table->string('slug')->unique();
          $table->string('images');
          $table->boolean('active');
          $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // drop posts table
        Schema::drop('posts');
    }
}

Comments migration file

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCommentTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // comments table
        Schema::create('comments', function(Blueprint $table){
          $table->increments('id');
          $table -> integer('on_post') -> unsigned() -> default(0);
          $table->foreign('on_post')
                ->references('id')->on('posts')
                ->onDelete('cascade');
          $table -> integer('from_user') -> unsigned() -> default(0);
          $table->foreign('from_user')
                ->references('id')->on('users')
                ->onDelete('cascade');
          $table->text('body'); // our comments
          $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // delete comments table
        Scheme::drop('comments');
    }
}

Create Authentication

php artisan make:auth

Edit user migrations file to add new role to database

            $table->string('password');
            // add new field in users table
            $table->enum('role',['admin','author','subscriber'])->default('author');
            $table->rememberToken();

Run migration

php artisan migrate

Video tutorial Setting up database



Create New Model

php artisan make:model Posts

php artisan make:model Comments

Posts Model

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Posts extends Model {
    // restricts columns from modifying
    protected $guarded = [];
    // posts has many comments
    // returns all comments on that post
    public function comments(){
      return $this->hasMany('App\Comments','on_post');
    }
    // returns the instance of the user who is author of that post
    public function author(){
      return $this->belongsTo('App\User','author_id');
    }
}

Comments Model

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Comments extends Model {
    // comments table in database
    protected $guarded = [];
    // user who has commented
    public function author(){
      return $this->belongsTo('App\User','from_user');
    }
    // returns post of any comment
    public function post(){
      return $this->belongsTo('App\Posts','on_post');
    }
}

Create New controller

php artisan make:controller PostsController --resource

php artisan make:controller CommnentsController --resource

PostsController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Posts;
use App\User;
use Redirect;
class PostsController extends Controller {
    public function index() {
        //fetch 5 posts from database which are active and latest
        $posts = Posts::where('active',1)->orderBy('created_at')->paginate(2);
        // page Heading
        $title = 'Latest Post';
        // return to our view (home.blade.php)
        return view('home')->withPosts($posts)->withTitle($title);
    }
    // we need to show the single page of our posts
    public function show($slug) {
      $post = Posts::where('slug',$slug)->first();
      if (!$post) {
        return redirect('/')->withErrors('requested page not found');
      }
      $comments = $post->comments;
      return view('posts.show')->withPost($post)->withComments($comments);
    }
}

CommentsController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Posts;
use App\Comments;
use Redirect;
class CommentsController extends Controller {
    public function store(Request $request) {
        $input['from_user'] = $request->user()->id;
        $input['on_post'] = $request->input('on_post');
        $input['body'] = $request->input('body');
        $slug = $request->input('slug');
        Comments::create( $input );
        return redirect($slug)->with('message', 'Comment published');
    }
}

Add Routes

Auth::routes();
Route::get('/','PostsController@index');
Route::get('/home', 'PostsController@index');
Route::get('/{slug}', 'PostsController@show')->where('slug', '[A-Za-z0-9-_]+');
Route::group(['middleware' => ['auth']], function() {
  Route::post('comment/add','CommentsController@store');
});

Adding Bootstrap templates

Download bootstrap template for blog here https://startbootstrap.com/template-overviews/clean-blog/
After download bootstrap templates, just copy all file to laravel Project (Public Folder) see on videos tutorial.

Next, we need to create master templates blade.

Create Master Templates (for home Page)
Create new file in resources\views\layouts\app.blade.php

app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Laravel 5.3 Blog System | www.hc-kr.com</title>

    <!-- Bootstrap Core CSS -->
    <link href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Theme CSS -->
    <link href="{{ asset('css/clean-blog.min.css') }}" rel="stylesheet">

    <!-- Custom Fonts -->
    <link href="{{ asset('vendor/font-awesome/css/font-awesome.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'>

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
        <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>
<body>

    <!-- Navigation -->
    <nav class="navbar navbar-default navbar-custom navbar-fixed-top">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header page-scroll">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                    <span class="sr-only">Toggle navigation</span>
                    Menu <i class="fa fa-bars"></i>
                </button>
                <a class="navbar-brand" href="index.html">Start Bootstrap</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="/">Home</a></li>
                    <li><a href="#">About</a></li>
                    <li><a href="#">Sample Post</a></li>
                    <li><a href="#">Contact</a></li>
                    @if (Auth::guest())
                      <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Members<span class="caret"></span></a>
                        <ul class="dropdown-menu" role="menu">
                          <li><a href="{{ url('/login') }}">Login</a></li>
                          <li><a href="{{ url('/register') }}">Register</a></li>
                        </ul>
                      </li>
                    @else
                    <li class="dropdown">
                      <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ Auth::user()->name }}<span class="caret"></span></a>
                      <ul class="dropdown-menu" role="menu">
                        <li><a href="{{ url('/logout') }}">Logout</a></li>
                      </ul>
                    </li>
                    @endif
                </ul>
            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container -->
    </nav>

    <!-- Page Header -->
    <!-- Set your background image for this header on the line below. -->
    <header class="intro-header" style="background-image: url({{ asset('/img/'.$post->images) }})">
        <div class="container">
            <div class="row">
                <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                  @yield('header')
                </div>
            </div>
        </div>
    </header>

    <!-- Main Content -->
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="post-preview">
                  @yield('content')
                </div>
                @yield('pagination')
            </div>
        </div>
    </div>

    <hr>

    <!-- Footer -->
    <footer>
        <div class="container">
            <div class="row">
                <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                    <ul class="list-inline text-center">
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-facebook fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-github fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                    </ul>
                    <p class="copyright text-muted">Copyright © Your Website 2016</p>
                </div>
            </div>
        </div>
    </footer>

    <!-- jQuery -->
    <script src="{{ asset('vendor/jquery/jquery.min.js') }}"></script>
    <!-- Bootstrap Core JavaScript -->
    <script src="{{ asset('vendor/bootstrap/js/bootstrap.min.js') }}"></script>
    <!-- Contact Form JavaScript -->
    <script src="{{ asset('js/jqBootstrapValidation.js') }}"></script>
    <script src="{{ asset('js/contact_me.js') }}"></script>
    <!-- Theme JavaScript -->
    <script src="{{ asset('js/clean-blog.min.js') }}"></script>
</body>

</html>

Update home.blade.php that stored on resources\views\home.blade.php

home.blade.php

@extends('layouts.app')
@section('header')
  <div class="site-heading">
    <h1>Sector Code</h1>
    <hr class="small">
    <span class="subheading">Simple Laravel 5.3 Blogs System, Share and subsribe our channel <br>
      More tutorial go to www.hc-kr.com
    </span>
  </div>
@endsection
@section('content')
  @if (!$posts->count())
    There is no post till now. Login and write a new post now!!!
  @else
  @foreach ($posts as $post)
      <h2 class="post-title">
        <a href="{{ url('/'.$post->slug) }}">{{ $post->title }}</a>
      </h2>
      <p class="post-subtitle">
        {!! str_limit($post->body, $limit= 120, $end = '....... <a href='.url("/".$post->slug).'>Read More</a>') !!}
      </p>
      <p class="post-meta">
        {{ $post->created_at->format('M d,Y \a\t h:i a') }} By <a href="{{ url('/user/'.$post->author_id)}}">{{ $post->author->name }}</a>
      </p>
  @endforeach
  @endif
@endsection
@section('pagination')
<div class="row">
  <hr>
  {!! $posts->links() !!}
</div>
@endsection

Next, create new master blade template for login/register page, that stored on resources\views\layouts\appadmin.blade.php

appadmin.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <!-- Styles -->
    <link href="/css/app.css" rel="stylesheet">
    <!-- Scripts -->
    <script>
        window.Laravel = <?php echo json_encode([
            'csrfToken' => csrf_token(),
        ]); ?>
    </script>
</head>
<body>
    <div class="container">
      <div class="row">
        <div class="col-md-12">
          @yield('content')
        </div>
      </div>
    </div>
    <!-- Scripts -->
    <script src="/js/app.js"></script>
</body>
</html>

Next, update our login or register page, that stored on resources\views\auth\login.blade.php and resources\views\auth\register.blade.php

Just replace this code @extends('layouts.app')
to @extends('layouts.appadmin')

Video Tutorial showing posts, comments, bootstrap templates



Follow and subscribe for the next lessons....

Build a Blog System with Laravel 5.3 - Setup Database, Display Post, Single Page, Comments System, Bootstrap Templates


Laravel 5.3 tutorial - How to Build a blog application using laravel 5.3? at the previews tutorial, we have learn how to make simple blog system using laravel 5.3, please read here Laravel 5.3 Make Simple Blog.

In this lessons, we will build a blog application with new versions, so just following this tutorial for step by step.

Build a Blog System with Laravel 5.3

INTRODUCTIONS

What is this application?
This is a simple blogging application with the following features:
Build a Blog System with Laravel 5.3

  1. Anyone can login or register
  2. Users can be 'admin', 'author' or 'subscriber'.
  3. Authors can write/update/delete their own posts.
  4. Admin has full access on the website and can read/ write/ update/ delete any of the posts.
  5. Anyone can read these posts
  6. Users can comment on the posts (only after login)
  7. Use tinymce library to create posts
  8. Adding images in the post
  9. Costumize slug
  10. etc..

Here's Intruction Video tutorials


BUILD BLOG APPLICATION PROJECT

First step, we need to create new database using MySQL database, make sure you have database and named with "myblog2016".

Create Project

next step, create new laravel project, install laravel 5.3 using composer

composer create-project --prefer-dist laravel/laravel myblog

Next, open the project using text editor and create conection

Create Connection

setup connection to database, your database configuration is stored on .ENV file

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myblog2016
DB_USERNAME=root
DB_PASSWORD=yourpassword

Create Table & Migrations

php artisan make:migration create_posts_table

php artisan make:migration create_comments_table

Posts migration file

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // posts table
        Schema::create('posts', function(Blueprint $table){
          $table->increments('id'); // table Id's
          $table -> integer('author_id') -> unsigned() -> default(0);
          $table->foreign('author_id')
                ->references('id')->on('users')
                ->onDelete('cascade');
          $table->string('title')->unique();
          $table->string('description'); // for meta description
          $table->text('body'); // our posts
          $table->string('slug')->unique();
          $table->string('images');
          $table->boolean('active');
          $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // drop posts table
        Schema::drop('posts');
    }
}

Comments migration file

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCommentTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // comments table
        Schema::create('comments', function(Blueprint $table){
          $table->increments('id');
          $table -> integer('on_post') -> unsigned() -> default(0);
          $table->foreign('on_post')
                ->references('id')->on('posts')
                ->onDelete('cascade');
          $table -> integer('from_user') -> unsigned() -> default(0);
          $table->foreign('from_user')
                ->references('id')->on('users')
                ->onDelete('cascade');
          $table->text('body'); // our comments
          $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // delete comments table
        Scheme::drop('comments');
    }
}

Create Authentication

php artisan make:auth

Edit user migrations file to add new role to database

            $table->string('password');
            // add new field in users table
            $table->enum('role',['admin','author','subscriber'])->default('author');
            $table->rememberToken();

Run migration

php artisan migrate

Video tutorial Setting up database



Create New Model

php artisan make:model Posts

php artisan make:model Comments

Posts Model

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Posts extends Model {
    // restricts columns from modifying
    protected $guarded = [];
    // posts has many comments
    // returns all comments on that post
    public function comments(){
      return $this->hasMany('App\Comments','on_post');
    }
    // returns the instance of the user who is author of that post
    public function author(){
      return $this->belongsTo('App\User','author_id');
    }
}

Comments Model

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Comments extends Model {
    // comments table in database
    protected $guarded = [];
    // user who has commented
    public function author(){
      return $this->belongsTo('App\User','from_user');
    }
    // returns post of any comment
    public function post(){
      return $this->belongsTo('App\Posts','on_post');
    }
}

Create New controller

php artisan make:controller PostsController --resource

php artisan make:controller CommnentsController --resource

PostsController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Posts;
use App\User;
use Redirect;
class PostsController extends Controller {
    public function index() {
        //fetch 5 posts from database which are active and latest
        $posts = Posts::where('active',1)->orderBy('created_at')->paginate(2);
        // page Heading
        $title = 'Latest Post';
        // return to our view (home.blade.php)
        return view('home')->withPosts($posts)->withTitle($title);
    }
    // we need to show the single page of our posts
    public function show($slug) {
      $post = Posts::where('slug',$slug)->first();
      if (!$post) {
        return redirect('/')->withErrors('requested page not found');
      }
      $comments = $post->comments;
      return view('posts.show')->withPost($post)->withComments($comments);
    }
}

CommentsController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Posts;
use App\Comments;
use Redirect;
class CommentsController extends Controller {
    public function store(Request $request) {
        $input['from_user'] = $request->user()->id;
        $input['on_post'] = $request->input('on_post');
        $input['body'] = $request->input('body');
        $slug = $request->input('slug');
        Comments::create( $input );
        return redirect($slug)->with('message', 'Comment published');
    }
}

Add Routes

Auth::routes();
Route::get('/','PostsController@index');
Route::get('/home', 'PostsController@index');
Route::get('/{slug}', 'PostsController@show')->where('slug', '[A-Za-z0-9-_]+');
Route::group(['middleware' => ['auth']], function() {
  Route::post('comment/add','CommentsController@store');
});

Adding Bootstrap templates

Download bootstrap template for blog here https://startbootstrap.com/template-overviews/clean-blog/
After download bootstrap templates, just copy all file to laravel Project (Public Folder) see on videos tutorial.

Next, we need to create master templates blade.

Create Master Templates (for home Page)
Create new file in resources\views\layouts\app.blade.php

app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Laravel 5.3 Blog System | www.hc-kr.com</title>

    <!-- Bootstrap Core CSS -->
    <link href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Theme CSS -->
    <link href="{{ asset('css/clean-blog.min.css') }}" rel="stylesheet">

    <!-- Custom Fonts -->
    <link href="{{ asset('vendor/font-awesome/css/font-awesome.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'>

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
        <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>
<body>

    <!-- Navigation -->
    <nav class="navbar navbar-default navbar-custom navbar-fixed-top">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header page-scroll">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                    <span class="sr-only">Toggle navigation</span>
                    Menu <i class="fa fa-bars"></i>
                </button>
                <a class="navbar-brand" href="index.html">Start Bootstrap</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="/">Home</a></li>
                    <li><a href="#">About</a></li>
                    <li><a href="#">Sample Post</a></li>
                    <li><a href="#">Contact</a></li>
                    @if (Auth::guest())
                      <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Members<span class="caret"></span></a>
                        <ul class="dropdown-menu" role="menu">
                          <li><a href="{{ url('/login') }}">Login</a></li>
                          <li><a href="{{ url('/register') }}">Register</a></li>
                        </ul>
                      </li>
                    @else
                    <li class="dropdown">
                      <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ Auth::user()->name }}<span class="caret"></span></a>
                      <ul class="dropdown-menu" role="menu">
                        <li><a href="{{ url('/logout') }}">Logout</a></li>
                      </ul>
                    </li>
                    @endif
                </ul>
            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container -->
    </nav>

    <!-- Page Header -->
    <!-- Set your background image for this header on the line below. -->
    <header class="intro-header" style="background-image: url({{ asset('/img/'.$post->images) }})">
        <div class="container">
            <div class="row">
                <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                  @yield('header')
                </div>
            </div>
        </div>
    </header>

    <!-- Main Content -->
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="post-preview">
                  @yield('content')
                </div>
                @yield('pagination')
            </div>
        </div>
    </div>

    <hr>

    <!-- Footer -->
    <footer>
        <div class="container">
            <div class="row">
                <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                    <ul class="list-inline text-center">
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-facebook fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                        <li>
                            <a href="#">
                                <span class="fa-stack fa-lg">
                                    <i class="fa fa-circle fa-stack-2x"></i>
                                    <i class="fa fa-github fa-stack-1x fa-inverse"></i>
                                </span>
                            </a>
                        </li>
                    </ul>
                    <p class="copyright text-muted">Copyright © Your Website 2016</p>
                </div>
            </div>
        </div>
    </footer>

    <!-- jQuery -->
    <script src="{{ asset('vendor/jquery/jquery.min.js') }}"></script>
    <!-- Bootstrap Core JavaScript -->
    <script src="{{ asset('vendor/bootstrap/js/bootstrap.min.js') }}"></script>
    <!-- Contact Form JavaScript -->
    <script src="{{ asset('js/jqBootstrapValidation.js') }}"></script>
    <script src="{{ asset('js/contact_me.js') }}"></script>
    <!-- Theme JavaScript -->
    <script src="{{ asset('js/clean-blog.min.js') }}"></script>
</body>

</html>

Update home.blade.php that stored on resources\views\home.blade.php

home.blade.php

@extends('layouts.app')
@section('header')
  <div class="site-heading">
    <h1>Sector Code</h1>
    <hr class="small">
    <span class="subheading">Simple Laravel 5.3 Blogs System, Share and subsribe our channel <br>
      More tutorial go to www.hc-kr.com
    </span>
  </div>
@endsection
@section('content')
  @if (!$posts->count())
    There is no post till now. Login and write a new post now!!!
  @else
  @foreach ($posts as $post)
      <h2 class="post-title">
        <a href="{{ url('/'.$post->slug) }}">{{ $post->title }}</a>
      </h2>
      <p class="post-subtitle">
        {!! str_limit($post->body, $limit= 120, $end = '....... <a href='.url("/".$post->slug).'>Read More</a>') !!}
      </p>
      <p class="post-meta">
        {{ $post->created_at->format('M d,Y \a\t h:i a') }} By <a href="{{ url('/user/'.$post->author_id)}}">{{ $post->author->name }}</a>
      </p>
  @endforeach
  @endif
@endsection
@section('pagination')
<div class="row">
  <hr>
  {!! $posts->links() !!}
</div>
@endsection

Next, create new master blade template for login/register page, that stored on resources\views\layouts\appadmin.blade.php

appadmin.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <!-- Styles -->
    <link href="/css/app.css" rel="stylesheet">
    <!-- Scripts -->
    <script>
        window.Laravel = <?php echo json_encode([
            'csrfToken' => csrf_token(),
        ]); ?>
    </script>
</head>
<body>
    <div class="container">
      <div class="row">
        <div class="col-md-12">
          @yield('content')
        </div>
      </div>
    </div>
    <!-- Scripts -->
    <script src="/js/app.js"></script>
</body>
</html>

Next, update our login or register page, that stored on resources\views\auth\login.blade.php and resources\views\auth\register.blade.php

Just replace this code @extends('layouts.app')
to @extends('layouts.appadmin')

Video Tutorial showing posts, comments, bootstrap templates



Follow and subscribe for the next lessons....

Thứ Sáu, 4 tháng 11, 2016

Laravel 5 Tutorial : Simple File (Image) Upload With Example In Laravel 5.3


Laravel 5.3 Tutorial - How to upload a file (image) in Laravel 5.3? this tutorial will show you how to create simple upload image or upload file using laravel 5.3.

I assume before doing this lesson, you must read step by step How to create simple Blog in laravel 5.3.

Simple File (Image) Upload With Example

First step, we need to add new column "images" in our database "blog_post" table, so please modife your migration tables or you can change it using manually in your PhpMyAdmin.

    public function up()
    {
        Schema::create('blog_post', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->string('description');
        $table->string('images');
        $table->timestamps();
      });
    }

Then run migration using Artisan CLI

php artisan migration:refresh

Next steps, add new folder ("image") in public\image, we will save our post images in here.

Goto our pages (blog/create.blade.php) and modife that file, we will add browse images button and save it to database
File (Image) Upload With Example In Laravel 5.3

resources\views\blog\create.blade.php

@extends('master')
@section('content')
  <h2>Add new post</h2>
  <form class="" action="/blog" method="post" enctype="multipart/form-data">
    <input type="text" name="title" value="" placeholder="this is title"><br>
    {{ ($errors->has('title')) ? $errors->first('title') : '' }} <br>
    <textarea name="description" rows="8" cols="100" placeholder="this is description"></textarea><br>
    {{ ($errors->has('description')) ? $errors->first('description') : '' }} <br>
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <img src="http://placehold.it/100x100" id="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
    <div class="col-md-12">
      <button type="submit" class="btn btn-primary pull-right" value="post">
        Submit
      </button>
    </div>
  </form>
@stop

resources\views\master.blade.php

add this JQuery files to show the thumbnail images in create pages.

<script type="text/javascript">
      function readURL(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function (e) {
            $('#showimages').attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }
      $("#inputimages").change(function () {
        readURL(this);
      });
  </script>

And finally, modife our controller

BlogController.php

public function store(Request $request)
    {
        // we will create validation function here
        $this->validate($request,[
            'title'=> 'required',
            'description' => 'required',
        ]);

        $blog = new Blog;
        $blog->title = $request->title;
        $blog->description = $request->description;


        $file = $request->file('images');
        $fileName = $file->getClientOriginalName();
        $request->file('images')->move("image/",$fileName);
        $blog->images = $fileName;
        // save all data
        $blog->save();
        //redirect page after save data
        return redirect('blog')->with('message','data hasbeen updated!');
    }

Video Tutorial How to Upload file (image) in Laravel 5.3



List Video Laravel 5.3 For beginners



Build Blog using laravel 5.3



Laravel Vue.JS Tutorial



See you next lessons ...

Laravel 5 Tutorial : Simple File (Image) Upload With Example In Laravel 5.3


Laravel 5.3 Tutorial - How to upload a file (image) in Laravel 5.3? this tutorial will show you how to create simple upload image or upload file using laravel 5.3.

I assume before doing this lesson, you must read step by step How to create simple Blog in laravel 5.3.

Simple File (Image) Upload With Example

First step, we need to add new column "images" in our database "blog_post" table, so please modife your migration tables or you can change it using manually in your PhpMyAdmin.

    public function up()
    {
        Schema::create('blog_post', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->string('description');
        $table->string('images');
        $table->timestamps();
      });
    }

Then run migration using Artisan CLI

php artisan migration:refresh

Next steps, add new folder ("image") in public\image, we will save our post images in here.

Goto our pages (blog/create.blade.php) and modife that file, we will add browse images button and save it to database
File (Image) Upload With Example In Laravel 5.3

resources\views\blog\create.blade.php

@extends('master')
@section('content')
  <h2>Add new post</h2>
  <form class="" action="/blog" method="post" enctype="multipart/form-data">
    <input type="text" name="title" value="" placeholder="this is title"><br>
    {{ ($errors->has('title')) ? $errors->first('title') : '' }} <br>
    <textarea name="description" rows="8" cols="100" placeholder="this is description"></textarea><br>
    {{ ($errors->has('description')) ? $errors->first('description') : '' }} <br>
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <img src="http://placehold.it/100x100" id="showimages" style="max-width:200px;max-height:200px;float:left;"/>
    <div class="row">
      <div class="col-md-12">
        <input type="file" id="inputimages" name="images">
      </div>
    </div>
    <div class="col-md-12">
      <button type="submit" class="btn btn-primary pull-right" value="post">
        Submit
      </button>
    </div>
  </form>
@stop

resources\views\master.blade.php

add this JQuery files to show the thumbnail images in create pages.

<script type="text/javascript">
      function readURL(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function (e) {
            $('#showimages').attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }
      $("#inputimages").change(function () {
        readURL(this);
      });
  </script>

And finally, modife our controller

BlogController.php

public function store(Request $request)
    {
        // we will create validation function here
        $this->validate($request,[
            'title'=> 'required',
            'description' => 'required',
        ]);

        $blog = new Blog;
        $blog->title = $request->title;
        $blog->description = $request->description;


        $file = $request->file('images');
        $fileName = $file->getClientOriginalName();
        $request->file('images')->move("image/",$fileName);
        $blog->images = $fileName;
        // save all data
        $blog->save();
        //redirect page after save data
        return redirect('blog')->with('message','data hasbeen updated!');
    }

Video Tutorial How to Upload file (image) in Laravel 5.3



List Video Laravel 5.3 For beginners



Build Blog using laravel 5.3



Laravel Vue.JS Tutorial



See you next lessons ...