Laravel 5.5 Beginner Task List

博主认为,最好的教程一定是官方文档。而要快速建立关于某个语言或框架的知识结构,一定是直接上手做一个小项目。

Laravel 5.5 于今年 8 月份发布,是下一个 LTS 版本,从这个版本发布开始会停止对 Laravel 5.1 的 bug 修复,而对 5.1 的安全修复直到 2018 年 7 月份。

LTS 是指长期支持版本,是 Laravel 能提供的最长时间维护的版本,一般发行版只提供 6 个月的 Bug 修复支持,一年的安全修复支持。所以商业用途最好使用 LTS 版本。

关于 LTS 可参考 Laravel 的发布路线图

网上关于 Laravel 的教程很多,但是教程的基本内容无非是了解 laravel 的 MVC ,然后做数据的增删改查。

官方文档其实就很好,该 tutorials 中包括两个部分,一个是 Beginner Task List 另一个是 Intermediate Task List 。可惜的是 5.5 目前还没有这部分的内容。

但是差异也不是很大,原文地址 Beginner Task List

本文是以上面的 5.1 文档为参考,以 5.5 为开发框架,进行了实践后,记录下来的。

本文中使用的环境是 ubuntu + apache + mysql + php ,使用的 hyper-v 虚拟机,关于这部分,对读者可能没有价值,可跳过。但对博主个人有记录以备后查的作用,所以会写下来。

安装 Laravel

我同时安装了 Laravel 5.1 和 Laravel 5.5 ,一个给到 51 端口,一个给到 55 端口。

环境要求

Laravel 5.5 系统要求 Laravel 5.1 系统要求
PHP >= 7.0.0
OpenSSL PHP Extension
PDO PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension
XML PHP Extension
PHP >= 5.5.9
OpenSSL PHP Extension
PDO PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension

通过 Laravel installer 安装 5.5 (最新的)

composer global require "laravel/installer"

如果此时输入 laravel 一定会提示 laravel: command not found
这是因为该命令不在环境变量中
查看环境变量:

$ echo $PATH
/home/thankit/bin:/home/thankit/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

一般情况下的 composer vendor bin 目录在:

  • MacOS: $HOME/.composer/vendor/bin
  • GNU / Linux Distributions: $HOME/.config/composer/vendor/bin

下面我们要将该变量添加到 $PATH 中

export PATH="~/.config/composer/vendor/bin:$PATH"

下面可以用 laravel 命令了。

切换到工作目录下,比如 todo55

laravel new

这样就会在当前目录下安装 laravel

下面我们查看下 laravel 的版本号

$ php artisan --version
Laravel Framework 5.5.20

通过 composer 安装 5.1

将 5.1 版本的放在目录 todo51
todo51 目录下

composer create-project laravel/laravel  ./ "5.1.*"

同样看下版本号:

$ php artisan --version
Laravel Framework version 5.1.46 (LTS)

设置权限

storagebootstrap/cache 目录, web 服务器必须具有可写权限。

对我来说,我需要给组 www-data 写权限

chmod g+w -R storage bootstrap/cache

设置虚拟目录 (可跳过)

确保 mod_rewrite 开启了,这样 public/.htaccess 就有作用了。

以下是针对 Apache 的

启用 Apache rewrite 模块 a2enmod rewrite

我将让 todo51 监听 51 端口,而 todo55 监听 55 端口

首先将 varnish 监听端口从 80 上改到 6082
其次修改 /etc/apache2/ports.conf 增加监听的端口
然后修改 /etc/apache2/sites-available/000-default.conf

<VirtualHost *:51>

        DocumentRoot /home/thankit/www/laravel/todo51/public
        <Directory /home/thankit/www/laravel/todo51/public>
                AllowOverride all
        #       Options +FollowSymLinks
        #       RewriteEngine On
        #       RewriteCond %{REQUEST_FILENAME} !-d
        #       RewriteCond %{REQUEST_FILENAME} !-f
        #       RewriteRule ^ index.php [L]
        </Directory>

</VirtualHost>
<VirtualHost *:55>

        DocumentRoot /home/thankit/www/laravel/todo55/public
        <Directory /home/thankit/www/laravel/todo55/public>
                AllowOverride all
        #       Options +FollowSymLinks
        #       RewriteEngine On
        #       RewriteCond %{REQUEST_FILENAME} !-d
        #       RewriteCond %{REQUEST_FILENAME} !-f
        #       RewriteRule ^ index.php [L]
        </Directory>

</VirtualHost>

看看是否监听了端口

netstat -lntp

一切正常,
将通过 http://192.168.0.251:51/ 访问 5.1 的 todo

laravel 5.1 安装成功

将通过 http://192.168.0.251:55/ 访问 5.5 的 todo

laravel 5.5 安装报错

下面我们得看看 5.5 为什么报错了。
我们进入 todo5.5 的目录,修改 config/app.php
将 debug 打开

'debug'  => env('APP_DEBUG', true),

下面我们再刷新,看看错误是什么

RuntimeException
No application encryption key has been specified.

下面直接将 .env.example 拷贝一份重命名为 .env
然后运行命令

5$ php artisan key:generate
Application key [base64:aJqES8WcAQJJ0jjoMKeQojV0TWnae5ALs8JQnm/uW5w=] set successfully.

下面再打开网站看看,这次正常了:

Task List 创建

数据库迁移

首先对数据库帐密进行设置,有两处 config\database.php.env

.env 是主配置文件,会覆盖 database.php 中的参数

我们设置好 .env 中关于 db 的部分
执行:

php artisan make:migration create_tasks_table --create=tasks

他将在 database/migrations/ 目录下创建类似 YYYY_M_DD_HHMMSS_create_tableName_table.php 的文件,就像2017_11_08_064436_create_tasks_table.php

其中的内容如下:

<?php

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

class CreateTasksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

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

该类包含了两个方法,up() (执行迁移命令时创建表结构)和 down() (执行回滚时删除表结构)

更多的参考 Database: Migrations

下面我们给他添加一个字段 name

    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

下面执行数据迁移:

php artisan migrate

然后我们进入数据库中看看,tasks 表被创建出来了

下面试一下回滚:

php artisan migrate:rollback

在看看数据库中的表都被删除了。

php artisan migrate:refresh 全部回滚重建

数据库填充

我们将创建一个 Task model 对应我们的表 tasks
默认规则是模型类名的复数作为与其对应的表名,除非在模型类中明确指定了其它名称。

php artisan make:model Task

他在 app 目录下创建了 Task.php 内容如下:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    //
}

下面我们创建自动填充文件:

php artisan make:seeder TasksTableSeeder

他将在 database/seeds 目录下创建 TasksTableSeeder.php ,这个文件就是数据库填充文件了,他的命名规则是数据库表名加上 TableSeeder 并且首字母大写,表名一般是复数,所以我们有了 TasksTableSeeder

#File: database/seeds/TasksTableSeeder.php
<?php

use App\Task;
use Illuminate\Database\Seeder;

class TasksTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('tasks')->insert(['name' => str_random(10)]);
        Task::create(['name' => 'thankit']);
    }
}

然后将 DatabaseSeeder.php 添加内容:

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // $this->call(UsersTableSeeder::class);
        $this->call(TasksTableSeeder::class);
    }
}

最后我们来运行命令:

php artisan db:seed

之后我们就可以在数据库中看看表中数据了:

路由

routes/web.php 文件用于定义 web 界面的路由。这里面的路由都会被分配给 web 中间件组,它提供了会话状态和 CSRF 保护等功能。定义在 routes/api.php 中的路由都是无状态的,并且被分配了 api 中间件组。

所以我们在 web.php 中添加以下内容

<?php
use Illuminate\Http\Request;
Route::get('/', function () {
    return view('tasks');
});

/**
 * Add A New Task
 */
Route::post('/task', function (Request $request) {
    //
});

/**
 * Delete An Existing Task
 */
Route::delete('/task/{id}', function ($id) {
    //
});

创建父 blade 模版

File:resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Laravel Quickstart - Basic</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" crossorigin="anonymous">
        <!-- CSS And JavaScript -->
    </head>

    <body>
        <div class="container">
            <nav class="navbar navbar-default">
                <!-- Navbar Contents -->
            </nav>
        </div>

        @yield('content')
    </body>
</html>

子 blade 模版

File:resources/views/tasks.blade.php

@extends('layouts.app')

@section('content')

    <!-- Bootstrap Boilerplate... -->

    <div class="panel-body">
        <!-- Display Validation Errors -->
        <?php // @include('common.errors') ;?>

        <!-- New Task Form -->
        <form action="/task" method="POST" class="form-horizontal">
            {{ csrf_field() }}

            <!-- Task Name -->
            <div class="form-group">
                <label for="task" class="col-sm-3 control-label">Task</label>

                <div class="col-sm-6">
                    <input type="text" name="name" id="task-name" class="form-control">
                </div>
            </div>

            <!-- Add Task Button -->
            <div class="form-group">
                <div class="col-sm-offset-3 col-sm-6">
                    <button type="submit" class="btn btn-default">
                        <i class="fa fa-plus"></i> Add Task
                    </button>
                </div>
            </div>
        </form>
    </div>

    <!-- TODO: Current Tasks -->
@endsection

解释,还是英文的说的好理解,所以附上:

the @extends directive informs Blade that we are using the layout we defined at resources/views/layouts/app.blade.php. All of the content between @section('content') and @endsection will be injected into the location of the @yield('content') directive within the app.blade.php layout

起码看起来有点样子了
Laravel 5.5

验证输入并增加 tasks

修改 web.php 中的路由:

// 这里不能少
use Illuminate\Http\Request;

Route::post('/task', function (Request $request) {

    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    // Create The Task...
});

这样去掉 resources/views/tasks.blade.php 中的注释

@include('common.errors')

补上模版:
resources/views/common/errors.blade.php

@if (count($errors) > 0)
    <!-- Form Error List -->
    <div class="alert alert-danger">
        <strong>Whoops! Something went wrong!</strong>

        <br><br>

        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

现在如果我们提交空值,就会有错误提示了。
Laravel 5.5

下面我们要增加 tasks
所以修改 web.php 的内容:

use App\Task;
use Illuminate\Http\Request;
/**
 * Display All Tasks
 */
Route::get('/', function () {
    return view('tasks');
});

/**
 * Add A New Task
 */
Route::post('/task', function (Request $request) {

    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput(['name' => 'reminder'])
            ->withErrors($validator);
    }

    // Create The Task...
    $task       = new Task;
    $task->name = $request->name;
    $task->save();

    return redirect('/');
});
...

所以接下来我们测试提交一个 task ,发现已经添加到数据库表中了。

展示已经有的 tasks

File:routes/web.php

Route::get('/', function () {
    $tasks = Task::orderBy('created_at', 'asc')->get();
    return view('tasks', [
        'tasks' => $tasks,
    ]);
});

File:resoures/views/tasks.blade.php

@extends('layouts.app')

@section('content')
    <!-- Create Task Form...这里有省略 -->

    <!-- Current Tasks -->
    @if (count($tasks) > 0)
        <div class="panel panel-default">
            <div class="panel-heading">
                Current Tasks
            </div>

            <div class="panel-body">
                <table class="table table-striped task-table">

                    <!-- Table Headings -->
                    <thead>
                        <th>Task</th>
                        <th>&nbsp;</th>
                    </thead>

                    <!-- Table Body -->
                    <tbody>
                        @foreach ($tasks as $task)
                            <tr>
                                <!-- Task Name -->
                                <td class="table-text">
                                    <div>{{ $task->name }}</div>
                                </td>

                                <td>
                                    <!-- TODO: Delete Button -->
                                </td>
                            </tr>
                        @endforeach
                    </tbody>
                </table>
            </div>
        </div>
    @endif
@endsection

效果如下:
Laravel 5.5

删除 tasks

上面的文件中我们留了一个删除按钮没有写
下面补上:

<tr>
    <!-- Task Name -->
    <td class="table-text">
        <div>{{ $task->name }}</div>
    </td>

    <td>
        <form action="/task/{{ $task->id }}" method="POST">
            {{ csrf_field() }}
            {{ method_field('DELETE') }}

            <button type="submit" class="btn btn-danger">Delete Task</button>
        </form>
    </td>
</tr>

注意这里的 {{ method_field('DELETE') }} 等同于

<input type="hidden" name="_method" value="DELETE">

File:routes/web.php

Route::delete('/task/{id}', function ($id) {
    Task::findOrFail($id)->delete();
    return redirect('/');
});

最后的效果如下:
Task List 最终效果

发表评论

电子邮件地址不会被公开。 必填项已用*标注