Laravel 教程:逐步构建您的第一个 Laravel 应用程序
发布于 作者: Eric L. Barnes
自 2011 年首次发布以来,Laravel 经历了指数级增长。2015 年,它成为 GitHub 上最受欢迎的 PHP 框架,并迅速成为全球各地人们的首选框架。如果您想了解更多关于历史的信息,请查看 什么是 Laravel。
Laravel 以最终用户为中心:这意味着它专注于简单性、清晰度和完成工作。个人和公司都在用它来构建各种应用程序,从简单的业余爱好项目到财富 500 强公司。
我编写本 Laravel 教程的目的是为正在学习 Laravel 的初学者提供一个指南。本指南将带您从最初的想法到真正的可部署应用程序。如果您希望以电子书的形式阅读本教程,您可以订阅我们的每周 Laravel 新闻简报 并免费获得它。
本教程对 Laravel 的介绍并非面面俱到,但如果您想要更全面的介绍,我建议您阅读《Laravel:快速入门》一书。本教程假定您具备一些先决条件,以下是您需要了解的内容
注意:对于本地 PHP 开发,我建议使用 Mac OSX 和 Valet,因为它会自动设置所有内容。如果您使用的是 Windows,请考虑使用 Homestead 或其他虚拟机。另一个选择是社区提供的 Valet 的 Windows 移植版。
我正在尝试按照在真实环境中创建新应用程序的方式来进行。事实上,代码和想法来自我构建的一个项目。
规划
每个项目都必须从某个地方开始;无论是工作中的项目任务,还是脑海中的想法。无论它起源于哪里,在开始编码之前彻底规划所有功能对于完成项目至关重要。
您如何规划取决于您的思维方式。作为视觉型的人,我喜欢在纸上进行规划,画出我设想的屏幕外观,然后从编码方式倒推回去。其他人则喜欢在文本文件、维基或一些思维导图工具中编写项目计划。您如何规划并不重要,重要的是您必须进行规划。
在本指南中,我们将构建一个链接目录。以下是此链接应用程序的基本目标列表
- 显示一个简单的链接列表。
- 创建一个表单,供用户提交新的链接。
- 验证表单。
- 将数据插入数据库。
让我们开始吧!
第一步
有了简单的攻击计划,现在是时候启动一个全新的空项目了。我喜欢将所有项目放在 ~/Sites 目录中,以下说明将使用该位置。我已经在 Valet 中“停放”了该目录,因此任何文件夹都将自动映射到浏览器中的“文件夹名.test”。
打开您的终端应用程序并切换到该目录。
mkdir ~/Sitescd ~/Sites
Laravel 提供了一个方便的安装程序。如果您计划编写 Laravel 应用程序,请按照 安装文档 中的说明设置安装程序。
无论您是设置安装程序还是想使用 composer,请运行以下命令之一来为 links
应用程序创建一个新的 Laravel 项目
# Via the installerlaravel new links # Via composercomposer create-project --prefer-dist laravel/laravel links "7.*"
这将在 ~/Sites/links
中创建一个新目录并安装一个新的 Laravel 项目。
现在在浏览器中访问 links.test
将显示默认的 Laravel 欢迎页面
数据库设置
当您创建一个新的 Laravel 项目时,安装过程会自动创建一个 .env
文件(从 .env.example
文件复制),用于配置和凭据。根据您的设置,您需要修改以下设置块以匹配您的数据库配置
DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=laravelDB_USERNAME=rootDB_PASSWORD=
您可能需要为此项目创建一个新的数据库
# Connect via the mysql CLImysql -u root -pmysql> create database links_development;mysql> exit # Or use the -e flag to run the create commandmysql -u root -e'create database links_development'
然后,您需要调整 .env
中的数据库配置
DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=links_developmentDB_USERNAME=rootDB_PASSWORD=
测试数据库连接的最佳方法是运行 migrate
artisan 命令
php artisan migrate
如果一切顺利,您应该在运行 migrate 命令后看到类似以下内容
身份验证脚手架
Laravel 有一个单独的第一方包用于生成通用的脚手架,这使得设置身份验证变得轻而易举。要使用它,我们需要安装 UI composer 包
composer require laravel/ui
UI 包提供了一些命令来为 React、Vue 和 Bootstrap 等工具设置脚手架。我们将为本项目创建简单的身份验证脚手架,但您可以随意按照 前端设置 文档进行操作。
运行以下命令以生成身份验证所需的路由、控制器、视图和其他文件
php artisan ui bootstrap --auth
最后,我们需要使用以下命令编译我们的 CSS UI
npm install # Build dev assetsnpm run dev # Or use a watcher to automatically update changesnpm run watch
watch
命令将监听 JS 和 CSS 文件的变化,并自动更新它们。您可能希望在开发过程中在一个单独的标签中运行 npm run watch
。
尽管本教程不会深入探讨身份验证,但运行此命令会修改我们的视图和路由。因此,我们尽早运行它,就不必担心它会影响我们的任何代码。
设置并运行好基本内容后,是时候开始编写一些代码了。
构建链接列表
如果您开始考虑一个完成的项目,很容易感到不知所措。解决这个问题的最佳方法是将项目分解成小的任务。因此,让我们先从显示一个链接列表开始。
虽然显示一个链接列表听起来像是一个小任务,但它仍然需要数据库、数据库表、表中的数据、数据库查询和视图文件。
创建迁移将是第一步,Laravel Artisan 命令行工具可以帮助我们构建它。
php artisan make:migration create_links_table --create=links
现在,打开此命令创建的文件。它将位于 database/migrations/{{datetime}}_create_links_table.php 中。您会注意到该文件夹中还有一些其他迁移,这些迁移由框架提供。
在“up()”方法中,添加以下模式
Schema::create('links', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->string('url')->unique(); $table->text('description'); $table->timestamps();});
保存文件并运行迁移
php artisan migrate
在使用测试数据时,您可以快速应用模式
php artisan migrate:fresh
接下来,我们需要一些数据和一个模型来处理我们的数据库表。Laravel 提供了两个功能来帮助我们完成此操作:一是数据库播种器,它使用数据填充数据库;二是模型工厂文件,它允许我们生成虚假模型数据,我们可使用这些数据来填充我们的开发数据库和测试
php artisan make:model --factory Link
make:model
命令将创建一个 app/Link.php
模型文件。Laravel 模型提供了一个强大的数据库 API,称为 Eloquent,您可以在 Eloquent 文档 中详细了解它。
--factory
标志将在 database/factories
路径中生成一个新的工厂文件,用于生成应用程序数据。在本例中,一个新的 LinkFactory
文件将包含我们 Link
模型的空工厂定义。
打开LinkFactory.php
文件并填写以下内容
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Link;use Faker\Generator as Faker; $factory->define(Link::class, function (Faker $faker) { return [ 'title' => substr($faker->sentence(2), 0, -1), 'url' => $faker->url, 'description' => $faker->paragraph, ];});
我们使用$faker->sentence()
方法生成标题,并使用substr
删除句子末尾的句点。
接下来,创建链接播种器,以便我们可以轻松地将演示数据添加到表中
php artisan make:seeder LinksTableSeeder
make:seeder
命令会生成一个新的数据库类,用来用数据填充我们的links
表。
打开database/seeds/LinksTableSeeder.php
文件,添加以下内容
public function run(){ factory(App\Link::class, 5)->create();}
为了“激活”LinksTableSeeder
,我们需要从主database/seeds/DatabaseSeeder.php
的运行方法中调用它
public function run(){ $this->call(LinksTableSeeder::class);}
您现在可以运行迁移和种子来自动将数据添加到表中。使用migrate:fresh
命令,我们可以获得一个干净的模式,该模式应用所有迁移,然后填充数据库
$ php artisan migrate:fresh --seedDropped all tables successfully.Migration table created successfully.Migrating: 2014_10_12_000000_create_users_tableMigrated: 2014_10_12_000000_create_users_tableMigrating: 2014_10_12_100000_create_password_resets_tableMigrated: 2014_10_12_100000_create_password_resets_tableMigrating: 2017_11_03_023418_create_links_tableMigrated: 2017_11_03_023418_create_links_tableSeeding: LinksTableSeeder
使用tinker shell,您可以开始使用模型数据
$ php artisan tinker>>> \App\Link::first();=> App\Link {#3060 id: 1, title: "Rerum doloremque", url: "http://russel.info/suscipit-et-iste-debitis-beatae-repudiandae-eveniet.html", description: "Dolorem voluptas voluptatum voluptatem consequuntur amet dolore odit. Asperiores ullam alias vel soluta ut in. Facere quia et sit laudantium culpa ea possimus.", created_at: "2020-04-05 00:44:33", updated_at: "2020-04-05 00:44:33", }>>>
我们有了数据位置和一个与数据库交互的模型!让我们开始构建UI,将新链接添加到应用程序中。
路由和视图
要构建一个显示链接列表的视图,我们需要更新主项目路由,还要定义一个新的路由,用于显示我们的提交表单。我们可以在routes/web.php
文件中添加新的路由到我们的应用程序中。
在web路由文件中,您应该看到以下默认路由
Route::get('/', function () { return view('welcome');});
要创建一个新路由,我们可以使用路由闭包或一个专门的控制器类。在本教程中,我们将对提交和索引路由使用闭包。
首先,让我们通过从数据库获取链接集合并将其传递给视图来更新主页路由
Route::get('/', function () { $links = \App\Link::all(); return view('welcome', ['links' => $links]);});
第二个参数可以是一个关联数组数据,键最终会成为模板文件中的变量名。
如果您愿意,也可以使用流畅API来定义变量
// with()return view('welcome')->with('links', $links); // dynamic method to name the variablereturn view('welcome')->withLinks($links);
接下来,编辑welcome.blade.php文件,添加一个简单的foreach
来显示所有链接
@foreach ($links as $link) <a href="{{ $link->url }}">{{ $link->title }}</a>@endforeach
以下是welcome.blade.php
HTML应该的样子
<body> <div class="flex-center position-ref full-height"> @if (Route::has('login')) <div class="top-right links"> @auth <a href="{{ url('/home') }}">Home</a> @else <a href="{{ route('login') }}">Login</a> <a href="{{ route('register') }}">Register</a> @endauth </div> @endif <div class="content"> <div class="title m-b-md"> Laravel </div> <div class="links"> @foreach ($links as $link) <a href="{{ $link->url }}">{{ $link->title }}</a> @endforeach </div> </div> </div></body>
如果您刷新浏览器,您现在应该看到添加的所有链接列表。有了这些设置,让我们转到提交链接。
显示链接提交表单
我们几乎完成了在Laravel中创建第一个应用程序!
我们将通过允许其他人向应用程序提交链接来完成本Laravel教程,这需要三个字段:标题、URL和描述。
我是一个视觉化的人,在规划需要HTML的功能之前,我喜欢将它们画出来,以便在我脑子里了解我正在构建的内容。以下是一个简单绘制的表单
由于我们在上一节中添加了所有核心结构、模型工厂、迁移和模型,我们可以通过重用所有这些内容来享受好处。
首先,在routes/web.php文件中创建一个新路由
Route::get('/submit', function () { return view('submit');});
接下来,我们需要在resources/views/submit.blade.php
中创建submit.blade.php
模板,并使用以下样板bootstrap标记
@extends('layouts.app')@section('content') <div class="container"> <div class="row"> <h1>Submit a link</h1> </div> <div class="row"> <form action="/submit" method="post"> @csrf @if ($errors->any()) <div class="alert alert-danger" role="alert"> Please fix the following errors </div> @endif <div class="form-group"> <label for="title">Title</label> <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" placeholder="Title" value="{{ old('title') }}"> @error('title') <div class="invalid-feedback">{{ $message }}</div> @enderror </div> <div class="form-group"> <label for="url">Url</label> <input type="text" class="form-control @error('url') is-invalid @enderror" id="url" name="url" placeholder="URL" value="{{ old('url') }}"> @error('url') <div class="invalid-feedback">{{ $message }}</div> @enderror </div> <div class="form-group"> <label for="description">Description</label> <textarea class="form-control @error('description') is-invalid @enderror" id="description" name="description" placeholder="description">{{ old('description') }}</textarea> @error('description') <div class="invalid-feedback">{{ $message }}</div> @enderror </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> </div>@endsection
此表单中包含很多内容,所以让我们回顾一下可能在您刚接触Laravel时会让人困惑的主要要点。
在表单的顶部附近,我们有一个刀片条件,它检查是否有任何验证错误。当存在错误时,将显示bootstrap警报消息,提示用户修复无效的表单字段
@if ($errors->any()) <div class="alert alert-danger" role="alert"> Please fix the following errors </div>@endif
每个单独的表单字段都会检查验证错误,并显示错误消息,并输出一个has-error
类
<div class="form-group"> <label for="title">Title</label> <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" placeholder="Title" value="{{ old('title') }}"> @error('title') <div class="invalid-feedback">{{ $message }}</div> @enderror</div>
如果用户提交无效数据,路由将存储验证信息到会话中,并将用户重定向回表单。{{ old('title') }}
函数将填充最初提交的数据。如果用户忘记提交其中一个字段,其他包含数据的字段将在验证失败并显示错误后被填充。
如果一个字段有错误,@error
指令提供一个错误消息变量,您可以在指令块内使用它
@error('title') <div class="invalid-feedback">{{ $message }}</div>@enderror
另一种检查和显示错误的方法是使用验证失败和重定向后提供给视图的$error
变量
@if($errors->has('title')) <div class="invalid-feedback">{{ $errors->first('title') }}</div>@endif
@error
指令在后台使用相同的变量,您可以随意使用您喜欢的任何方法。
提交表单
有了表单,我们就可以处理在服务器上发送和验证表单数据了。回到routes/web.php
文件,为POST
请求创建一个新的路由
use Illuminate\Http\Request; Route::post('/submit', function (Request $request) { $data = $request->validate([ 'title' => 'required|max:255', 'url' => 'required|url|max:255', 'description' => 'required|max:255', ]); $link = tap(new App\Link($data))->save(); return redirect('/');});
注意:确保在web.php
的顶部附近添加use Illuminate\Http\Request
。
这个路由比其他路由要复杂一些。
首先,我们注入Illuminate\Http\Request对象,该对象保存POST数据和有关请求的其他数据。
接下来,我们使用请求的validate()
方法来验证表单数据。validate方法是在Laravel 5.5中引入的,它是验证其他方法的简便方法。作为奖励,已验证的字段将返回到$data
变量中,我们可以使用它们来填充我们的模型。
我们要求所有三个字段,使用管道字符,我们可以定义多个规则。所有三个规则的最大字符数都可以为255,url
字段需要一个有效的URL。
如果验证失败,将抛出一个异常,路由将返回用户,并带有原始输入数据和验证错误。
接下来,我们使用tap()
辅助函数来创建一个新的Link
模型实例,然后保存它。使用tap允许我们调用save()
,并在保存后仍然返回模型实例。
通常,您需要在没有tap的情况下执行以下操作,它只是添加了一点语法糖
$link = new \App\Link($data);$link->save(); return $link;
如果我们想要用数据填充一个新模型,我们需要允许通过批量赋值来“填充”字段。fillable属性旨在防止字段被批量赋值,除非您在数组中定义的项目除外。
仔细考虑一下:我们正在从请求中获取用户输入,并对数据库模型进行批量赋值。注意用户提交的数据的危险,并注意保护你不希望用户通过表单直接操作的数据。
在本例中,我们正在验证每个字段,因此允许它们进行批量赋值是安全的。为了允许我们的模型将值赋值给这些字段,请打开app/Link.php
文件,并将其更新为以下内容
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Link extends Model{ protected $fillable = [ 'title', 'url', 'description' ];}
如果我们想避免批量赋值,我们的代码可能如下所示
$data = $request->validate([ 'title' => 'required|max:255', 'url' => 'required|url|max:255', 'description' => 'required|max:255',]); $link = new \App\Link;$link->title = $data['title'];$link->url = $data['url'];$link->description = $data['description']; // Save the model$link->save();
我们在POST路由中做的最后一件事是在成功保存链接后将用户重定向回主页。
至此,我们的表单应该可以防止提交包含无效字段的链接
如果表单通过验证,数据应该被保存到数据库中,用户将被重定向回主页。
测试表单提交
我们有一个基本的工作表单,但我们应该通过编写测试来确保它继续工作。
Laravel 使针对路由和中间件执行集成测试的HTTP测试变得轻而易举,所以让我们编写一些功能测试来验证我们的代码按预期工作。
在我们开始之前,我们需要在我们的phpunit.xml
文件中调整一些内容,以便我们可以使用内存中的SQLite数据库。您需要确保已安装了正确的PHP模块。
从Laravel 7开始,项目的phpunit.xml
文件配置了一个内存中的SQLite数据库。如果您使用的是旧版本的Laravel,请通过添加以下内容来更改数据库连接
<php> <!-- ... --> <env name="DB_CONNECTION" value="sqlite"/> <env name="DB_DATABASE" value=":memory:"/> <!-- ... --></php>
接下来,删除与Laravel一起提供的占位符测试
rm tests/Feature/ExampleTest.php
我们已经准备好开始通过HTTP请求测试/submit
表单,以确保路由验证、保存和重定向按预期工作。
首先,让我们创建一个新的功能测试来测试我们的路由
php artisan make:test SubmitLinksTest
该命令会创建一个新的测试文件,其中包含适当的依赖项,包括一个RefreshDatabase
特征,我们将使用它来验证我们的链接在有效时是否被保存到数据库中。
打开新的tests/Feature/SubmitLinksTest.php
文件,让我们在类的主体中定义一些骨架测试,我们将在其中填充内容
/** @test */function guest_can_submit_a_new_link() {} /** @test */function link_is_not_created_if_validation_fails() {} /** @test */function link_is_not_created_with_an_invalid_url() {} /** @test */function max_length_fails_when_too_long() {} /** @test */function max_length_succeeds_when_under_max() {}
这些测试应该让您对我们要测试的内容有一个概览
- 验证有效的链接是否被保存到数据库中
- 验证失败时,链接不在数据库中
- 不允许使用无效的URL
- 当字段长度超过
max:255
验证规则时,验证应该失败 - 当字段长度满足
max:255
时,验证应该成功。
我们可能还缺少一些东西,但对于您的第一个Laravel应用程序来说,这是一个不错的列表,应该说明了Laravel中的一些基本HTTP测试技术。
保存有效的链接
我们将编写的第一个测试是验证有效数据是否存储到数据库中的测试
<?php namespace Tests\Feature; use Illuminate\Validation\ValidationException;use Tests\TestCase;use Illuminate\Foundation\Testing\RefreshDatabase; class SubmitLinksTest extends TestCase{ use RefreshDatabase; /** @test */ function guest_can_submit_a_new_link() { $response = $this->post('/submit', [ 'title' => 'Example Title', 'url' => 'http://example.com', 'description' => 'Example description.', ]); $this->assertDatabaseHas('links', [ 'title' => 'Example Title' ]); $response ->assertStatus(302) ->assertHeader('Location', url('/')); $this ->get('/') ->assertSee('Example Title'); }}
请注意RefreshDatabase
特征,它确保每个测试都有一个新的数据库,以便为每个测试提供一个全新的数据库环境,其中包含所有迁移。
我们的第一个测试提交有效的数据,它返回一个响应对象,我们可以用它来断言我们的路由按预期响应。我们验证数据库中是否包含一个记录,其标题是我们刚刚创建的。
接下来,我们验证响应是否为302
状态码,以及指向主页的Location
头。
最后,我们请求主页,并验证链接标题是否在主页上可见。
让我们运行第一个测试,以确保一切按预期通过。Laravel 7 添加了一个新的artisan test
命令,或者您可以使用phpunit
php artisan test # Or run phpunit directlyvendor/bin/phpunit
您应该看到测试套件通过了
测试验证失败
当用户通常提交错误的数据时,我们希望验证触发异常,我们可以用它来确保我们的验证层正常工作
/** @test */function link_is_not_created_if_validation_fails(){ $response = $this->post('/submit'); $response->assertSessionHasErrors(['title', 'url', 'description']);}
我们使用Laravel的assertSessionHasErrors()
来确保会话为每个必需字段都有验证错误。因为我们向路由提交了空数据,所以我们期望required
规则会为每个字段触发。
让我们运行测试套件来验证我们到目前为止的工作
$ php artisan test tests/Feature/SubmitLinksTest PASS Tests\Feature\SubmitLinksTest ✓ guest can submit a new link ✓ link is not created if validation fails Tests: 2 passed Time: 0.32s
测试URL验证
我们希望只有有效的URL才能通过验证,这样我们的应用程序就不会尝试显示无效数据。
/** @test */function link_is_not_created_with_an_invalid_url(){ $this->withoutExceptionHandling(); $cases = ['//invalid-url.com', '/invalid-url', 'foo.com']; foreach ($cases as $case) { try { $response = $this->post('/submit', [ 'title' => 'Example Title', 'url' => $case, 'description' => 'Example description', ]); } catch (ValidationException $e) { $this->assertEquals( 'The url format is invalid.', $e->validator->errors()->first('url') ); continue; } $this->fail("The URL $case passed validation when it should have failed."); }}
Laravel 有一个withoutExceptionHandling()
方法,它会禁用Laravel的路由异常处理代码,该代码用于在异常后生成HTTP响应。我们利用这一点,以便我们可以检查验证异常对象并断言错误消息。
我们循环遍历各种情况(您可以根据需要添加自己的情况),并捕获ValidationException
的实例。如果文本通过了异常处理,我们将手动使测试失败,因为我们期望路由每次都抛出一个ValidationExcepiton
异常。
catch
块使用验证器对象来检查url
错误,并断言实际错误消息与预期的验证错误消息匹配。
我喜欢使用try/catch
技术,然后使用$this->fail()
作为安全机制,而不是使用PHPUnit提供的异常注解。一定要在捕获的异常中return
,以避免混淆测试失败。我认为捕获异常可以进行否则无法进行的断言,并且在大多数情况下提供了我喜欢的更精细的控制。
测试最大长度验证
我们将使用max:255
验证规则测试一些场景:当字段在长度为256
个字符的情况下未通过最大长度验证时,以及当字段长度足够长(255
个字符)通过验证时。
尽管Laravel包含max
验证规则的功能,但我喜欢对其进行测试以验证我的应用程序是否应用了这些规则。如果有人删除了max
验证规则,那么测试将捕获到它。
我喜欢测试最小值和最大值验证规则的阈值,作为额外的预防措施,以确保我的应用程序尊重我设置的最小值和最大值边界。
首先,让我们测试“最大长度”场景
/** @test */function max_length_fails_when_too_long(){ $this->withoutExceptionHandling(); $title = str_repeat('a', 256); $description = str_repeat('a', 256); $url = 'http://'; $url .= str_repeat('a', 256 - strlen($url)); try { $this->post('/submit', compact('title', 'url', 'description')); } catch(ValidationException $e) { $this->assertEquals( 'The title may not be greater than 255 characters.', $e->validator->errors()->first('title') ); $this->assertEquals( 'The url may not be greater than 255 characters.', $e->validator->errors()->first('url') ); $this->assertEquals( 'The description may not be greater than 255 characters.', $e->validator->errors()->first('description') ); return; } $this->fail('Max length should trigger a ValidationException');}
再次,我们禁用异常处理并创建比通过验证长一个字符的数据。
我们断言每个字段都确保它们都包含最大长度验证错误消息。
最后,我们需要在捕获的异常中return
,并使用$this->fail()
作为安全机制以使测试失败。
接下来,我们测试“低于最大值”场景
/** @test */function max_length_succeeds_when_under_max(){ $url = 'http://'; $url .= str_repeat('a', 255 - strlen($url)); $data = [ 'title' => str_repeat('a', 255), 'url' => $url, 'description' => str_repeat('a', 255), ]; $this->post('/submit', $data); $this->assertDatabaseHas('links', $data);}
我们使表单数据足够长以通过max:255
验证,并断言提交数据后数据在数据库中。
运行测试套件,确保一切正常。
$ php artisan test tests/Feature/SubmitLinksTest PASS Tests\Feature\SubmitLinksTest ✓ guest can submit a new link ✓ link is not created if validation fails ✓ link is not created with an invalid url ✓ max length fails when too long ✓ max length succeeds when under max Tests: 5 passed Time: 0.58s
结论
恭喜您完成本教程!
本指南旨在帮助您开始构建应用程序,您可以将其作为构建块来获得开发应用程序所需的技能。我知道这涵盖了很多功能,如果您不熟悉该框架,可能会让人感到不知所措。
我希望本Laravel入门介绍能向您展示为什么这么多人对该框架感到兴奋。